diff --git a/.travis.yml b/.travis.yml index 23952ef80062a4490e7984f44bd09000fbecccb6..501bece870d162afff5302e9a6d807cd43f1bab8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ before_install: - | mkdir ext && cd ext if [ "$TRAVIS_OS_NAME" == "osx" ]; then - brew install boost openssl llvm@4 gmp gettext ninja mongodb mongo-c-driver + brew install boost openssl llvm@4 gmp gettext ninja mongodb mongo-c-driver python3 brew link gettext --force brew services start mongodb WASM_BRANCH=macos diff --git a/CMakeLists.txt b/CMakeLists.txt index 17f2fa0976beecec847292506564d86b6819ceee..bcb1c62bd4e29173cf53d7b7afd3b05f638a3b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,6 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") endif() - set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") set(BUILD_DOXYGEN FALSE CACHE BOOL "Build doxygen documentation on every make") set(BUILD_MONGO_DB_PLUGIN FALSE CACHE BOOL "Build mongo database plugin") diff --git a/CMakeModules/wasm.cmake b/CMakeModules/wasm.cmake index 97e782f7c078f616199528ac31dc6e87d935d260..b762a54faffde8865810fba987d4c92a8a36fb35 100644 --- a/CMakeModules/wasm.cmake +++ b/CMakeModules/wasm.cmake @@ -59,7 +59,8 @@ if( NOT ("${WASM_CLANG}" STREQUAL "" OR "${WASM_LLC}" STREQUAL "" OR "${WASM_LLV endif() macro(compile_wast) - cmake_parse_arguments(ARG "" "TARGET" "SOURCE_FILES;INCLUDE_FOLDERS" ${ARGN}) + #read arguments include ones that we don't since arguments get forwared "as is" and we don't want to threat unknown argument names as values + cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) set(target ${ARG_TARGET}) # NOTE: Setting SOURCE_FILE and looping over it to avoid cmake issue with compilation ${target}.bc's rule colliding with @@ -106,10 +107,28 @@ macro(compile_wast) -nostdlib -nostdlibinc -fno-threadsafe-statics -fno-rtti -fno-exceptions -c ${infile} -o ${outfile}.bc ) + if (${ARG_NOWARNINGS}) + list(APPEND WASM_COMMAND -Wno-everything) + else() + list(APPEND WASM_COMMAND -Weverything -Wno-c++98-compat -Wno-old-style-cast -Wno-vla -Wno-vla-extension -Wno-c++98-compat-pedantic + -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-packed -Wno-padded -Wno-c99-extensions) + endif() + foreach(folder ${ARG_INCLUDE_FOLDERS}) list(APPEND WASM_COMMAND -I ${folder}) endforeach() - + + if ("${ARG_SYSTEM_INCLUDE_FOLDERS}" STREQUAL "") + set (ARG_SYSTEM_INCLUDE_FOLDERS ${DEFAULT_SYSTEM_INCLUDE_FOLDERS}) + endif() + foreach(folder ${ARG_SYSTEM_INCLUDE_FOLDERS}) + list(APPEND WASM_COMMAND -isystem ${folder}) + endforeach() + + foreach(folder ${ARG_SYSTEM_INCLUDE_FOLDERS}) + list(APPEND WASM_COMMAND -isystem ${folder}) + endforeach() + add_custom_command(OUTPUT ${outfile}.bc DEPENDS ${infile} COMMAND ${WASM_COMMAND} @@ -128,9 +147,9 @@ macro(compile_wast) endmacro(compile_wast) macro(add_wast_library) - cmake_parse_arguments(ARG "" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS" ${ARGN}) + cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS" ${ARGN}) set(target ${ARG_TARGET}) - compile_wast(TARGET ${ARG_TARGET} SOURCE_FILES ${ARG_SOURCE_FILES} INCLUDE_FOLDERS ${ARG_INCLUDE_FOLDERS}) + compile_wast(${ARGV}) get_filename_component("${ARG_TARGET}_BC_FILENAME" "${ARG_DESTINATION_FOLDER}/${ARG_TARGET}.bc" ABSOLUTE CACHE) add_custom_target(${target} ALL DEPENDS ${${ARG_TARGET}_BC_FILENAME}) @@ -146,11 +165,11 @@ macro(add_wast_library) endmacro(add_wast_library) macro(add_wast_executable) - cmake_parse_arguments(ARG "" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) + cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) set(target ${ARG_TARGET}) set(DESTINATION_FOLDER ${ARG_DESTINATION_FOLDER}) - compile_wast(TARGET ${ARG_TARGET} SOURCE_FILES ${ARG_SOURCE_FILES} INCLUDE_FOLDERS ${ARG_INCLUDE_FOLDERS}) + compile_wast(${ARGV}) foreach(lib ${ARG_LIBRARIES}) list(APPEND LIBRARIES ${${lib}_BC_FILENAME}) diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000000000000000000000000000000..9b4b0a184c47c5cd13d20555c6c369e8075b3c62 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,71 @@ +pipeline { + agent any + stages { + stage('Build') { + parallel { + stage('Ubuntu') { + steps { + sh ''' + . $HOME/.bash_profile + ./eosio_build.sh + ''' + } + } + stage('MacOS') { + steps { + sh ''' + . $HOME/.bash_profile + echo "Darwin build coming soon..." + ''' + } + } + stage('Fedora') { + steps { + sh ''' + . $HOME/.bash_profile + echo "Fedora build coming soon..." + ''' + } + } + } + } + stage('Tests') { + parallel { + stage('Ubuntu') { + steps { + sh ''' + . $HOME/.bash_profile + export EOSLIB=$(pwd)/contracts + cd build + printf "Waiting for testing to be available..." + while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done + echo "OK!" + ctest --output-on-failure + ''' + } + } + stage('MacOS') { + steps { + sh ''' + . $HOME/.bash_profile + echo "Darwin tests coming soon..." + ''' + } + } + stage('Fedora') { + steps { + sh ''' + . $HOME/.bash_profile + echo "Fedora tests coming soon..." + ''' + } + } + } + } + } + post { + always { + cleanWs() + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 857d3fdba11b09b4e4cc5bbb96b668113f5fd164..a77e37ce653c02f06775b4c09bfa7f0c39ee388a 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,10 @@ The public testnet described in the [wiki](https://github.com/EOSIO/eos/wiki/Tes ### Supported Operating Systems EOS.IO currently supports the following operating systems: -1. Ubuntu 16.04 and higher (Ubuntu 16.10 recommended). -2. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended). -3. Fedora 25 and higher (Fedora 27 recommended). +1. Amazon 2017.09 and higher. +2. Fedora 25 and higher (Fedora 27 recommended). +3. Ubuntu 16.04 and higher (Ubuntu 16.10 recommended). +4. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended). # Resources 1. [EOS.IO Website](https://eos.io) @@ -33,8 +34,8 @@ EOS.IO currently supports the following operating systems: 1. [Getting Started](#gettingstarted) 2. [Setting up a build/development environment](#setup) 1. [Automated build script](#autobuild) - 1. [Clean install Linux (Ubuntu & Fedora) for a local testnet](#autoubuntulocal) - 2. [Clean install Linux (Ubuntu & Fedora) for the public testnet](#autoubuntupublic) + 1. [Clean install Linux (Amazon, Fedora, & Ubuntu) for a local testnet](#autoubuntulocal) + 2. [Clean install Linux (Amazon, Fedora, & Ubuntu) for the public testnet](#autoubuntupublic) 3. [MacOS for a local testnet](#automaclocal) 4. [MacOS for the public testnet](#automacpublic) 3. [Building EOS and running a node](#runanode) @@ -54,9 +55,10 @@ EOS.IO currently supports the following operating systems: 7. [Doxygen documentation](#doxygen) 8. [Running EOS in Docker](#docker) 9. [Manual installation of the dependencies](#manualdep) - 1. [Clean install Ubuntu 16.04 and higher](#ubuntu) - 2. [MacOS Sierra 10.12 and higher](#macos) - 3. [Fedora 25 and higher](#fedora) + 1. [Clean install Amazon 2017.09 and higher](#manualdepamazon) + 2. [Clean install Fedora 25 and higher](#manualdepfedora) + 3. [Clean install Ubuntu 16.04 and higher](#manualdepubuntu) + 4. [Clean install MacOS Sierra 10.12 and higher](#manualdepmacos) ## Getting Started @@ -69,12 +71,13 @@ The following instructions detail the process of getting the software, building ### Automated build script Supported Operating Systems: -1. Ubuntu 16.04 and higher. -2. MacOS Darwin 10.12 and higher. -3. Fedora 25 and higher. +1. Amazon 2017.09 and higher. +2. Fedora 25 and higher (Fedora 27 recommended). +3. Ubuntu 16.04 and higher (Ubuntu 16.10 recommended). +4. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended). -For Ubuntu, MacOS and Fedora there is an automated build script that can install all dependencies and builds EOS. -We are working on supporting Centos, Amazon Linux & Red Hat in future releases. +For Amazon, Fedora, Ubuntu & MacOS there is an automated build script that can install all dependencies and builds EOS. +We are working on supporting other Linux/Unix distributions in future releases. It is called eosio_build.sh @@ -89,7 +92,7 @@ Choose whether you will be building for a local testnet or for the public testne 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. -#### :no_entry: Clean install Linux (Ubuntu & Fedora) for a local testnet :no_entry: +#### :no_entry: Clean install Linux (Amazon, Fedora & Ubuntu) for a local testnet :no_entry: ```bash git clone https://github.com/eosio/eos --recursive @@ -107,7 +110,7 @@ sudo make install Now you can proceed to the next step - [Creating and launching a single-node testnet](#singlenode) -#### Clean install Linux (Ubuntu & Fedora) for the public testnet +#### Clean install Linux (Amazon, Fedora & Ubuntu) for the public testnet ```bash git clone https://github.com/eosio/eos --recursive @@ -567,33 +570,31 @@ Dependencies: * [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git) * [binaryen](https://github.com/WebAssembly/binaryen.git) - -### Clean install Ubuntu 16.10 + +### Clean install Amazon 2017.09 and higher Install the development toolkit: ```bash -sudo apt-get update -wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - -sudo apt-get install clang-4.0 lldb-4.0 libclang-4.0-dev cmake make \ - libbz2-dev libssl-dev libgmp3-dev \ - autotools-dev build-essential \ - libbz2-dev libicu-dev python-dev \ - autoconf libtool git +sudo yum update +sudo yum install git gcc72.x86_64 gcc72-c++.x86_64 autoconf automake libtool make bzip2 \ + bzip2-devel.x86_64 openssl-devel.x86_64 gmp.x86_64 gmp-devel.x86_64 \ + libstdc++72.x86_64 python27-devel.x86_64 libedit-devel.x86_64 \ + ncurses-devel.x86_64 swig.x86_64 gettext-devel.x86_64 + ``` Install Boost 1.66: ```bash cd ~ -wget -c 'https://sourceforge.net/projects/boost/files/boost/1.64.0/boost_1_66_0.tar.bz2/download' -O boost_1.64.0.tar.bz2 -tar xjf boost_1.66.0.tar.bz2 -cd boost_1_66_0/ +curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2 +tar xf boost_1.66.0.tar.bz2 echo "export BOOST_ROOT=$HOME/boost_1_66_0" >> ~/.bash_profile source ~/.bash_profile +cd boost_1_66_0/ ./bootstrap.sh "--prefix=$BOOST_ROOT" ./b2 install -source ~/.bash_profile ``` Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git): @@ -604,7 +605,7 @@ git clone https://github.com/cryptonomex/secp256k1-zkp.git cd secp256k1-zkp ./autogen.sh ./configure -make +make -j$( nproc ) sudo make install ``` @@ -638,8 +639,10 @@ cd .. mkdir build cd build cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ -make -j4 install +make -j$( nproc ) +make install ``` + Add `WASM_LLVM_CONFIG` and `LLVM_DIR` to your `.bash_profile`: ```bash @@ -647,35 +650,33 @@ echo "export WASM_LLVM_CONFIG=~/wasm-compiler/llvm/bin/llvm-config" >> ~/.bash_p echo "export LLVM_DIR=~/wasm-compiler/lib/cmake/llvm" >> ~/.bash_profile source ~/.bash_profile ``` - Your environment is set up. Now you can build EOS and run a node. - -### MacOS Sierra 10.12.6 - -macOS additional Dependencies: - -* Brew -* Newest XCode + +### Clean install Fedora 25 and higher -Upgrade your XCode to the newest version: +Install the development toolkit: ```bash -xcode-select --install -``` - -Install homebrew: +sudo yum update +sudo yum install git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make cmake.x86_64 \ + bzip2 bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 \ + libstdc++-devel.x86_64 python3-devel.x86_64 libedit.x86_64 \ + ncurses-devel.x86_64 swig.x86_64 gettext-devel.x86_64 -```bash -ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` -Install the dependencies: +Install Boost 1.66: ```bash -brew update -brew install git automake libtool boost openssl llvm@4 gmp ninja gettext -brew link gettext --force +cd ~ +curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2 +tar xf boost_1.66.0.tar.bz2 +echo "export BOOST_ROOT=$HOME/boost_1_66_0" >> ~/.bash_profile +source ~/.bash_profile +cd boost_1_66_0/ +./bootstrap.sh "--prefix=$BOOST_ROOT" +./b2 install ``` Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git): @@ -686,11 +687,11 @@ git clone https://github.com/cryptonomex/secp256k1-zkp.git cd secp256k1-zkp ./autogen.sh ./configure -make +make -j$( nproc ) sudo make install ``` -Install [binaryen v1.37.14](https://github.com/WebAssembly/binaryen.git): +To use the WASM compiler, EOS has an external dependency on [binaryen](https://github.com/WebAssembly/binaryen.git): ```bash cd ~ @@ -698,6 +699,7 @@ git clone https://github.com/WebAssembly/binaryen.git cd ~/binaryen git checkout tags/1.37.14 cmake . && make + ``` Add `BINARYEN_ROOT` to your .bash_profile: @@ -707,7 +709,7 @@ echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile source ~/.bash_profile ``` -Build LLVM and clang for WASM: +By default LLVM and clang do not include the WASM build target, so you will have to build it yourself: ```bash mkdir ~/wasm-compiler @@ -726,35 +728,38 @@ Add `WASM_LLVM_CONFIG` and `LLVM_DIR` to your `.bash_profile`: ```bash echo "export WASM_LLVM_CONFIG=~/wasm-compiler/llvm/bin/llvm-config" >> ~/.bash_profile -echo "export LLVM_DIR=/usr/local/Cellar/llvm@4/4.0.1/lib/cmake/llvm/" >> ~/.bash_profile +echo "export LLVM_DIR=~/wasm-compiler/lib/cmake/llvm" >> ~/.bash_profile source ~/.bash_profile ``` +Your environment is set up. Now you can build EOS and run a node. - -### Clean install Fedora 25 and higher + +### Clean install Ubuntu 16.04 & Higher Install the development toolkit: ```bash -sudo yum update -sudo yum install git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make cmake.x86_64 \ - bzip2 bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 \ - libstdc++-devel.x86_64 python3-devel.x86_64 libedit.x86_64 \ - ncurses-devel.x86_64 swig.x86_64 gettext-devel.x86_64 - +sudo apt-get update +wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - +sudo apt-get install clang-4.0 lldb-4.0 libclang-4.0-dev cmake make \ + libbz2-dev libssl-dev libgmp3-dev \ + autotools-dev build-essential \ + libbz2-dev libicu-dev python-dev \ + autoconf libtool git ``` Install Boost 1.66: ```bash cd ~ -curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2 -tar xf boost_1.66.0.tar.bz2 +wget -c 'https://sourceforge.net/projects/boost/files/boost/1.66.0/boost_1_66_0.tar.bz2/download' -O boost_1.66.0.tar.bz2 +tar xjf boost_1.66.0.tar.bz2 +cd boost_1_66_0/ echo "export BOOST_ROOT=$HOME/boost_1_66_0" >> ~/.bash_profile source ~/.bash_profile -cd boost_1_66_0/ ./bootstrap.sh "--prefix=$BOOST_ROOT" ./b2 install +source ~/.bash_profile ``` Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git): @@ -799,14 +804,96 @@ cd .. mkdir build cd build cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ -make -j$( nproc ) install +make -j4 install +``` +Add `WASM_LLVM_CONFIG` and `LLVM_DIR` to your `.bash_profile`: + +```bash +echo "export WASM_LLVM_CONFIG=~/wasm-compiler/llvm/bin/llvm-config" >> ~/.bash_profile +echo "export LLVM_DIR=/usr/local/Cellar/llvm/4.0.1/lib/cmake/llvm" >> ~/.bash_profile +source ~/.bash_profile +``` + +Your environment is set up. Now you can build EOS and run a node. + + +### MacOS Sierra 10.12.6 & higher + +macOS additional Dependencies: + +* Brew +* Newest XCode + +Upgrade your XCode to the newest version: + +```bash +xcode-select --install +``` + +Install homebrew: + +```bash +ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +Install the dependencies: + +```bash +brew update +brew install git automake libtool boost openssl llvm@4 gmp ninja gettext +brew link gettext --force +``` + +Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git): + +```bash +cd ~ +git clone https://github.com/cryptonomex/secp256k1-zkp.git +cd secp256k1-zkp +./autogen.sh +./configure +make -j$( sysctl -in machdep.cpu.core_count ) +sudo make install +``` + +Install [binaryen v1.37.14](https://github.com/WebAssembly/binaryen.git): + +```bash +cd ~ +git clone https://github.com/WebAssembly/binaryen.git +cd ~/binaryen +git checkout tags/1.37.14 +cmake . && make -j$( sysctl -in machdep.cpu.core_count ) +``` + +Add `BINARYEN_ROOT` to your .bash_profile: + +```bash +echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile +source ~/.bash_profile +``` + +Build LLVM and clang for WASM: + +```bash +mkdir ~/wasm-compiler +cd ~/wasm-compiler +git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git +cd llvm/tools +git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git +cd .. +mkdir build +cd build +cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ +make -j$( sysctl -in machdep.cpu.core_count ) +make install ``` Add `WASM_LLVM_CONFIG` and `LLVM_DIR` to your `.bash_profile`: ```bash echo "export WASM_LLVM_CONFIG=~/wasm-compiler/llvm/bin/llvm-config" >> ~/.bash_profile -echo "export LLVM_DIR=~/wasm-compiler/lib/cmake/llvm" >> ~/.bash_profile +echo "export LLVM_DIR=/usr/local/Cellar/llvm@4/4.0.1/lib/cmake/llvm/" >> ~/.bash_profile source ~/.bash_profile ``` Your environment is set up. Now you can build EOS and run a node. diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index 469ae00cc1970656481596c1e9d3f5d2fc85dcf0..06390f40ae292d6850ecdfca0f64ca6481519aef 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -1,4 +1,8 @@ -set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_SOURCE_DIR}/contracts/libc++/upstream/include ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include ${Boost_INCLUDE_DIR}) +# will be implictly used for any compilation unit if not overrided by SYSTEM_INCLUDE_FOLDERS parameter +# these directories go as -isystem to avoid warnings from code of third-party libraries +set(DEFAULT_SYSTEM_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/libc++/upstream/include ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include ${Boost_INCLUDE_DIR}) + +set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts) add_subdirectory(eosiolib) add_subdirectory(musl) @@ -16,6 +20,8 @@ add_subdirectory(asserter) add_subdirectory(infinite) add_subdirectory(proxy) add_subdirectory(test_api) +add_subdirectory(test_api_mem) +add_subdirectory(test_api_db) #add_subdirectory(simpledb) #add_subdirectory(storage) #add_subdirectory(social) diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index 8ae709721b81b7117288bfded329239b6c1e80a4..41278cf63429b5d38fe7d97831ceeda929e5bc2a 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -29,7 +29,22 @@ "fields": [ {"name":"value", "type":"string"} ] + },{ + "name": "regproducer", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"} + {"name":"producer_key", "type":"bytes"} + ] + },{ + "name": "stakevote", + "base": "", + "fields": [ + {"name":"voter", "type":"account_name"} + {"name":"amount", "type":"asset"} + ] } + ], "actions": [{ "name": "transfer", @@ -40,6 +55,12 @@ },{ "name": "nonce", "type": "nonce" + },{ + "name": "regproducer", + "type": "regproducer" + },{ + "name": "stakevote", + "type": "stakevote" } ], "tables": [{ @@ -50,4 +71,4 @@ "key_types" : ["name"] } ] -} \ No newline at end of file +} diff --git a/contracts/eosio.system/eosio.system.cpp b/contracts/eosio.system/eosio.system.cpp index ee50cc7ea602da6b277487e0600910de94a8b64d..7d905ff0ecafd5da765fec97713c24f784b801f5 100644 --- a/contracts/eosio.system/eosio.system.cpp +++ b/contracts/eosio.system/eosio.system.cpp @@ -11,6 +11,7 @@ extern "C" { /// The apply method implements the dispatch of events to this contract void apply( uint64_t code, uint64_t act ) { + print( eosio::name(code), "::", eosio::name(act) ); eosiosystem::contract::apply( code, act ); } } diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index 655a4c7ff86b9aad42ce966fe2c6e0777eec6d4f..9080da09453410b3dc9548c24520fe3fa4e039c1 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -14,13 +14,60 @@ #include #include +#include +#include + namespace eosiosystem { + using eosio::indexed_by; + using eosio::const_mem_fun; + using eosio::bytes; + using std::map; + using std::pair; + using eosio::print; template class contract { public: static const account_name system_account = SystemAccount; typedef eosio::generic_currency< eosio::token > currency; + typedef typename currency::token_type system_token_type; + + struct producer_votes { + account_name owner; + uint64_t padding = 0; + uint128_t total_votes; + + uint64_t primary_key()const { return owner; } + uint128_t by_votes()const { return total_votes; } + + EOSLIB_SERIALIZE( producer_votes, (owner)(total_votes) ) + }; + typedef eosio::multi_index< N(producervote), producer_votes, + indexed_by > + > producer_votes_index_type; + + struct account_votes { + account_name owner; + account_name proxy; + uint32_t last_update; + system_token_type staked; + std::vector producers; + + uint64_t primary_key()const { return owner; } + + EOSLIB_SERIALIZE( account_votes, (owner)(proxy)(last_update)(staked)(producers) ) + }; + typedef eosio::multi_index< N(accountvotes), account_votes> account_votes_index_type; + + + struct producer_config { + account_name owner; + eosio::bytes packed_key; /// a packed public key object + + uint64_t primary_key()const { return owner; } + EOSLIB_SERIALIZE( producer_config, (owner)(packed_key) ) + }; + typedef eosio::multi_index< N(producercfg), producer_config> producer_config_index_type; struct total_resources { account_name owner; @@ -30,11 +77,10 @@ namespace eosiosystem { uint64_t primary_key()const { return owner; } - EOSLIB_SERIALIZE( total_resources, (owner)(total_net_weight)(total_cpu_weight)(total_ram) ); + EOSLIB_SERIALIZE( total_resources, (owner)(total_net_weight)(total_cpu_weight)(total_ram) ) }; - /** * Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. */ @@ -57,7 +103,7 @@ namespace eosiosystem { EOSLIB_SERIALIZE( delegated_bandwidth, (from)(to)(net_weight)(cpu_weight) (start_pending_net_withdraw)(pending_net_withdraw)(deferred_net_withdraw_handler) - (start_pending_cpu_withdraw)(pending_cpu_withdraw)(deferred_cpu_withdraw_handler) ); + (start_pending_cpu_withdraw)(pending_cpu_withdraw)(deferred_cpu_withdraw_handler) ) }; @@ -72,45 +118,55 @@ namespace eosiosystem { }; ACTION( SystemAccount, regproducer ) { - account_name producer_to_register; + account_name producer; + bytes producer_key; - EOSLIB_SERIALIZE( regproducer, (producer_to_register) ); + EOSLIB_SERIALIZE( regproducer, (producer)(producer_key) ) }; ACTION( SystemAccount, regproxy ) { account_name proxy_to_register; - EOSLIB_SERIALIZE( regproxy, (proxy_to_register) ); + EOSLIB_SERIALIZE( regproxy, (proxy_to_register) ) }; - ACTION( SystemAccount, delnetbw ) { + ACTION( SystemAccount, delegatebw ) { account_name from; account_name receiver; - typename currency::token_type stake_quantity; + typename currency::token_type stake_net_quantity; + typename currency::token_type stake_cpu_quantity; - EOSLIB_SERIALIZE( delnetbw, (from)(receiver)(stake_quantity) ) + EOSLIB_SERIALIZE( delegatebw, (from)(receiver)(stake_net_quantity)(stake_cpu_quantity) ) }; - ACTION( SystemAccount, undelnetbw ) { + ACTION( SystemAccount, undelegatebw ) { account_name from; account_name receiver; - typename currency::token_type stake_quantity; + typename currency::token_type unstake_net_quantity; + typename currency::token_type unstake_cpu_quantity; - EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) ) + EOSLIB_SERIALIZE( undelegatebw, (from)(receiver)(unstake_net_quantity)(unstake_cpu_quantity) ) }; ACTION( SystemAccount, nonce ) { eosio::string value; - EOSLIB_SERIALIZE( nonce, (value) ); + EOSLIB_SERIALIZE( nonce, (value) ) }; /// new id options: // 1. hash + collision // 2. incrementing count (key=> tablename - static void on( const delnetbw& del ) { + static void on( const delegatebw& del ) { + eosio_assert( del.stake_cpu_quantity.quantity >= 0, "must stake a positive amount" ); + eosio_assert( del.stake_net_quantity.quantity >= 0, "must stake a positive amount" ); + + auto total_stake = del.stake_cpu_quantity + del.stake_net_quantity; + eosio_assert( total_stake.quantity >= 0, "must stake a positive amount" ); + + require_auth( del.from ); del_bandwidth_index_type del_index( SystemAccount, del.from ); @@ -123,12 +179,14 @@ namespace eosiosystem { del_index.emplace( del.from, [&]( auto& dbo ){ dbo.from = del.from; dbo.to = del.receiver; - dbo.net_weight = del.stake_quantity; + dbo.net_weight = del.stake_net_quantity; + dbo.cpu_weight = del.stake_cpu_quantity; }); } else { del_index.update( *itr, del.from, [&]( auto& dbo ){ - dbo.net_weight = del.stake_quantity; + dbo.net_weight = del.stake_net_quantity; + dbo.cpu_weight = del.stake_cpu_quantity; }); } @@ -136,25 +194,190 @@ namespace eosiosystem { if( tot_itr == nullptr ) { tot_itr = &total_index.emplace( del.from, [&]( auto& tot ) { tot.owner = del.receiver; - tot.total_net_weight += del.stake_quantity; + tot.total_net_weight += del.stake_net_quantity; + tot.total_cpu_weight += del.stake_cpu_quantity; }); } else { total_index.update( *tot_itr, 0, [&]( auto& tot ) { - tot.total_net_weight += del.stake_quantity; + tot.total_net_weight += del.stake_net_quantity; + tot.total_cpu_weight += del.stake_cpu_quantity; }); } set_resource_limits( tot_itr->owner, tot_itr->total_ram, tot_itr->total_net_weight.quantity, tot_itr->total_cpu_weight.quantity, 0 ); - currency::inline_transfer( del.from, SystemAccount, del.stake_quantity, "stake bandwidth" ); - } // delnetbw + currency::inline_transfer( del.from, SystemAccount, total_stake, "stake bandwidth" ); + } // delegatebw + + + + static void on( const undelegatebw& del ) { + eosio_assert( del.unstake_cpu_quantity.quantity >= 0, "must stake a positive amount" ); + eosio_assert( del.unstake_net_quantity.quantity >= 0, "must stake a positive amount" ); + + auto total_stake = del.unstake_cpu_quantity + del.unstake_net_quantity; + eosio_assert( total_stake.quantity >= 0, "must stake a positive amount" ); + + require_auth( del.from ); + + del_bandwidth_index_type del_index( SystemAccount, del.from ); + total_resources_index_type total_index( SystemAccount, del.receiver ); + + //eosio_assert( is_account( del.receiver ), "can only delegate resources to an existing account" ); + + const auto& dbw = del_index.get(del.receiver); + eosio_assert( dbw.net_weight >= del.unstake_net_quantity, "insufficient staked net bandwidth" ); + eosio_assert( dbw.cpu_weight >= del.unstake_cpu_quantity, "insufficient staked cpu bandwidth" ); + + del_index.update( dbw, del.from, [&]( auto& dbo ){ + dbo.net_weight -= del.unstake_net_quantity; + dbo.cpu_weight -= del.unstake_cpu_quantity; + + }); + + const auto& totals = total_index.get( del.receiver ); + total_index.update( totals, 0, [&]( auto& tot ) { + tot.total_net_weight -= del.unstake_net_quantity; + tot.total_cpu_weight -= del.unstake_cpu_quantity; + }); + + set_resource_limits( totals.owner, totals.total_ram, totals.total_net_weight.quantity, totals.total_cpu_weight.quantity, 0 ); + /// TODO: implement / enforce time delays on withdrawing + currency::inline_transfer( SystemAccount, del.from, total_stake, "unstake bandwidth" ); + } // undelegatebw + + + + + + /** + * This method will create a producr_config and producer_votes object for 'producer' + * + * @pre producer is not already registered + * @pre producer to register is an account + * @pre authority of producer to register + * + */ static void on( const regproducer& reg ) { - require_auth( reg.producer_to_register ); + auto producer = reg.producer; + require_auth( producer ); + + producer_votes_index_type votes( SystemAccount, SystemAccount ); + const auto* existing = votes.find( producer ); + eosio_assert( !existing, "producer already registered" ); + + votes.emplace( producer, [&]( auto& pv ){ + pv.owner = producer; + pv.total_votes = 0; + }); + + producer_config_index_type proconfig( SystemAccount, SystemAccount ); + proconfig.emplace( producer, [&]( auto& pc ) { + pc.owner = producer; + pc.packed_key = reg.producer_key; + }); + } + + ACTION( SystemAccount, stakevote ) { + account_name voter; + system_token_type amount; + + EOSLIB_SERIALIZE( stakevote, (voter)(amount) ) + }; + + static void on( const stakevote& sv ) { + print( "on stake vote\n" ); + eosio_assert( sv.amount.quantity > 0, "must stake some tokens" ); + require_auth( sv.voter ); + + account_votes_index_type avotes( SystemAccount, SystemAccount ); + + const auto* acv = avotes.find( sv.voter ); + if( !acv ) { + acv = &avotes.emplace( sv.voter, [&]( auto& av ) { + av.owner = sv.voter; + av.last_update = now(); + av.proxy = 0; + }); + } + + uint128_t old_weight = acv->staked.quantity; + uint128_t new_weight = old_weight + sv.amount.quantity; + + producer_votes_index_type votes( SystemAccount, SystemAccount ); + + for( auto p : acv->producers ) { + votes.update( votes.get( p ), 0, [&]( auto& v ) { + v.total_votes -= old_weight; + v.total_votes += new_weight; + }); + } + + avotes.update( *acv, 0, [&]( auto av ) { + av.last_update = now(); + av.staked += sv.amount; + }); + + currency::inline_transfer( sv.voter, SystemAccount, sv.amount, "stake for voting" ); + } + + ACTION( SystemAccount, voteproducer ) { + account_name voter; + account_name proxy; + std::vector producers; + + EOSLIB_SERIALIZE( voteproducer, (voter)(proxy)(producers) ) + }; + + /** + * @pre vp.producers must be sorted from lowest to highest + * @pre if proxy is set then no producers can be voted for + * @pre every listed producer or proxy must have been previously registered + * @pre vp.voter must authorize this action + * @pre voter must have previously staked some EOS for voting + */ + static void on( const voteproducer& vp ) { + eosio_assert( std::is_sorted( vp.producers.begin(), vp.producers.end() ), "producer votes must be sorted" ); + eosio_assert( vp.producers.size() <= 30, "attempt to vote for too many producers" ); + if( vp.proxy != 0 ) eosio_assert( vp.producers.size() == 0, "cannot vote for producers and proxy at same time" ); + + require_auth( vp.voter ); + + account_votes_index_type avotes( SystemAccount, SystemAccount ); + const auto& existing = avotes.get( vp.voter ); + + std::map > producer_vote_changes; + + uint128_t old_weight = existing.staked.quantity; /// old time + uint128_t new_weight = old_weight; /// TODO: update for current weight + + for( const auto& p : existing.producers ) + producer_vote_changes[p].first = old_weight; + for( const auto& p : vp.producers ) + producer_vote_changes[p].second = new_weight; + + producer_votes_index_type votes( SystemAccount, SystemAccount ); + for( const auto& delta : producer_vote_changes ) { + if( delta.second.first != delta.second.second ) { + const auto& provote = votes.get( delta.first ); + votes.update( provote, 0, [&]( auto& pv ){ + pv.total_votes -= delta.second.first; + pv.total_votes += delta.second.second; + }); + } + } + + avotes.update( existing, 0, [&]( auto& av ) { + av.proxy = vp.proxy; + av.last_update = now(); + av.producers = vp.producers; + }); } static void on( const regproxy& reg ) { require_auth( reg.proxy_to_register ); + } static void on( const nonce& ) { @@ -162,7 +385,11 @@ namespace eosiosystem { static void apply( account_name code, action_name act ) { - if( !eosio::dispatch( code, act) ) { + if( !eosio::dispatch( code, act) ) { if ( !eosio::dispatch( code, act ) ) { eosio::print("Unexpected action: ", eosio::name(act), "\n"); eosio_assert( false, "received unexpected action"); diff --git a/contracts/eosio/eosio.cpp b/contracts/eosio/eosio.cpp deleted file mode 100644 index 770d7cffb875d5983763298b455c2879959c818a..0000000000000000000000000000000000000000 --- a/contracts/eosio/eosio.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - - -namespace native { - /** - @defgroup eoscontract EOS Contract - @brief Documents the interface to the EOS currency contract - @ingroup contracts - @{ - */ - - /** - * @ingroup contracts - * @brief Defines the base class for all contracts - */ - struct contract { - - /** - * @brief updates the code that will be executed for this contract - * - *

Required Authority

- * - * Requires authority of *this* contract. - * - *

Required Scope

- * - * Requires scope of *this* contract. - * - * @note the change in code does not take effect until the start of the next block - */ - void setcode( Bytes code, - Abi abi, - uint8_t vm = 0, - uint8_t vm_version = 0 ) final; - - /** - * @brief updates the authority required for a named permission - * - *

Required Authority

- * - * Requires authority of *this* contract. - * - *

Required Scope

- * - * Requires scope of *this* contract. - */ - void setauth( Name permission, ///< the name for the permission being set - Name parent, ///< the parent permission to this permission - Authority auth ///< the set of keys/accounts and threshold ); - ) final; - - - /** - * @brief set the local named permission required for `this` account/contract to - * call `con::act(...)` - * - *

Required Authority

- * - * Requires authority of *this* contract. - * - *

Required Scope

- * - * Requires scope of *this* contract. - * - * @pre myperm must be defined by prior call to @ref setauth - * - * @param con - the name of the contract this permission applies - * @param act - the name of the action on @ref con this permission applies to - * @param myperm - the name of a permission set by @ref setauth on `this` contract - */ - void setperm( Name con, Name act, Name myperm ); - }; - - /** - * @class eos - * @brief A *native* currency contract implemented with account named `eos` - * @ingroup contracts - * - * @details The EOS contract is a *native* currency contract implemented with account named `eos`. This contract enables - * users to transfer EOS tokens to each other. This contract is designed to work the @ref stakedcontract and - * @ref systemcontract when creating new accounts, claiming staked EOS. - */ - struct eos : public contract { - - /** - @brief This action will transfer funds from one account to another. - - @pre `from`'s balance must be greaterthan or equal to `amount` transferred. - @pre The amount transferred must be greater than 0 - @pre `to` and `from` may not be the same account. - -

Required Authority

- - This action requires the authority of the `from` account. - -

Required Scope

- - This action requires access to `from` and `to` account scopes. It does not require - access to the `eos` scope which means that multiple transfers can execute in parallel - as long as they don't have any overlapping scopes. - -

Required Recipients

- - This action requires that the accounts `from` and `to` are listed in the required recipients. This ensures - other contracts are notified anytime EOS tokens are transferred. - - */ - void transfer ( - account_name from, ///< account from which EOS will be withdrawn - account_name to, ///< account to receive EOS, may not be same as `from` - uint64_t amount ///< must be greater than 0 and less or equal to `from`'s balance - ); - - }; /// class EOS - /// @} -} diff --git a/contracts/eosiolib/account.hpp b/contracts/eosiolib/account.hpp index 6b0871aa4f3b34e7ca8865a792bfb8fa59f751cc..f79764661d8de7f3c1270ce55ff0215b90b0ced5 100644 --- a/contracts/eosiolib/account.hpp +++ b/contracts/eosiolib/account.hpp @@ -7,6 +7,7 @@ #pragma once #include #include +#include namespace eosio { namespace account { @@ -68,13 +69,12 @@ struct PACKED(account_balance) { /** * @brief Retrieve a populated balance structure * @details Retrieve a populated balance structure - * @param account_balance stream to write - * @ret true if account's balance is found + * @param acnt - account + * @return true if account's balance is found */ - -bool get(account_balance& b) +bool get(account_balance& acnt) { - return account_balance_get(&b, sizeof(account_balance)); + return account_balance_get(&acnt, sizeof(account_balance)); } /// @} eosio diff --git a/contracts/eosiolib/action.h b/contracts/eosiolib/action.h index 7003e80e73e4db88a5d92ee85f3e02dbe0b3241e..39558fcf0eec405536bbc77b8d57fdc9b3dc428e 100644 --- a/contracts/eosiolib/action.h +++ b/contracts/eosiolib/action.h @@ -112,8 +112,8 @@ extern "C" { /** * Send an inline action in the context of this action's parent transaction - * @param serialized_action - * @param size + * @param serialized_action - serialized action + * @param size - size of serialized action in bytes */ void send_inline(char *serialized_action, size_t size); diff --git a/contracts/eosiolib/compiler_builtins.h b/contracts/eosiolib/compiler_builtins.h new file mode 100644 index 0000000000000000000000000000000000000000..2b1cf78eb35e7c0495bf3eb84fd9f388c69c918e --- /dev/null +++ b/contracts/eosiolib/compiler_builtins.h @@ -0,0 +1,51 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include + +extern "C" { + /** + * @defgroup compiler builtins API + * @brief Declares int128 helper builtins generated by the toolchain. + * @ingroup compilerbuiltinsapi + * + * @{ + */ + + /** + * Multiply two 128 bit integers split as two unsigned 64 bit integers and assign the value to the first parameter. + * @brief Multiply two 128 unsigned bit integers (which are represented as two 64 bit unsigned integers. + * @param res It will be replaced with the result product. + * @param la Low 64 bits of the first 128 bit factor. + * @param ha High 64 bits of the first 128 bit factor. + * @param lb Low 64 bits of the second 128 bit factor. + * @param hb High 64 bits of the second 128 bit factor. + * Example: + * @code + * __int128 res = 0; + * __int128 a = 100; + * __int128 b = 100; + * __multi3(res, a, (a >> 64), b, (b >> 64)); + * printi128(res); // Output: 10000 + * @endcode + */ + void __multi3(__int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); + + void __divti3(__int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); + void __udivti3(unsigned __int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); + + void __modti3(__int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); + void __umodti3(unsigned __int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); + + void __lshlti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); + void __lshrti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); + + void __ashlti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); + void __ashrti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); + + void __break_point(); + +} // extern "C" diff --git a/contracts/eosiolib/contracts.dox b/contracts/eosiolib/contracts.dox index 86fc02057aa5a57a1a46386a8a9ff5c383809372..3bc851b6c56ce5ac2853bea4ca88af8d0f9fa578 100644 --- a/contracts/eosiolib/contracts.dox +++ b/contracts/eosiolib/contracts.dox @@ -30,7 +30,7 @@ } ``` - `apply` is give the arguments `code` and `action` which uniquely identify every event in + `apply` is given the arguments `code` and `action` which uniquely identify every event in the system. For example, `code` could be a *currency* contract and `action` could be *transfer*. This event (code,action) may be passed to several contracts including the `sender` and `receiver`. It is up to your application to figure out what to do in response to such an event. diff --git a/contracts/eosiolib/crypto.h b/contracts/eosiolib/crypto.h index 337352fe83517bc2247f3566321875601c2bdf76..efa9a7b54d64a43524fad0d463a7c38206037b93 100644 --- a/contracts/eosiolib/crypto.h +++ b/contracts/eosiolib/crypto.h @@ -14,10 +14,76 @@ extern "C" { * * This method is optimized to a NO-OP when in fast evaluation mode */ -void eosio_assert_sha256( char* data, uint32_t length, const checksum* hash ); +void assert_sha256( char* data, uint32_t length, const checksum256* hash ); + +/** + * This method is implemented as: + * + * checksum calc_hash; + * sha1( data, length, &calc_hash ); + * eos_assert( calc_hash == hash, "invalid hash" ); + * + * This method is optimized to a NO-OP when in fast evaluation mode + */ +void assert_sha1( char* data, uint32_t length, const checksum160* hash ); + +/** + * This method is implemented as: + * + * checksum calc_hash; + * sha512( data, length, &calc_hash ); + * eos_assert( calc_hash == hash, "invalid hash" ); + * + * This method is optimized to a NO-OP when in fast evaluation mode + */ +void assert_sha512( char* data, uint32_t length, const checksum512* hash ); + +/** + * This method is implemented as: + * + * checksum calc_hash; + * ripemd160( data, length, &calc_hash ); + * eos_assert( calc_hash == hash, "invalid hash" ); + * + * This method is optimized to a NO-OP when in fast evaluation mode + */ +void assert_ripemd160( char* data, uint32_t length, const checksum160* hash ); /** * Calculates sha256( data,length) and stores result in memory pointed to by hash + * `hash` should be checksum<256> + */ +void sha256( char* data, uint32_t length, checksum256* hash ); + +/** + * Calculates sha1( data,length) and stores result in memory pointed to by hash + * `hash` should be checksum<160> + */ +void sha1( char* data, uint32_t length, checksum160* hash ); + +/** + * Calculates sha512( data,length) and stores result in memory pointed to by hash + * `hash` should be checksum<512> */ -void sha256( char* data, uint32_t length, checksum* hash ); +void sha512( char* data, uint32_t length, checksum512* hash ); + +/** + * Calculates ripemd160( data,length) and stores result in memory pointed to by hash + * `hash` should be checksum<160> + */ +void ripemd160( char* data, uint32_t length, checksum160* hash ); + +/** + * Calculates the public key used for a given signature and hash used to create a message and places it in `pub` + * returns the number of bytes read into pub + * `digest` should be checksum<256> + */ +int recover_key( checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ); + +/** + * Tests a given public key with the generated key from digest and the signature + * `digest` should be checksum<256> + */ +void assert_recover_key( checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ); + } diff --git a/contracts/eosiolib/datastream.hpp b/contracts/eosiolib/datastream.hpp index 9186d0a40207f090398316fdf52b9ed7daa70cd4..67f708c0afa17ae42095519cd90acd8f9a7910e4 100644 --- a/contracts/eosiolib/datastream.hpp +++ b/contracts/eosiolib/datastream.hpp @@ -18,7 +18,7 @@ template class datastream { public: datastream( T start, size_t s ) - :_start(start),_pos(start),_end(start+s){}; + :_start(start),_pos(start),_end(start+s){} /** * Skips a specified number of bytes from this stream @@ -99,7 +99,7 @@ class datastream { * @brief Gets the position within the current stream * @return p the position within the current stream */ - inline size_t tellp()const { return _pos - _start; } + inline size_t tellp()const { return size_t(_pos - _start); } /** * Returns the number of remaining bytes that can be read/skipped @@ -119,7 +119,7 @@ class datastream { template<> class datastream { public: - datastream( size_t init_size = 0):_size(init_size){}; + datastream( size_t init_size = 0):_size(init_size){} inline bool skip( size_t s ) { _size += s; return true; } inline bool write( const char* ,size_t s ) { _size += s; return true; } inline bool put(char ) { ++_size; return true; } diff --git a/contracts/eosiolib/db.h b/contracts/eosiolib/db.h index 5bf6ea18b483f73ea2a36053a06b917014df98c5..4d7957c308b9a952e03e6c2ee8f3280507c9b073 100644 --- a/contracts/eosiolib/db.h +++ b/contracts/eosiolib/db.h @@ -304,8 +304,6 @@ int32_t update_str( account_name scope, table_name table, account_name bta, char * @param scope - the account scope that will be read, must exist in the transaction scopes list * @param code - identifies the code that controls write-access to the data * @param table - the ID/name of the table within the scope/code context to query - * @param key - location of the record key - * @param keylen - length of the record key * @param value - location to copy the front record value * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found @@ -316,8 +314,6 @@ int32_t update_str( account_name scope, table_name table, account_name bta, char * @param scope - the account scope that will be read, must exist in the transaction scopes list * @param code - identifies the code that controls write-access to the data * @param table - the ID/name of the table within the scope/code context to query - * @param key - location of the record key - * @param keylen - length of the record key * @param value - location to copy the back record value * @param valuelen - maximum length of the record value to read * @return the number of bytes read or -1 if key was not found diff --git a/contracts/eosiolib/db.hpp b/contracts/eosiolib/db.hpp index 558feded2ab9b5cd047c326e6f6565227dab31f4..e4d0aa35011995313285b37cd8f662eb04b99232 100644 --- a/contracts/eosiolib/db.hpp +++ b/contracts/eosiolib/db.hpp @@ -96,85 +96,6 @@ struct table_impl { } }; -/** - * @defgroup dualindextable Dual Index Table - * @brief Defines a type-safe C++ wrapper around the C Dual Index Table - * - * @tparam scope - the default account name/scope that this table is located within - * @tparam code - the code account name which has write permission to this table - * @tparam table - a unique identifier (name) for this table - * @tparam Record - the type of data stored in each row - * @tparam PrimaryType - the type of the first field stored in @ref Record - * @tparam SecondaryType - the type of the second field stored in @ref Record - * - * The primary and secondary indices are sorted as N-bit unsigned integers from lowest to highest. - * - * @code - * struct model { - * uint64_t primary; - * uint64_t secondary; - * uint64_t value; - * }; - * - * typedef table MyTable; - * model a { 1, 11, N(first) }; - * model b { 2, 22, N(second) }; - * model c { 3, 33, N(third) }; - * model d { 4, 44, N(fourth) }; - * - * bool res = MyTable::store(a); - * ASSERT(res, "store"); - * - * res = MyTable::store(b); - * ASSERT(res, "store"); - * - * res = MyTable::store(c); - * ASSERT(res, "store"); - * - * res = MyTable::store(d); - * ASSERT(res, "store"); - * - * model query; - * res = MyTable::primary_index::get(1, query); - * ASSERT(res && query.primary == 1 && query.value == N(first), "first"); - * - * res = MyTable::primary_index::front(query); - * ASSERT(res && query.primary == 4 && query.value == N(fourth), "front"); - * - * res = MyTable::primary_index::back(query); - * ASSERT(res && query.primary == 1 && query.value == N(first), "back"); - * - * res = MyTable::primary_index::previous(query); - * ASSERT(res && query.primary == 2 && query.value == N(second), "previous"); - * - * res = MyTable::primary_index::next(query); - * ASSERT(res && query.primary == 1 && query.value == N(first), "first"); - * - * res = MyTable::secondary_index::get(11, query); - * ASSERT(res && query.primary == 11 && query.value == N(first), "first"); - * - * res = MyTable::secondary_index::front(query); - * ASSERT(res && query.secondary == 44 && query.value == N(fourth), "front"); - * - * res = MyTable::secondary_index::back(query); - * ASSERT(res && query.secondary == 11 && query.value == N(first), "back"); - * - * res = MyTable::secondary_index::previous(query); - * ASSERT(res && query.secondary == 22 && query.value == N(second), "previous"); - * - * res = MyTable::secondary_index::next(query); - * ASSERT(res && query.secondary == 11 && query.value == N(first), "first"); - * - * res = MyTable::remove(query); - * ASSERT(res, "remove"); - * - * res = MyTable::get(query); - * ASSERT(!res, "not found already removed"); - * - * @endcode - * @ingroup databaseCpp - * @{ - */ template struct table { private: @@ -244,7 +165,6 @@ struct table { /** * @param p - reference to primary key to get the lower bound of; must be initialized with a value; * @param r - reference to a record to load the value to. - * @param s - account scope. default is current scope of the class * * @return true if successful read. */ @@ -255,7 +175,6 @@ struct table { /** * @param p - reference to primary key to get the upper bound of; must be initialized with a value; * @param r - reference to a record to load the value to. - * @param s - account scope. default is current scope of the class * * @return true if successful read. */ @@ -419,493 +338,7 @@ struct table { }; /// @} -template<> -struct table_impl { - - 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 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 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 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 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 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 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, 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, account_name bta, const void* data, uint32_t len ) { - return update_i64( scope, table_n, bta, data, len ); - } -}; - - /** - * @defgroup singleindextable Single Index Table - * @brief Defines a type-safe C++ wrapper around the C Single Index Table - * - * @tparam scope - the default account name scope that this table is located within - * @tparam code - the code account name which has write permission to this table - * @tparam table - a unique identifier (name) for this table - * @tparam Record - the type of data stored in each row - * @tparam PrimaryType - the type of the first field stored in @ref Record - * - * Example - * @code - * - * struct my_model { - * uint128_t number; - * uint64_t name; - * }; - * - * typedef table MyTable; - * - * my_model a { 1, N(one) }; - * my_model b { 2, N(two) }; - * my_model c { 3, N(three) }; - * my_model d { 4, N(four) }; - * - * bool res = MyTable::store(a); - * ASSERT(res, "store"); - - * res = MyTable::store(b); - * ASSERT(res, "store"); - * - * res = MyTable::store(c); - * ASSERT(res, "store"); - * - * res = MyTable::store(d); - * ASSERT(res, "store"); - * - * my_model query; - * res = MyTable::front(query); - * ASSERT(res && query.number == 4 && query.name == N(four), "front"); - * - * res = MyTable::back(query); - * ASSERT(res && query.number == 1 && query.name == N(one), "back"); - * - * res = MyTable::primary_index::previous(query); - * ASSERT(res && query.number == 2 && query.name == N(two), "previous"); - * - * res = MyTable::primary_index::next(query); - * ASSERT(res && query.number == 1 && query.name == N(one), "next"); - * - * query.number = 4; - * res = MyTable::get(query); - * ASSERT(res && query.number == 4 && query.name = N(four), "get"); - * - * query.name = N(Four); - * res = MyTable.update(query); - * ASSERT(res && query.number == 4 && query.name == N(Four), "update"); - * - * res = MyTable.remove(query); - * ASSERT(res, "remove"); - * - * res = MyTable.get(query); - * ASSERT(!res, "get of removed record"); - * - * @endcode - * @ingroup databaseCpp - * @{ - */ -template -struct table { - private: - typedef table_impl impl; - static_assert( sizeof(PrimaryType) <= sizeof(Record), "invalid template parameters" ); - - public: - typedef PrimaryType primary; - /** - * @brief Primary Index of the Table - */ - struct primary_index { - /** - * @param r - reference to a record to store the front. - * @param s - scope; defaults to scope of the class. - * - * @return true if successfully retrieved the front of the table. - */ - static bool front( Record& r, uint64_t s = scope ) { - return impl::front_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param r - reference to a record to store the back. - * @param s - scope; defaults to scope of the class. - * - * @return true if successfully retrieved the back of the table. - */ - static bool back( Record& r, uint64_t s = scope ) { - return impl::back_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param r - reference to store the next record. Must be initialized with a key. - * @param s - scope; defaults to scope of the class. - * - * @return true if successfully retrieved the next record. - */ - static bool next( Record& r, uint64_t s = scope ) { - return impl::next_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param r - reference to store previous record. Must be initialized with a key. - * @param s - scope; defaults to scope of the class. - * - * @return true if successfully retrieved the previous record. - */ - static bool previous( Record& r, uint64_t s = scope ) { - return impl::previous_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param p - reference to the primary key to retrieve the record. - * @param r - reference to hold the result of the query. - * @param s - scope; defaults to scope of the class. - * @return true if successfully retrieved the record. - */ - static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) { - *reinterpret_cast(&r) = p; - return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param p - reference to the primary key to retrieve the lower bound. - * @param r - reference to hold the result of the query. - * @param s - scope; defaults to scope of the class. - * @return true if successfully retrieved the record. - */ - static bool lower_bound( const PrimaryType& p, Record& r, uint64_t s = scope ) { - *reinterpret_cast(&r) = p; - return impl::lower_bound_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param p - reference to the primary key to retrieve the upper bound. - * @param r - reference to hold the result of the query. - * @param s - scope; defaults to scope of the class. - * @return true if successfully retrieved the record. - */ - static bool upper_bound( const PrimaryType& p, Record& r, uint64_t s = scope ) { - *reinterpret_cast(&r) = p; - return impl::upper_bound_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @param r - reference to record to be removed. - * @param s - scope; defaults to scope of the class. - * @return true if successfully removed. - */ - static bool remove( const Record& r, uint64_t s = scope ) { - return impl::remove( s, table_n, &r ) != 0; - } - }; - - - /** - * @brief Fetches the front of the table - * @details Fetches the front of the table - * @param r - reference to hold the value - * @param s - scope; defaults to scope of the class. - * @return true if successfully retrieved the front - */ - static bool front( Record& r, uint64_t s = scope ) { return primary_index::front(r, s); } - - /** - * @brief Fetches the back of the table - * @details Fetches the back of the table - * @param r - reference to hold the value - * @param s - scope; defaults to scope of the class. - * @return true if successfully retrieved the back - */ - static bool back( Record& r, uint64_t s = scope ) { return primary_index::back(r, s); } - - /** - * @brief Retrieves the record for the specified primary key - * @details Retrieves the record for the specified primary key - * @param p - the primary key of the record to fetch - * @param r - reference of record to hold return value - * @param s - scope; defaults to scope of the class. - * @return true if get succeeds. - */ - static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) { - *reinterpret_cast(&r) = p; - return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @brief Retrieves a record based on initialized primary key value - * @details Retrieves a record based on initialized primary key value - * @param r - reference of a record to hold return value; must be initialized to the primary key to be fetched. - * @param s - scope; defaults to scope of the class. - * @return true if get succeeds. - */ - static bool get( Record& r, uint64_t s = scope ) { - return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record); - } - - /** - * @brief Store a record to the table - * @details Store a record to the table - * @param r - the record to be stored. - * @param s - scope; defaults to scope of the class. - * @return true if store succeeds. - */ - 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; - } - - /** - * @brief Update a record in the table. - * @details Update a record in the table. - * @param r - the record to be updated including the updated values (cannot update the index). - * @param s - scope; defaults to scope of the class. - * @return true if update succeeds. - */ - 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; - } - - /** - * @brief Remove a record from the table. - * @details Remove a record from the table. - * @param r - the record to be removed. - * @param s - scope; defaults to scope of the class. - * @return true if remove succeeds. - */ - static bool remove( const Record& r, uint64_t s = scope ) { - return impl::remove( s, table_n, &r ) != 0; - } -}; /// @} singleindextable - - -template<> -struct table_impl_obj { - - 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, 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 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 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 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 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 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 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 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 ); - } -}; - -/** - * @defgroup singlevarindextable Single Variable Length Index Table - * @brief Defines a type-safe C++ wrapper around the C Single Variable Length Index Table (e.g. string index) - * - * @tparam scope - the default account name scope that this table is located within - * @tparam code - the code account name which has write permission to this table - * @tparam table_n - a unique identifier (name) for this table - * @tparam PrimaryType - the type of the first field stored in @ref Record - * - * @ingroup databaseCpp - * @{ - */ - -template -struct var_table { - private: - typedef table_impl_obj impl; - - public: - typedef PrimaryType primary; - - /** - * @brief Store a record to the table - * @details Store a record to the table - * @param key - key of the data to be stored - * @param keylen - length of the key - * @param record - data to be stored - * @param len - length of data to be stored - * @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, bta, key, keylen, record, len ); - } - - /** - * @brief Update a record in the table - * @details Update a record to the table - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @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, bta, key, keylen, record, len ); - } - - /** - * @brief Fetches the front of the table - * @details Fetches the front of the table - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @return the number of bytes read or -1 if key was not found - */ - int32_t front( char* record, uint32_t len ) { - return impl::front( code, scope, table_n, record, len ); - } - - /** - * @brief Fetches the back of the table - * @details Fetches the back of the table - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @return the number of bytes read or -1 if key was not found - */ - int32_t back( char* record, uint32_t len ) { - return impl::back( code, scope, table_n, record, len ); - } - - /** - * @brief Fetches a record from the table - * @details Fetches a record from the table - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @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( code, scope, table_n, key, keylen, record, len ); - } - - /** - * @brief Fetches a record which key is next of the given key - * @details Fetches a record which key is next of the given key - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @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( code, scope, table_n, key, keylen, record, len ); - } - - /** - * @brief Fetches a record which key is previous of the given key - * @details Fetches a record which key is previous of the given key - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @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( code, scope, table_n, key, keylen, record, len ); - } - - /** - * @brief Fetches a record which key is the nearest larger than or equal to the given key - * @details Fetches a record which key is the nearest larger than or equal to the given key - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @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( code, scope, table_n, key, keylen, record, len ); - } - - /** - * @brief Fetches a record which key is the nearest larger than the given key - * @details Fetches a record which key is the nearest larger than the given key - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @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( code, scope, table_n, key, keylen, record, len ); - } - - /** - * @brief Remove a record from the table. - * @details Remove a record from the table. - * @param key - key of the data to be updated - * @param keylen - length of the key - * @param record - data to be updated - * @param len - length of data to be updated - * @return 1 if a record was removed, and 0 if no record with key was found - */ - int32_t remove( primary key, uint32_t keylen ) { - return impl::remove( scope, table_n, key, keylen ); - } -}; - -/// @} singlevarindextable } // namespace eosio -#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/eosiolib.cpp b/contracts/eosiolib/eosiolib.cpp index 9dfda4d0410c9fde6030ef2fad89979f2fb628c8..d72f79e30a33e4e734afc751cb3983d1b371e106 100644 --- a/contracts/eosiolib/eosiolib.cpp +++ b/contracts/eosiolib/eosiolib.cpp @@ -47,7 +47,7 @@ namespace eosio { return nullptr; } - const uint32_t new_heap_size = remaining > _new_heap_size ? _new_heap_size : remaining; + const uint32_t new_heap_size = uint32_t(remaining) > _new_heap_size ? _new_heap_size : uint32_t(remaining); char* new_memory_start = static_cast(sbrk(new_heap_size)); // if we can expand the current memory, keep working with it if (current_memory->expand_memory(new_memory_start, new_heap_size)) @@ -75,7 +75,6 @@ namespace eosio { adjust_to_mem_block(size); // first pass of loop never has to initialize the slot in _available_heap - uint32_t needs_init = 0; char* buffer = nullptr; memory* current = nullptr; // need to make sure @@ -129,7 +128,6 @@ namespace eosio { return nullptr; } - const uint32_t REMOVE = size; adjust_to_mem_block(size); char* realloc_ptr = nullptr; @@ -283,12 +281,11 @@ namespace eosio { return nullptr; } - const int32_t diff = size - *orig_ptr_size; - if (diff < 0) + if( *orig_ptr_size > size ) { // use a buffer_ptr to allocate the memory to free char* const new_ptr = ptr + size + _size_marker; - buffer_ptr excess_to_free(new_ptr, -diff, _heap + _heap_size); + buffer_ptr excess_to_free(new_ptr, *orig_ptr_size - size, _heap + _heap_size); excess_to_free.mark_free(); return ptr; @@ -297,11 +294,11 @@ namespace eosio { else if (orig_buffer_end == &_heap[_offset]) { orig_buffer.size(size); - _offset += diff; + _offset += size - *orig_ptr_size; return ptr; } - if (-diff == 0) + if (size == *orig_ptr_size ) return ptr; if (!orig_buffer.merge_contiguous_if_available(size)) @@ -418,7 +415,7 @@ namespace eosio { bool merge_contiguous(uint32_t needed_size, bool all_or_nothing) { // do not bother if there isn't contiguious space to allocate - if (all_or_nothing && _heap_end - _ptr < needed_size) + if( all_or_nothing && uint32_t(_heap_end - _ptr) < needed_size ) return false; uint32_t possible_size = _size; @@ -472,7 +469,7 @@ namespace eosio { uint32_t _heaps_actual_size; uint32_t _active_heap; uint32_t _active_free_heap; - static const uint32_t _alloc_memory_mask = 1 << 31; + static const uint32_t _alloc_memory_mask = uint32_t(1) << 31; }; memory_manager memory_heap; diff --git a/contracts/eosiolib/fixedpoint.hpp b/contracts/eosiolib/fixedpoint.hpp index e8b14ca2b36df1400a32bf69551e2c5463f853dc..e2836ef190e995e275826c38e0bd9fedf031399b 100644 --- a/contracts/eosiolib/fixedpoint.hpp +++ b/contracts/eosiolib/fixedpoint.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include namespace eosio { @@ -148,8 +149,15 @@ ope * fixed_point128<3> b(a); if(!Q) return 0; return val << (32-Q); } - - + + void print() const { + uint128_t ip(int_part()); + uint128_t fp(frac_part()); + printi128(&ip); + prints("."); + printi128(&fp); + } + // Various assignment operators template fixed_point128 &operator=(const fixed_point32 &r); template fixed_point128 &operator=(const fixed_point64 &r); @@ -225,6 +233,12 @@ ope * fixed_point128<3> b(a); return val << (32-Q); } + void print() const { + printi(int_part()); + prints("."); + printi128(frac_part()); + } + // Various assignment operators template fixed_point64 &operator=(const fixed_point32 &r); template fixed_point64 &operator=(const fixed_point64 &r); @@ -295,6 +309,12 @@ ope * fixed_point128<3> b(a); return val << (32-Q); } + void print() const { + printi(int_part()); + prints("."); + printi128(frac_part()); + } + // Various assignment operators template fixed_point32 &operator=(const fixed_point32 &r); template fixed_point32 &operator=(const fixed_point64 &r); @@ -440,6 +460,7 @@ ope * fixed_point128<3> b(a); // std::cout << "Performing division on " << val << ", with " << q << " precision / " << r.val << ", with " << qr << " precision. Result precision " << ((q>qr) ? q:qr) << std::endl; // Convert val to 128 bit by additionally shifting 64 bit and take the result to 128bit // Q(X+64-Y) = Q(X+64) / Q(Y) + eosio_assert( !(r.int_part() == 0 && r.frac_part() == 0), "divide by zero" ); return fixed_point128((int128_t(val)<<64)/r.val); } @@ -536,6 +557,7 @@ ope * fixed_point128<3> b(a); fixed_point64 fixed_point32::operator/(const fixed_point32 &r) const { // Convert val into 64 bit and perform the division // Q(X+32-Y) = Q(X+32) / Q(Y) + eosio_assert( !(r.int_part() == 0 && r.frac_part() == 0), "divide by zero" ); return fixed_point64((int64_t(val)<<32)/r.val); } @@ -552,6 +574,8 @@ ope * fixed_point128<3> b(a); template fixed_point64 fixed_divide(uint32_t lhs, uint32_t rhs) { + + eosio_assert( rhs != 0, "divide by zero" ); fixed_point64 result = fixed_point32<0>(lhs) / fixed_point32<0>(rhs); return result; } @@ -569,6 +593,8 @@ ope * fixed_point128<3> b(a); template fixed_point128 fixed_divide(uint64_t lhs, uint64_t rhs) { + + eosio_assert( rhs != 0, "divide by zero" ); fixed_point128 result = fixed_point64<0>(lhs) / fixed_point64<0>(rhs); return fixed_point128(result); } diff --git a/contracts/eosiolib/generic_currency.hpp b/contracts/eosiolib/generic_currency.hpp index 8ac1fbdd52a9108d7def9ecb371380047c1af891..ef9e06ee1680dc123148badd4e112383a207ed37 100644 --- a/contracts/eosiolib/generic_currency.hpp +++ b/contracts/eosiolib/generic_currency.hpp @@ -110,7 +110,7 @@ namespace eosio { static void inline_transfer( account_name from, account_name to, token_type quantity, string memo = string() ) { - action act( permission_level(code,N(active)), transfer_memo( from, to, asset(quantity), move(memo) )); + action act( permission_level(from,N(active)), transfer_memo( from, to, asset(quantity), move(memo) )); act.send(); } diff --git a/contracts/eosiolib/math.h b/contracts/eosiolib/math.h index e6c7652ba6b494aa84b70ff4a411e330f16e1639..9aa41bea91f0f4ac3cdb78df5b8ae069c222bb44 100644 --- a/contracts/eosiolib/math.h +++ b/contracts/eosiolib/math.h @@ -157,7 +157,7 @@ extern "C" { * Convert double (interpreted as 64 bit unsigned integer) to 64 bit unsigned integer. * This function will first reinterpret_cast the input to double (50 decimal digit precision) then convert it to double, then reinterpret_cast it to 64 bit unsigned integer. * @brief Convert double to 64 bit unsigned integer - * @param self Value in double interpreted as 64 bit unsigned integer + * @param a - value in double interpreted as 64 bit unsigned integer * @return Result of conversion in 64 bit unsigned integer * * Example: @@ -173,7 +173,7 @@ extern "C" { * Convert 64 bit unsigned integer to double (interpreted as 64 bit unsigned integer). * This function will convert the input to double (50 decimal digit precision) then reinterpret_cast it to 64 bit unsigned integer. * @brief Convert 64 bit unsigned integer to double (interpreted as 64 bit unsigned integer) - * @param self Value to be converted + * @param a - value to be converted * @return Result of conversion in double (interpreted as 64 bit unsigned integer) * * Example: diff --git a/contracts/eosiolib/multi_index.hpp b/contracts/eosiolib/multi_index.hpp index 63f3ad81d9aed9b70a241da02db3e36964c948ee..3b06278f0750e501301c10222013c35dd9f89ebc 100644 --- a/contracts/eosiolib/multi_index.hpp +++ b/contracts/eosiolib/multi_index.hpp @@ -29,6 +29,9 @@ struct secondary_iterator { static int db_idx_next( int iterator, uint64_t* primary ) { return db_idx64_next( iterator, primary ); } static int db_idx_prev( int iterator, uint64_t* primary ) { return db_idx64_previous( iterator, primary ); } static void db_idx_remove( int iterator ) { db_idx64_remove( iterator ); } + static int db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, uint64_t& secondary ) { + return db_idx64_find_primary( code, scope, table, &secondary, primary ); + } }; template<> @@ -36,8 +39,19 @@ struct secondary_iterator { static int db_idx_next( int iterator, uint64_t* primary ) { return db_idx128_next( iterator, primary ); } static int db_idx_prev( int iterator, uint64_t* primary ) { return db_idx128_previous( iterator, primary ); } static void db_idx_remove( int iterator ) { db_idx128_remove( iterator ); } + static int db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, + uint64_t primary, uint128_t& secondary ) { + return db_idx128_find_primary( code, scope, table, &secondary, primary ); + } }; +int db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t primary, const uint64_t& secondary ) { + return db_idx64_store( scope, table, payer, primary, &secondary ); +} +int db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t primary, const uint128_t& secondary ) { + return db_idx128_store( scope, table, payer, primary, &secondary ); +} + void db_idx_update( int iterator, uint64_t payer, const uint64_t& secondary ) { db_idx64_update( iterator, payer, &secondary ); } @@ -77,67 +91,73 @@ int db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, uint128_t& template class multi_index; +template +struct indexed_by { + enum constants { index_name = IndexName }; + typedef Extractor secondary_extractor_type; + typedef decltype( Extractor()(nullptr) ) secondary_type; +}; -template +template struct index_by { - //typedef typename std::decay::type value_type; - typedef Extractor extractor_secondary_type; - typedef decltype( Extractor()(nullptr) ) secondary_type; + typedef Extractor extractor_secondary_type; + typedef typename std::decay::type secondary_type; index_by(){} - static const int index_number = IndexNumber; - static const uint64_t index_name = IndexName; + enum constants { + index_name = IndexName, + index_number = N + }; + + constexpr static int number() { return N; } + constexpr static uint64_t name() { return IndexName; } private: template friend class multi_index; - Extractor extract_secondary_key; + static auto extract_secondary_key(const T& obj) { return extractor_secondary_type()(obj); } - int store( uint64_t scope, uint64_t payer, const T& obj ) { - // fetch primary key and secondary key here.. - return -1; + static int store( uint64_t scope, uint64_t payer, const T& obj ) { + return db_idx_store( scope, IndexName, payer, obj.primary_key(), extract_secondary_key(obj) ); } - void update( int iterator, uint64_t payer, const secondary_type& secondary ) { + + static void update( int iterator, uint64_t payer, const secondary_type& secondary ) { db_idx_update( iterator, payer, secondary ); } - int find_primary( uint64_t code, uint64_t scope, uint64_t primary, secondary_type& secondary )const { + static int find_primary( uint64_t code, uint64_t scope, uint64_t primary, secondary_type& secondary ) { return db_idx_find_primary( code, scope, IndexName, secondary, primary ); } - void remove( int itr ) { + static void remove( int itr ) { secondary_iterator::db_idx_remove( itr ); } - int find_secondary( uint64_t code, uint64_t scope, secondary_type& secondary, uint64_t& primary )const { + static int find_secondary( uint64_t code, uint64_t scope, secondary_type& secondary, uint64_t& primary ) { return db_idx_find_secondary( code, scope, IndexName, secondary, primary ); } - int lower_bound( uint64_t code, uint64_t scope, secondary_type& secondary, uint64_t& primary )const { + static int lower_bound( uint64_t code, uint64_t scope, secondary_type& secondary, uint64_t& primary ) { return db_idx_lowerbound( code, scope, IndexName, secondary, primary ); } - int upper_bound( uint64_t code, uint64_t scope, secondary_type& secondary, uint64_t& primary )const { + static int upper_bound( uint64_t code, uint64_t scope, secondary_type& secondary, uint64_t& primary ) { return db_idx_upperbound( code, scope, IndexName, secondary, primary ); } }; -/* -template -auto make_index_by( Extractor&& l ) { - return index_by{ std::forward(l) }; -} -*/ + +namespace hana = boost::hana; + template class multi_index { private: - struct item : public T { template @@ -148,14 +168,34 @@ class multi_index const multi_index& __idx; int __primary_itr; - int __iters[sizeof...(Indicies)]; + int __iters[sizeof...(Indicies)+(sizeof...(Indicies)==0)]; }; uint64_t _code; uint64_t _scope; - boost::hana::tuple _indicies; + template + struct intc { enum e{ value = I }; operator uint64_t()const{ return I; } }; + + static constexpr auto transform_indicies( ) { + typedef decltype( hana::zip_shortest( + hana::make_tuple( intc<0>(), intc<1>(), intc<2>(), intc<3>(), intc<4>(), intc<5>() ), + hana::tuple() ) ) indicies_input_type; + + return hana::transform( indicies_input_type(), [&]( auto&& idx ){ + typedef typename std::decay(idx))>::type num_type; + typedef typename std::decay(idx))>::type idx_type; + return index_by(); + + }); + } + + typedef decltype( multi_index::transform_indicies() ) indicies_type; + indicies_type _indicies; struct by_primary_key; struct by_primary_itr; @@ -167,9 +207,6 @@ class multi_index > > _items_index; -// mutable std::map _items; /// by_primary_key -// mutable std::map _items_by_itr; - const item& load_object_by_primary_iterator( int itr )const { const auto& by_pitr = _items_index.template get(); auto cacheitr = by_pitr.find( itr ); @@ -177,10 +214,11 @@ class multi_index return *cacheitr; auto size = db_get_i64( itr, nullptr, 0 ); + eosio_assert( size >= 0, "error reading iterator" ); char tmp[size]; - db_get_i64( itr, tmp, size ); + db_get_i64( itr, tmp, uint32_t(size) ); - datastream ds(tmp,size); + datastream ds(tmp,uint32_t(size)); auto result = _items_index.emplace( *this, [&]( auto& i ) { T& val = static_cast(i); @@ -188,7 +226,7 @@ class multi_index i.__primary_itr = itr; boost::hana::for_each( _indicies, [&]( auto& idx ) { - i.__iters[idx.index_number] = -1; + i.__iters[ idx.number() ] = -1; }); }); @@ -202,18 +240,20 @@ class multi_index public: multi_index( uint64_t code, uint64_t scope ):_code(code),_scope(scope){} - ~multi_index() { - } - template + uint64_t get_code()const { return _code; } + uint64_t get_scope()const { return _scope; } + + template struct index { + private: typedef typename MultiIndexType::item item_type; typedef typename IndexType::secondary_type secondary_key_type; + public: + static constexpr uint64_t name() { return IndexType::name(); } struct const_iterator { - private: - public: friend bool operator == ( const const_iterator& a, const const_iterator& b ) { return a._item == b._item; @@ -231,8 +271,20 @@ class multi_index } const_iterator& operator++() { + if( !_item ) return *this; + if( _item->__iters[Number] == -1 ) { + /// TODO: lookup iter for this item in this index + secondary_key_type temp_secondary_key; + auto idxitr = secondary_iterator::db_idx_find_primary( + _idx.get_code(), + _idx.get_scope(), + _idx.name(), + _item->primary_key(), temp_secondary_key); + } + + uint64_t next_pk = 0; - auto next_itr = secondary_iterator::db_idx_next( _item->__iters[IndexType::index_number], &next_pk ); + auto next_itr = secondary_iterator::db_idx_next( _item->__iters[Number], &next_pk ); if( next_itr == -1 ) { _item = nullptr; return *this; @@ -240,15 +292,18 @@ class multi_index const T& obj = *_idx._multidx.find( next_pk ); auto& mi = const_cast( static_cast(obj) ); - mi.__iters[IndexType::index_number] = next_itr; + mi.__iters[Number] = next_itr; _item = &mi; return *this; } const_iterator& operator--() { + if( !_item ) { + + } uint64_t prev_pk = 0; - auto prev_itr = secondary_iterator::db_idx_prev( _item->__iters[IndexType::index_number], &prev_pk ); + auto prev_itr = secondary_iterator::db_idx_prev( _item->__iters[Number], &prev_pk ); if( prev_itr == -1 ) { _item = nullptr; return *this; @@ -256,7 +311,7 @@ class multi_index const T& obj = *_idx._multidx.find( prev_pk ); auto& mi = const_cast( static_cast(obj) ); - mi.__iters[IndexType::index_number] = prev_itr; + mi.__iters[Number] = prev_itr; _item = &mi; return *this; @@ -266,7 +321,7 @@ class multi_index const T* operator->()const { return *static_cast(_item); } private: - friend class index; + friend struct index; const_iterator( const index& idx, const typename MultiIndexType::item* i = nullptr ) :_idx(idx), _item(i){} @@ -281,24 +336,25 @@ class multi_index } const_iterator lower_bound( typename IndexType::secondary_type& secondary ) { uint64_t primary = 0; - auto itr = _idx.lower_bound( _multidx._code, _multidx._scope, secondary, primary ); + auto itr = IndexType::lower_bound( _multidx._code, _multidx._scope, secondary, primary ); if( itr == -1 ) return end(); const T& obj = *_multidx.find( primary ); auto& mi = const_cast( static_cast(obj) ); - mi.__iters[IndexType::index_number] = itr; + mi.__iters[Number] = itr; return const_iterator( *this, &mi ); } + uint64_t get_code()const { return _multidx.get_code(); } + uint64_t get_scope()const { return _multidx.get_scope(); } private: friend class multi_index; - index( const MultiIndexType& midx, const IndexType& idx ) - :_multidx(midx),_idx(idx){} + index( const MultiIndexType& midx ) //, const IndexType& idx ) + :_multidx(midx){} const MultiIndexType _multidx; - const IndexType& _idx; }; @@ -323,14 +379,20 @@ class multi_index //eosio_assert( _item, "null ptr" ); uint64_t pk; auto next_itr = db_next_i64( _item->__primary_itr, &pk ); - _item = &_multidx.load_object_by_primary_iterator( next_itr ); + if( next_itr == -1 ) + _item = nullptr; + else + _item = &_multidx.load_object_by_primary_iterator( next_itr ); return *this; } const_iterator& operator--() { //eosio_assert( _item, "null ptr" ); uint64_t pk; auto next_itr = db_previous_i64( _item->__primary_itr, &pk ); - _item = &_multidx.load_object_by_primary_iterator( next_itr ); + if( next_itr == -1 ) + _item = nullptr; + else + _item = &_multidx.load_object_by_primary_iterator( next_itr ); return *this; } @@ -372,9 +434,21 @@ class multi_index } template auto get_index()const { - const auto& idx = boost::hana::find_if( _indicies, []( auto x ){ - return std::integral_constant(); } ).value(); - return index::type>( *this, idx ); + auto idx = boost::hana::find_if( _indicies, []( auto&& in ){ + /* + auto& x = hana::at_c<1>(idxp); + return std::integral_constant::type::index_name == IndexName)>(); + */ + return std::integral_constant::type::index_name == IndexName>(); + } ).value(); + + return index( *this ); + + /* + typedef typename std::decay(idx))>::type num_type; + + return index(idx))>::type, num_type::value >( *this, hana::at_c<1>(idx) ); + */ } template @@ -391,7 +465,7 @@ class multi_index i.__primary_itr = db_store_i64( _scope, TableName, payer, pk, tmp, sizeof(tmp) ); boost::hana::for_each( _indicies, [&]( auto& idx ) { - i.__iters[idx.index_number] = idx.store( _scope, payer, obj ); + i.__iters[idx.number()] = idx.store( _scope, payer, obj ); }); }); @@ -406,7 +480,7 @@ class multi_index // eosio_assert( &objitem.__idx == this, "invalid object" ); - auto secondary_keys = boost::hana::transform( _indicies, [&]( auto& idx ) { + auto secondary_keys = boost::hana::transform( _indicies, [&]( auto&& idx ) { return idx.extract_secondary_key( obj ); }); @@ -421,18 +495,25 @@ class multi_index db_update_i64( objitem.__primary_itr, payer, tmp, sizeof(tmp) ); boost::hana::for_each( _indicies, [&]( auto& idx ) { + typedef typename std::decay::type index_type; + auto secondary = idx.extract_secondary_key( mutableobj ); - if( boost::hana::at_c::type::index_number>(secondary_keys) != secondary ) { - auto indexitr = mutableitem.__iters[idx.index_number]; + if( hana::at_c(secondary_keys) != secondary ) { + auto indexitr = mutableitem.__iters[idx.number()]; if( indexitr == -1 ) - indexitr = mutableitem.__iters[idx.index_number] = idx.find_primary( _code, _scope, pk, secondary ); + indexitr = mutableitem.__iters[idx.number()] = idx.find_primary( _code, _scope, pk, secondary ); idx.update( indexitr, payer, secondary ); } }); } + const T& get( uint64_t primary )const { + auto result = find( primary ); + eosio_assert( result != nullptr, "unable to find key" ); + return *result; + } const T* find( uint64_t primary )const { auto cacheitr = _items_index.find(primary); if( cacheitr != _items_index.end() ) @@ -453,7 +534,7 @@ class multi_index db_remove_i64( objitem.__primary_itr ); boost::hana::for_each( _indicies, [&]( auto& idx ) { - auto i = objitem.__iters[idx.index_number]; + auto i = objitem.__iters[idx.number()]; if( i == -1 ) { typename std::decay::type::secondary_type second; i = idx.find_primary( _code, _scope, objitem.primary_key(), second ); diff --git a/contracts/eosiolib/multiindex.hpp b/contracts/eosiolib/multiindex.hpp deleted file mode 100644 index 80f751a7b38bc1908517b0d9d46f508463bb87bb..0000000000000000000000000000000000000000 --- a/contracts/eosiolib/multiindex.hpp +++ /dev/null @@ -1,341 +0,0 @@ - -extern "C" { - /** - * - * @return an ID that serves as an iterator to the object stored, -1 for error - */ - int db_store_i64( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, char* buffer, size_t buffer_size ); - int db_update_i64( int iterator, char* buffer, size_t buffer_size ); - - /** - * max_buffer_size should start out with the space reserved for buffer, but is set to the actual size of buffer - * - * if max_buffer_size is greater than actual buffer size, then buffer will be filled with contents, otherwise not - * - * @return an ID that serves as an iterator to the object stored, -1 for error/not found - */ - int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id, char* buffer, size_t* max_buffer_size ); - int db_lower_bound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id, char* buffer, size_t* max_buffer_size ); - int db_upper_bound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id, char* buffer, size_t* max_buffer_size ); - - /** return an iterator to the next item after @param iterator and optionally fetch data if buffer is not null */ - int db_next( int iterator, uint64_t* id, char* buffer, size_t* max_buffer_size ); - /** return an iterator to the prev item after @param iterator and optionally fetch data if buffer is not null */ - int db_prev( int iterator, uint64_t* id, char* buffer, size_t* max_buffer_size ); - - /** - * @return the number of elements in the table stored at code/scope/table - */ - int db_count_i64( uint64_t code, uint64_t scope, uint64_t table ); - void db_remove_i64( int iterator ); - - int db_find_primary_index64( uint64_t scope, uint64_t table, uint64_t primary, uint64_t* secondary ); - int db_find_secondary_index64( uint64_t scope, uint64_t table, uint64_t* primary, uint64_t secondary ); - - int db_upper_bound_primary_index64( uint64_t scope, uint64_t table, uint64_t primary, uint64_t* secondary ); - int db_upper_bound_secondary_index64( uint64_t scope, uint64_t table, uint64_t* primary, uint64_t secondary ); - - int db_lower_bound_primary_index64( uint64_t scope, uint64_t table, uint64_t primary, uint64_t* secondary ); - int db_lower_bound_secondary_index64( uint64_t scope, uint64_t table, uint64_t* primary, uint64_t secondary ); - - int db_update_index64( int iterator, uint64_t payer, uint64_t id, uint64_t indexvalue ); - int db_remove_index64( int iterator ); - int db_next_index64( int iterator, uint64_t* value ); - int db_prev_index64( int iterator, uint64_t* value ); - - int db_find_primary_index128( uint64_t scope, uint64_t table, uint64_t primary, uint128_t* secondary ); - int db_find_secondary_index128( uint64_t scope, uint64_t table, uint64_t* primary, const uint128_t* secondary ); - - int db_upper_bound_primary_index128( uint64_t scope, uint64_t table, uint64_t primary, uint128_t* secondary ); - int db_upper_bound_secondary_index128( uint64_t scope, uint64_t table, uint64_t* primary, const uint128_t* secondary ); - - int db_lower_bound_primary_index128( uint64_t scope, uint64_t table, uint64_t primary, uint128_t* secondary ); - int db_lower_bound_secondary_index128( uint64_t scope, uint64_t table, uint64_t* primary, const uint128_t* secondary ); - - int db_update_index128( int iterator, uint64_t payer, uint64_t id, const uint128_t* secondary ); - int db_remove_index128( int iterator ); - - int db_next_index128( int iterator, uint128_t* value ); - int db_prev_index128( int iterator, uint128_t* value ); -} /// extern "C" - - -namespace eosio { - - namespace detail { - template - struct id_for{}; - } - - struct limit_order { - uint64_t id; - uint128_t price; - uint64_t expiration; - account_name owner; - - uint128_t by_owner_id()const { - uint128_t result(owner); - result << 64; - result |= id; - return result; - } - - uint128_t by_price()const { return price; } - uint64_t by_expiration()const { return expiration; } - - EOSLIB_SERIALIZE( (id)(price)(expiration)(owner) ) - }; - - template - class index_by { - typedef std::decay::type value_type - static const uint64_t index_name = IndexName; - static const uint64_t number = Number; - Extractor ex; - }; - - template - class multi_index { - - auto indicies = make_tuple( make_index(N(byorderid), []( const T& obj ){ return obj.id; }), - make_index(N(byexpiration), []( const T& obj) { return obj.by_expiration(); } ) - make_index(N(byprice), []( const T& obj) { return obj.by_price(); } ) ); - - mutable map _items; - - public: - - - template - const T* find( const Key& k )const { - - } - - template - auto get_keys( const T& obj ) { - return get_keys<1>( std::make_tuple( - } - - template = 0 > - auto get_keys( Existing&& e, const T& obj ) { - return std::tuple_cat( std::forward(e), std::get( indicies ).extract( obj ) ); - } - - template = 0 > - auto get_keys( Existing&& e, const T& obj ) { - return get_keys( std::tuple_cat( std::forward(e), std::get( indicies ).extract( obj ) ), obj ); - } - - - template - const T& create( Lambda&& constructor, uint64_t payer ) { - auto i = new item( *this ); - constructor( static_cast(*i) ); - const T& obj = static_cast(*i); - - char tmp[ pack_size( obj ) ]; - datastream ds( tmp, sizeof(tmp) ); - pack( ds, obj ); - - auto pk = obj.primary_key(); - i->__itrs[0] = db_store_i64( _code, _scope, _tables[0], payer, pk, tmp, sizeof(tmp) ); - - for_each( indicies, [&]( auto& idx ) { - i->__itrs[idx.number] = idx.store( _code, _scope, idx.index_name, payer, pk, idx.extract( obj ) ); - }); - - items[pk] = i; - return obj; - } - - template - void update( const T& obj, uint64_t payer, Lambda&& updater ) { - T& mobj = const_cast(obj); - item& i = static_cast(mobj); - - auto pk = mobj.primary_key(); - - eosio_assert( &i.__mutli_idx == this ); - - auto old_idx = std::make_tuple( - obj.primary_key(), obj.expiration(), obj.by_owner_id(), obj.by_price() ); - updater(mobj); - - char tmp[ pack_size( mobj ) ]; - datastream ds( tmp, sizeof(tmp) ); - pack( ds, mobj ); - db_update_i64( i.__itrs[0], payer, tmp, sizeof(tmp) ); - - auto new_idx = std::make_tuple( - obj.primary_key(), obj.expiration(), obj.by_owner_id(), obj.by_price() ); - - if( std::get<1>(old_idx) != std::get<1>(new_idx) ) { - if( i.__itrs[1] == -2 ) i.__itrs[1] = db_idx64_find_primary( pk ); - db_idx64_update( i.__itrs[1], payer, std::get<1>(new_idx) ); - } - if( std::get<2>(old_idx) != std::get<2>(new_idx) ) { - if( i.__itrs[2] == -2 ) i.__itrs[2] = db_idx64_find_primary( pk ); - db_idx64_update( i.__itrs[2], payer, std::get<2>(new_idx) ); - } - if( std::get<3>(old_idx) != std::get<3>(new_idx) ) { - if( i.__itrs[3] == -2 ) i.__itrs[3] = db_idx64_find_primary( pk ); - db_idx64_update( i.__itrs[3], payer, std::get<3>(new_idx) ); - } - } - - private: - struct item : public T - { - item( multi_index& o ):__mutli_idx(o) { - } - multi_index& __multi_idx; - int __itrs[3]; - }; - - }; - - /* - multi_index< N(limitorders), limit_order, - index< N(ownerid), &limit_order::by_owner_id >, - index< N(byprice), &limit_order::by_price >, - index< N(byexpire), &limit_order::by_expiration> - > orderbook; - */ - - - - - - - - - /* - template - class multi_index { - public: - struct cache_object : public ObjectType { - int primary_itr; - }; - - const cache_object* find( uint64_t primary ) { - auto itr = _cache.find( primary ); - if( itr != cache.end() ) - return itr->second; - db_find_i64( Code, _scope, TableName, primary ); - - } - - private: - std::map _cache; - }; - - - auto order = orderbook.begin(); - auto end = orderbook.end(); - while( order != end ) { - auto cur = order; - ++order; - orderbook.remove( cur ); - } - - const limit_order& order = *orderbook.begin(); - - - /// Options: - // 1. maintain a wasm-side cache of all dereferenced objects - // a. keeps pointers valid - // b. minimizes temporary copies - // c. eliminates redundant deserialization losses - // d. will utilize more heap memory than necessary, potentially hitting sbrk - // - // 2. keep API light and return a copy - - - - - - - template - class index - { - public: - index( uint64_t code, uint64_t scope, uint64_t table ); - - struct iterator { - iterator( index& idx, int itr ) - :_idx(idx), _itr(itr){ - if( itr >= 0 ) - db_index::get( itr, _primary, _secondary ); - } - - uint64_t primary()const { return _primary; } - const SecondaryKeyType& secondary()const { return _secondary; } - - private: - uint64_t _primary; - SecondaryKeyType _secondary; - index& _idx; - int _itr; - }; - - iterator lower_bound( const SecondaryKeyType& lb ) { - return iterator( db_index::secondary_lower_bound( _code, _scope, _table, lb ) ); - } - - private: - uint64_t _code; - uint64_t _scope; - uint64_t _table; - }; - - - - template - class multi_index { - public: - struct iterator { - - private: - int primary_itr; - }; - - - - multi_index( code_name code, scope_name scope, table_name table ) - :_code(code),_scope(scope),_table(table){} - - void insert( const T& obj, account_name payer ) { - uint64_t id = id_for::get(obj); - auto buf = pack(obj); - store_i64( _scope, _table, payer, id, buf.data(), buf.size() ); - Indices::insert( _code, _scope, _table, payer, obj ); - } - - template - void emplace( Constructor&& c ) { - T tmp; - id_for::get(tmp) = allocate_id(); - c(tmp); - insert( tmp ); - } - - - template - void modify( const T& obj, account_name payer, Lambda&& update ) { - update(tmp); - - uint64_t id = id_for::get(value); - auto buf = pack(tmp); - store_i64( _code, _scope, _table, payer, id, buf.data(), buf.size() ); - - Indices::update( _code, _scope, _table, payer, obj ); - } - - - - private: - - }; - - -} // namespace eosio diff --git a/contracts/eosiolib/print.h b/contracts/eosiolib/print.h index 1f2606e257ee4ba65c6c2c07279a1a863a542e70..e327814c56ecd3cf7b8fae0b7cd260cd501080d1 100644 --- a/contracts/eosiolib/print.h +++ b/contracts/eosiolib/print.h @@ -51,7 +51,7 @@ extern "C" { /** * Prints value as a 64 bit unsigned integer * @brief Prints value as a 64 bit unsigned integer - * @param Value of 64 bit unsigned integer to be printed + * @param value of 64 bit unsigned integer to be printed * * Example: * @code @@ -76,7 +76,7 @@ extern "C" { /** * Prints value as double * @brief Prints value as double - * @param Value of double (interpreted as 64 bit unsigned integer) to be printed + * @param value of double (interpreted as 64 bit unsigned integer) to be printed * * Example: * @code @@ -89,7 +89,7 @@ extern "C" { /** * Prints a 64 bit names as base32 encoded string * @brief Prints a 64 bit names as base32 encoded string - * @param Value of 64 bit names to be printed + * @param name - 64 bit name to be printed * * Example: * @code @@ -101,6 +101,7 @@ extern "C" { /** */ void printhex( void* data, uint32_t datalen ); + /// @} #ifdef __cplusplus } diff --git a/contracts/eosiolib/print.hpp b/contracts/eosiolib/print.hpp index 0c994a9e40faf0ad1a1e454836db1ffe7b38759c..4d1c83da1deb76f6fb9db8060d1379c9dbdc0903 100644 --- a/contracts/eosiolib/print.hpp +++ b/contracts/eosiolib/print.hpp @@ -14,7 +14,7 @@ namespace eosio { /** * Prints string * @brief Prints string - * @param cstr - a null terminated string + * @param ptr - a null terminated string */ inline void print( const char* ptr ) { prints(ptr); @@ -23,7 +23,7 @@ namespace eosio { /** * Prints 64 bit unsigned integer as a 64 bit unsigned integer * @brief Prints integer 64 bit unsigned integer - * @param Value to be printed + * @param num to be printed */ inline void print( uint64_t num ) { printi(num); @@ -32,7 +32,7 @@ namespace eosio { /** * Prints 32 bit unsigned integer as a 64 bit unsigned integer * @brief Prints integer 32 bit unsigned integer - * @param Value to be printed + * @param num to be printed */ inline void print( uint32_t num ) { printi(num); @@ -41,16 +41,16 @@ namespace eosio { /** * Prints integer as a 64 bit unsigned integer * @brief Prints integer - * @param Value to be printed + * @param num to be printed */ inline void print( int num ) { - printi(num); + printi(uint64_t(num)); } /** * Prints unsigned integer as a 64 bit unsigned integer * @brief Prints unsigned integer - * @param Value to be printed + * @param num to be printed */ inline void print( unsigned int num ) { printi(num); @@ -59,7 +59,7 @@ namespace eosio { /** * Prints uint128 struct as 128 bit unsigned integer * @brief Prints uint128 struct - * @param Value to be printed + * @param num to be printed */ inline void print( uint128 num ) { printi128((uint128_t*)&num); @@ -68,7 +68,7 @@ namespace eosio { /** * Prints 128 bit unsigned integer * @brief Prints 128 bit unsigned integer - * @param Value to be printed + * @param num to be printed */ inline void print( uint128_t num ) { printi128((uint128_t*)&num); @@ -77,7 +77,7 @@ namespace eosio { /** * Prints a 64 bit names as base32 encoded string * @brief Prints a 64 bit names as base32 encoded string - * @param Value of 64 bit names to be printed + * @param name 64 bit name to be printed */ inline void print( name name ) { printn(name.value); @@ -93,6 +93,24 @@ namespace eosio { } + inline void print_f( const char* s ) { + prints(s); + } + + template + inline void print_f( const char* s, Arg val, Args... rest ) { + while ( *s != '\0' ) { + if ( *s == '%' ) { + print( val ); + print_f( s+1, rest... ); + return; + } + prints_l( s, 1 ); + s++; + } + } + + /** * @defgroup consoleCppapi Console C++ API * @ingroup consoleapi diff --git a/contracts/eosiolib/privileged.h b/contracts/eosiolib/privileged.h index 990da41c81a76fc68594f3cbbd659387454adf62..561176fbd6f5cf37f6b83b65dff273f6088a3144 100644 --- a/contracts/eosiolib/privileged.h +++ b/contracts/eosiolib/privileged.h @@ -16,9 +16,11 @@ extern "C" { * @{ */ - void set_resource_limits( account_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight, int64_t ignored); + void set_resource_limits( account_name account, uint64_t ram_bytes, uint64_t net_weight, uint64_t cpu_weight, int64_t ignored); void set_active_producers( char *producer_data, size_t producer_data_size ); + bool is_privileged( account_name account ); + ///@ } privilegedcapi } diff --git a/contracts/eosiolib/real.hpp b/contracts/eosiolib/real.hpp index ddf18ca2c70b14e0ebafde236ad9c2421840331f..6a6a394d9bebd5718e6546086bc4802a23c3c7a6 100644 --- a/contracts/eosiolib/real.hpp +++ b/contracts/eosiolib/real.hpp @@ -92,8 +92,6 @@ namespace eosio { * @brief Compares two double variables c1 and c2 * * @details Compares two double variables c1 and c2 - * @param c1 - * @param c2 * @return if c1 == c2, return true, otherwise false */ bool operator==(const real &c1, const real &c2) { @@ -105,8 +103,6 @@ namespace eosio { * @brief Compares two double variables c1 and c2 * * @details Compares two double variables c1 and c2 - * @param c1 - * @param c2 * @return if c1 > c2, return true, otherwise false */ bool operator>(const real &c1, const real &c2) { @@ -118,8 +114,6 @@ namespace eosio { * @brief Compares two double variables c1 and c2 * * @details Compares two double variables c1 and c2 - * @param c1 - * @param c2 * @return if c1 < c2, return true, otherwise false */ bool operator<(const real &c1, const real &c2) { diff --git a/contracts/eosiolib/singleton.hpp b/contracts/eosiolib/singleton.hpp index 6f3f862362948da77442804ea618ab569b6c59d3..962b4a44fd54bf4c12ab638ac406fdc7b93fd242 100644 --- a/contracts/eosiolib/singleton.hpp +++ b/contracts/eosiolib/singleton.hpp @@ -38,7 +38,7 @@ namespace eosio { if ( read < 0 ) { return def; } - return unpack( temp + sizeof(SingletonName), read ); + return unpack( temp + sizeof(SingletonName), size_t(read) ); } static T get_or_create( scope_name scope = Code, const T& def = T() ) { diff --git a/contracts/eosiolib/table.hpp b/contracts/eosiolib/table.hpp index 2b641f2a401b8927e5f179d9393415851235d70b..7f5f388e033629389d540d7a45c8d7233e475758 100644 --- a/contracts/eosiolib/table.hpp +++ b/contracts/eosiolib/table.hpp @@ -23,7 +23,7 @@ namespace eosio { auto read = load_i64( DefaultScope, scope , TableName, temp, sizeof(temp) ); eosio_assert( read > 0, "key does not exist" ); - datastream ds(temp, read); + datastream ds(temp, uint32_t(read) ); T result; ds >> result; return result; @@ -39,7 +39,7 @@ namespace eosio { return def; } - datastream ds(temp, read); + datastream ds(temp, uint32_t(read) ); T result; ds >> result; return result; @@ -54,7 +54,7 @@ namespace eosio { return def; } - datastream ds(temp, read); + datastream ds(temp, uint32_t(read) ); T result; ds >> result; return result; diff --git a/contracts/eosiolib/token.hpp b/contracts/eosiolib/token.hpp index aa9aa9cf6ebb06d87dde73fcbdffd9d2c0f8851b..6ecedc0f471c2adf421a73390956f68384cf2183 100644 --- a/contracts/eosiolib/token.hpp +++ b/contracts/eosiolib/token.hpp @@ -49,7 +49,7 @@ namespace eosio { * @brief Constructor for token given quantity of tokens available * @param v - quantity of tokens available */ - explicit token( NumberType v ):quantity(v){}; + explicit token( NumberType v ):quantity(v){} /** * Quantity of tokens available diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h index 749706b46c108e8a17b1f41ef69e07343adf0500..257224d3f29ea80a765faec7ce3efcaf43c526c3 100644 --- a/contracts/eosiolib/transaction.h +++ b/contracts/eosiolib/transaction.h @@ -72,26 +72,22 @@ extern "C" { /** * get the size of the currently executing transaction - * @return */ size_t transaction_size(); /** * get the block number used for TAPOS on the currently executing transaction * - * @return */ int tapos_block_num(); /** * get the block prefix used for TAPOS on the currently executing transaction - * @return */ int tapos_block_prefix(); /** * get the expiration of the currently executing transaction - * @return */ time expiration(); diff --git a/contracts/eosiolib/transaction.hpp b/contracts/eosiolib/transaction.hpp index d1bb1a9a35fb74db4f7d0cd790ee2f2bc0356773..2890edb64788cbd570784c76e1c1d5848e16b6e6 100644 --- a/contracts/eosiolib/transaction.hpp +++ b/contracts/eosiolib/transaction.hpp @@ -24,8 +24,8 @@ namespace eosio { class transaction { public: - transaction(time expiration = now() + 60, region_id region = 0) - :expiration(expiration),region(region) + transaction(time exp = now() + 60, region_id r = 0) + :expiration(exp),region(r) {} void send(uint32_t sender_id, time delay_until = 0) const { @@ -36,11 +36,14 @@ namespace eosio { time expiration; region_id region; uint16_t ref_block_num; - uint32_t ref_block_id; + uint32_t ref_block_prefix; + uint16_t packed_bandwidth_words = 0; /// number of 8 byte words this transaction can compress into + uint16_t context_free_cpu_bandwidth = 0; /// number of CPU usage units to bill transaction for + vector context_free_actions; vector actions; - EOSLIB_SERIALIZE( transaction, (expiration)(region)(ref_block_num)(ref_block_id)(actions) ); + EOSLIB_SERIALIZE( transaction, (expiration)(region)(ref_block_num)(ref_block_prefix)(packed_bandwidth_words)(context_free_cpu_bandwidth)(context_free_actions)(actions) ) }; class deferred_transaction : public transaction { diff --git a/contracts/eosiolib/types.h b/contracts/eosiolib/types.h index 05be74311ab8c3eb9b18b774944269809232f020..390a88c56590c2665e414fc95dbd0f52f501b61c 100644 --- a/contracts/eosiolib/types.h +++ b/contracts/eosiolib/types.h @@ -6,6 +6,10 @@ #include #include +/* +struct checksum_base { +}; +*/ #ifdef __cplusplus extern "C" { @@ -38,15 +42,23 @@ typedef int64_t share_type; #define PACKED(X) __attribute((packed)) X struct public_key { - uint8_t data[33]; + char data[34]; }; struct signature { - uint8_t data[65]; + uint8_t data[66]; +}; + +struct checksum256 { + uint8_t hash[32]; +}; + +struct checksum160 { + uint8_t hash[20]; }; -struct checksum { - uint64_t hash[4]; +struct checksum512 { + uint8_t hash[64]; }; struct fixed_string16 { diff --git a/contracts/eosiolib/types.hpp b/contracts/eosiolib/types.hpp index df08e24b90a00fa26b68724d1544301276fb51a4..44d4af330b890334e21ece5ef80af260975c66bb 100644 --- a/contracts/eosiolib/types.hpp +++ b/contracts/eosiolib/types.hpp @@ -13,7 +13,7 @@ namespace eosio { * @details Converts a base32 symbol into its binary representation, used by string_to_name() * @ingroup types */ - static constexpr char char_to_symbol( char c ) { + static constexpr char char_to_symbol( char c ) { if( c >= 'a' && c <= 'z' ) return (c - 'a') + 6; if( c >= '1' && c <= '5' ) @@ -39,7 +39,7 @@ namespace eosio { for( uint32_t i = 0; i <= 12; ++i ) { uint64_t c = 0; - if( i < len && i <= 12 ) c = char_to_symbol( str[i] ); + if( i < len && i <= 12 ) c = uint64_t(char_to_symbol( str[i] )); if( i < 12 ) { c &= 0x1f; @@ -90,5 +90,4 @@ namespace eosio { /// @} - } // namespace eos diff --git a/contracts/eosiolib/varint.hpp b/contracts/eosiolib/varint.hpp index c931e4deac8199863952d7f6cd08d471cdc87725..ac8fe3ce75ca288aa22cd8c4a16b98f1cf60103e 100644 --- a/contracts/eosiolib/varint.hpp +++ b/contracts/eosiolib/varint.hpp @@ -23,7 +23,7 @@ struct unsigned_int { template operator T()const { return static_cast(value); } - unsigned_int& operator=( int32_t v ) { value = v; return *this; } + unsigned_int& operator=( uint32_t v ) { value = v; return *this; } uint32_t value; @@ -102,7 +102,7 @@ struct signed_int { template friend DataStream& operator << ( DataStream& ds, const signed_int& v ){ - uint32_t val = (v.value<<1) ^ (v.value>>31); + uint32_t val = uint32_t((v.value<<1) ^ (v.value>>31)); do { uint8_t b = uint8_t(val) & 0x7f; val >>= 7; diff --git a/contracts/libc++/CMakeLists.txt b/contracts/libc++/CMakeLists.txt index 72fd6a7853cc06eb54f7a02767d68ff830f2f436..d59707a64ccc2117491a65c63aec18ee390a3472 100644 --- a/contracts/libc++/CMakeLists.txt +++ b/contracts/libc++/CMakeLists.txt @@ -9,6 +9,7 @@ FOREACH(FN ${SRC_FILENAMES}) ENDFOREACH(FN) add_wast_library(TARGET libc++ + NOWARNINGS SOURCE_FILES "${SRC_FILES}" INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} diff --git a/contracts/multi_index_test/CMakeLists.txt b/contracts/multi_index_test/CMakeLists.txt index c1f0faf35b8d2bab1cc17e5e55a880432e33a13b..50606049b242e515fe5b4a6a0f44672f10231885 100644 --- a/contracts/multi_index_test/CMakeLists.txt +++ b/contracts/multi_index_test/CMakeLists.txt @@ -2,7 +2,7 @@ file(GLOB ABI_FILES "*.abi") set(ABI_FILES "multi_index_test.abi") add_wast_executable(TARGET multi_index_test - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" /usr/local/include + INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" LIBRARIES libc++ libc eosiolib DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/contracts/multi_index_test/multi_index_test.cpp b/contracts/multi_index_test/multi_index_test.cpp index 5dab7854ce44cf3ab6e9db019cdc5ad12132e357..e00874105561b83f179f51eec586d8f4983ef617 100644 --- a/contracts/multi_index_test/multi_index_test.cpp +++ b/contracts/multi_index_test/multi_index_test.cpp @@ -5,6 +5,7 @@ using namespace eosio; struct limit_order { uint64_t id; + uint64_t padding = 0; uint128_t price; uint64_t expiration; account_name owner; @@ -20,8 +21,8 @@ extern "C" { /// The apply method implements the dispatch of events to this contract void apply( uint64_t code, uint64_t action ) { eosio::multi_index >, - index_by<1, N(byprice), limit_order, const_mem_fun > + indexed_by >, + indexed_by > > orders( N(exchange), N(exchange) ); auto payer = code; @@ -32,6 +33,7 @@ extern "C" { }); orders.update( order, payer, [&]( auto& o ) { + o.expiration = 4; }); const auto* o = orders.find( 1 ); @@ -41,9 +43,11 @@ extern "C" { auto expidx = orders.get_index(); for( const auto& item : orders ) { + (void)item.id; } for( const auto& item : expidx ) { + (void)item.id; } auto lower = expidx.lower_bound(4); diff --git a/contracts/musl/CMakeLists.txt b/contracts/musl/CMakeLists.txt index c4df0b239a5c3437940df7b22d35ed9c5352579f..30912e0b5084e3c26c768fab95a4e04d6b426912 100644 --- a/contracts/musl/CMakeLists.txt +++ b/contracts/musl/CMakeLists.txt @@ -16,6 +16,7 @@ file(GLOB THREAD_SOURCES "upstream/src/thread/*.c") #only for __lock __unlock set(INTERNAL_SOURCES upstream/src/internal/intscan.c upstream/src/internal/shgetc.c upstream/src/internal/libc.c) add_wast_library(TARGET libc + NOWARNINGS SOURCE_FILES ${CRYPT_SOURCES} ${CTYPE_SOURCES} ${ENV_SOURCES} ${ERRNO_SOURCES} ${EXIT_SOURCES} ${INTERNAL_SOURCES} ${LOCALE_SOURCES} ${MBYTE_SOURCES} ${MISC_SOURCES} ${SEARCH_SOURCES} ${STDIO_SOURCES} ${STDLIB_SOURCES} ${STRING_SOURCES} ${TIME_SOURCES} ${THREAD_SOURCES} INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include diff --git a/contracts/stltest/stltest.cpp b/contracts/stltest/stltest.cpp index d2b37110f8cf5607f4de975c31f4e7f698d1f769..457819ef3510dd67e12807109f5a52729a8e11b3 100644 --- a/contracts/stltest/stltest.cpp +++ b/contracts/stltest/stltest.cpp @@ -2,8 +2,6 @@ * @file * @copyright defined in eos/LICENSE.txt */ -#include /// defines transfer struct (abi) - // include entire libc #include #include @@ -195,7 +193,7 @@ namespace stltest { prints("f() called\n"); } - static void on(const message& msg) { + static void on( const message& ) { /* manual initialization of global variable new(&std::__start_std_streams)std::ios_base::Init; */ @@ -246,7 +244,7 @@ namespace stltest { std::map m; m.emplace(0, 1); - auto mit = m.lower_bound(2); + m.lower_bound(2); std::set st; st.insert(0); @@ -259,7 +257,7 @@ namespace stltest { //hs.insert(0); sort(dq.begin(), dq.end()); - auto lit = find_if(l.begin(), l.end(), [](uint32_t f) { return f < 10; }); + find_if(l.begin(), l.end(), [](uint32_t f) { return f < 10; }); prints("STL test done.\n"); //std::cout << "STL test done." << std::endl; } diff --git a/contracts/stltest/stltest.hpp b/contracts/stltest/stltest.hpp deleted file mode 100644 index 7b9637ef9c2c043f20cd95de027e160de40fec49..0000000000000000000000000000000000000000 --- a/contracts/stltest/stltest.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once \ No newline at end of file diff --git a/contracts/test.system/test.system.cpp b/contracts/test.system/test.system.cpp index 488f1919c921593857910295bc0f512aece31d9b..934f3101cc78f1c63bfefa11219d0d13c39a485e 100644 --- a/contracts/test.system/test.system.cpp +++ b/contracts/test.system/test.system.cpp @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -18,46 +19,41 @@ namespace testsystem { }; struct set_account_limits : dispatchable { - account_name account; - int64_t ram_bytes; - int64_t net_weight; - int64_t cpu_weight; + account_name account; + uint64_t ram_bytes = 0; + uint64_t net_weight = 0; + uint64_t cpu_weight = 0; static void process(const set_account_limits& act) { set_resource_limits(act.account, act.ram_bytes, act.net_weight, act.cpu_weight, 0); } - EOSLIB_SERIALIZE( set_account_limits, (account)(ram_bytes)(net_weight)(cpu_weight) ); + EOSLIB_SERIALIZE( set_account_limits, (account)(ram_bytes)(net_weight)(cpu_weight) ) }; struct set_global_limits : dispatchable { int64_t cpu_usec_per_period; - static void process(const set_global_limits& act) { + static void process(const set_global_limits& ) { // TODO: support this } - EOSLIB_SERIALIZE( set_global_limits, (cpu_usec_per_period) ); + EOSLIB_SERIALIZE( set_global_limits, (cpu_usec_per_period) ) }; struct producer_key { account_name account; std::string public_key; - EOSLIB_SERIALIZE( producer_key, (account)(public_key) ); + EOSLIB_SERIALIZE( producer_key, (account) ) //(public_key) ) }; struct set_producers : dispatchable { - uint32_t version; - vector producers; - static void process(const set_producers&) { char buffer[action_size()]; read_action( buffer, sizeof(buffer) ); set_active_producers(buffer, sizeof(buffer)); } - - EOSLIB_SERIALIZE( set_producers, (version)(producers) ); }; struct require_auth : dispatchable { @@ -93,7 +89,6 @@ namespace testsystem { using dispatcher = dispatcher_impl; }; - extern "C" { /// The apply method implements the dispatch of events to this contract diff --git a/contracts/test_api/test_account.cpp b/contracts/test_api/test_account.cpp deleted file mode 100644 index 6dc22ab52af02a811a15916d6022d47594240dbf..0000000000000000000000000000000000000000 --- a/contracts/test_api/test_account.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file test_account.cpp - * @copyright defined in eos/LICENSE.txt - */ - -#include -#include -#include - -#include "test_api.hpp" - -/// must match #define in eos/types/asset.hpp -#define EOS_SYMBOL (int64_t(4) | (uint64_t('E') << 8) | (uint64_t('O') << 16) | (uint64_t('S') << 24)) - -unsigned int test_account::test_balance_acc1() -{ - eosio::print("test_balance_acc1\n"); - eosio::account::account_balance b; - - b.account = N(acc1); - WASM_ASSERT(eosio::account::get(b), "account_balance_get should have found \"acc1\""); - - WASM_ASSERT(b.account == N(acc1), "account_balance_get should not change the account"); - WASM_ASSERT(b.eos_balance.amount == 24, "account_balance_get should have set a balance of 24"); - WASM_ASSERT(b.eos_balance.symbol == EOS_SYMBOL, "account_balance_get should have a set a balance symbol of EOS"); - WASM_ASSERT(b.staked_balance.amount == 23, "account_balance_get should have set a staked balance of 23"); - WASM_ASSERT(b.staked_balance.symbol == EOS_SYMBOL, "account_balance_get should have a set a staked balance symbol of EOS"); - WASM_ASSERT(b.unstaking_balance.amount == 14, "account_balance_get should have set a unstaking balance of 14"); - WASM_ASSERT(b.unstaking_balance.symbol == EOS_SYMBOL, "account_balance_get should have a set a unstaking balance symbol of EOS"); - WASM_ASSERT(b.last_unstaking_time == 55, "account_balance_get should have set a last unstaking time of 55"); - return WASM_TEST_PASS; -} diff --git a/contracts/test_api/test_action.cpp b/contracts/test_api/test_action.cpp index 6c06e3120060407f39d707992b648b0336b4a26c..6a56f38976b80eb86b5232fcdac7bbecfc32d5c0 100644 --- a/contracts/test_api/test_action.cpp +++ b/contracts/test_api/test_action.cpp @@ -1,11 +1,14 @@ /** - * @file - * @copyright defined in eos/LICENSE.txt + * @file action_test.cpp + * @copyright defined in eos/LICENSE.txt */ #include -#include "test_api.hpp" +#include +#include +#include +#include "test_api.hpp" void test_action::read_action_normal() { char buffer[100]; @@ -28,37 +31,37 @@ void test_action::read_action_normal() { eosio_assert(total == sizeof(dummy_action), "read_action(sizeof(dummy_action))" ); dummy_action *dummy13 = reinterpret_cast(buffer); - eosio_assert(dummy13->a == DUMMY_MESSAGE_DEFAULT_A, "dummy13->a == DUMMY_MESSAGE_DEFAULT_A"); - eosio_assert(dummy13->b == DUMMY_MESSAGE_DEFAULT_B, "dummy13->b == DUMMY_MESSAGE_DEFAULT_B"); - eosio_assert(dummy13->c == DUMMY_MESSAGE_DEFAULT_C, "dummy13->c == DUMMY_MESSAGE_DEFAULT_C"); - + + eosio_assert(dummy13->a == DUMMY_ACTION_DEFAULT_A, "dummy13->a == DUMMY_ACTION_DEFAULT_A"); + eosio_assert(dummy13->b == DUMMY_ACTION_DEFAULT_B, "dummy13->b == DUMMY_ACTION_DEFAULT_B"); + eosio_assert(dummy13->c == DUMMY_ACTION_DEFAULT_C, "dummy13->c == DUMMY_ACTION_DEFAULT_C"); } void test_action::read_action_to_0() { - uint32_t total = read_action((void *)0, 0x7FFFFFFF); + uint32_t total = read_action((void *)0, action_size()); } void test_action::read_action_to_64k() { - uint32_t total = read_action( (void *)((1<<16)-1), 0x7FFFFFFF); + uint32_t total = read_action( (void *)((1<<16)-2), action_size()); +} + +void test_action::require_notice() { + if( current_receiver() == N(testapi) ) { + eosio::require_recipient( N(acc1) ); + eosio::require_recipient( N(acc2) ); + eosio::require_recipient( N(acc1), N(acc2) ); + eosio_assert(false, "Should've failed"); + } else if ( current_receiver() == N(acc1) || current_receiver() == N(acc2) ) { + return; + } + eosio_assert(false, "Should've failed"); } -//unsigned int test_action::require_notice() { -// if( current_receiver() == N(testapi) ) { -// eosio::require_recipient( N(acc1) ); -// eosio::require_recipient( N(acc2) ); -// eosio::require_recipient( N(acc1), N(acc2) ); -// return WASM_TEST_FAIL; -// } else if ( current_receiver() == N(acc1) || current_receiver() == N(acc2) ) { -// return WASM_TEST_PASS; -// } -// return WASM_TEST_FAIL; -//} -// -//unsigned int test_action::require_auth() { -// eosio::require_auth( N(acc3) ); -// eosio::require_auth( N(acc4) ); -// return WASM_TEST_PASS; -//} +void test_action::require_auth() { + prints("require_auth"); + eosio::require_auth( N(acc3) ); + eosio::require_auth( N(acc4) ); +} void test_action::assert_false() { eosio_assert(false, "test_action::assert_false"); @@ -68,11 +71,33 @@ void test_action::assert_true() { eosio_assert(true, "test_action::assert_true"); } -//unsigned int test_action::now() { -// uint32_t tmp = 0; -// uint32_t total = read_action(&tmp, sizeof(uint32_t)); -// WASM_ASSERT( total == sizeof(uint32_t), "total == sizeof(uint32_t)"); -// WASM_ASSERT( tmp == ::now(), "tmp == now()" ); -// return WASM_TEST_PASS; -//} -// +void test_action::test_abort() { + abort(); + eosio_assert( false, "should've aborted" ); +} + +void test_action::test_publication_time() { + uint32_t pub_time = 0; + read_action(&pub_time, sizeof(uint32_t)); + eosio_assert( pub_time == publication_time(), "pub_time == publication_time()" ); +} + +void test_action::test_current_receiver() { + account_name cur_rec; + read_action(&cur_rec, sizeof(account_name)); + + eosio_assert( current_receiver() == cur_rec, "the current receiver does not match" ); +} + +void test_action::test_current_sender() { + account_name cur_send; + read_action(&cur_send, sizeof(account_name)); + eosio_assert( current_sender() == cur_send, "the current sender does not match" ); +} + +void test_action::now() { + uint32_t tmp = 0; + uint32_t total = read_action(&tmp, sizeof(uint32_t)); + eosio_assert( total == sizeof(uint32_t), "total == sizeof(uint32_t)"); + eosio_assert( tmp == ::now(), "tmp == now()" ); +} diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp index b3b6f98c2aa22ef11663b91e3af845d778924a66..a7d3fc1e00105bc8df546fa80a012dac83b6c6f7 100644 --- a/contracts/test_api/test_api.cpp +++ b/contracts/test_api/test_api.cpp @@ -5,19 +5,17 @@ #include #include "test_api.hpp" -//#include "test_account.cpp" -//#include "test_chain.cpp" -//#include "test_crypto.cpp" -//#include "test_db.cpp" -//#include "test_math.cpp" #include "test_action.cpp" #include "test_print.cpp" -//#include "test_string.cpp" -//#include "test_fixedpoint.cpp" -//#include "test_real.cpp" -//#include "test_transaction.cpp" -//#include "test_types.cpp" -#include "test_db.cpp" +#include "test_types.cpp" +#include "test_fixedpoint.cpp" +#include "test_math.cpp" +#include "test_compiler_builtins.cpp" +#include "test_real.cpp" +#include "test_crypto.cpp" +#include "test_chain.cpp" +#include "test_transaction.cpp" +#include "test_checktime.cpp" extern "C" { @@ -28,141 +26,117 @@ extern "C" { void apply( unsigned long long code, unsigned long long action ) { //eosio::print("==> CONTRACT: ", code, " ", action, "\n"); - //test_types -// WASM_TEST_HANDLER(test_types, types_size); -// WASM_TEST_HANDLER(test_types, char_to_symbol); -// WASM_TEST_HANDLER(test_types, string_to_name); -// WASM_TEST_HANDLER(test_types, name_class); -// -// //test_action + WASM_TEST_HANDLER(test_types, types_size); + WASM_TEST_HANDLER(test_types, char_to_symbol); + WASM_TEST_HANDLER(test_types, string_to_name); + WASM_TEST_HANDLER(test_types, name_class); + + //test_compiler_builtins + WASM_TEST_HANDLER(test_compiler_builtins, test_multi3); + WASM_TEST_HANDLER(test_compiler_builtins, test_divti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_divti3_by_0); + WASM_TEST_HANDLER(test_compiler_builtins, test_udivti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_udivti3_by_0); + WASM_TEST_HANDLER(test_compiler_builtins, test_modti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_modti3_by_0); + WASM_TEST_HANDLER(test_compiler_builtins, test_umodti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_umodti3_by_0); + WASM_TEST_HANDLER(test_compiler_builtins, test_lshlti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_lshrti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_ashlti3); + WASM_TEST_HANDLER(test_compiler_builtins, test_ashrti3); + + //test_action WASM_TEST_HANDLER(test_action, read_action_normal); WASM_TEST_HANDLER(test_action, read_action_to_0); WASM_TEST_HANDLER(test_action, read_action_to_64k); -// WASM_TEST_HANDLER(test_action, require_notice); -// WASM_TEST_HANDLER(test_action, require_auth); + WASM_TEST_HANDLER(test_action, require_notice); + WASM_TEST_HANDLER(test_action, require_auth); WASM_TEST_HANDLER(test_action, assert_false); WASM_TEST_HANDLER(test_action, assert_true); -// WASM_TEST_HANDLER(test_action, now); + WASM_TEST_HANDLER(test_action, now); + WASM_TEST_HANDLER(test_action, test_abort); + WASM_TEST_HANDLER(test_action, test_current_receiver); + WASM_TEST_HANDLER(test_action, test_current_sender); + WASM_TEST_HANDLER(test_action, test_publication_time); //test_print WASM_TEST_HANDLER(test_print, test_prints); + WASM_TEST_HANDLER(test_print, test_prints_l); WASM_TEST_HANDLER(test_print, test_printi); WASM_TEST_HANDLER(test_print, test_printi128); WASM_TEST_HANDLER(test_print, test_printn); -// //test_math -// WASM_TEST_HANDLER(test_math, test_multeq_i128); -// WASM_TEST_HANDLER(test_math, test_diveq_i128); -// WASM_TEST_HANDLER(test_math, test_diveq_i128_by_0); -// WASM_TEST_HANDLER(test_math, test_double_api); -// WASM_TEST_HANDLER(test_math, test_double_api_div_0); -// -// -// //test db -// WASM_TEST_HANDLER(test_db, key_i64_general); -// WASM_TEST_HANDLER(test_db, key_i64_remove_all); -// WASM_TEST_HANDLER(test_db, key_i64_small_load); -// WASM_TEST_HANDLER(test_db, key_i64_small_store); -// WASM_TEST_HANDLER(test_db, key_i64_store_scope); -// WASM_TEST_HANDLER(test_db, key_i64_remove_scope); -// WASM_TEST_HANDLER(test_db, key_i64_not_found); -// WASM_TEST_HANDLER(test_db, key_i64_front_back); -// WASM_TEST_HANDLER(test_db, key_i64i64i64_general); -// WASM_TEST_HANDLER(test_db, key_i128i128_general); -// WASM_TEST_HANDLER(test_db, key_str_general); -// WASM_TEST_HANDLER(test_db, key_str_table); -// WASM_TEST_HANDLER(test_db, key_str_setup_limit); -// WASM_TEST_HANDLER(test_db, key_str_min_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_str_under_limit); -// WASM_TEST_HANDLER(test_db, key_str_available_space_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_str_another_under_limit); -// WASM_TEST_HANDLER(test_db, key_i64_setup_limit); -// WASM_TEST_HANDLER(test_db, key_i64_min_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_i64_under_limit); -// WASM_TEST_HANDLER(test_db, key_i64_available_space_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_i64_another_under_limit); -// WASM_TEST_HANDLER(test_db, key_i128i128_setup_limit); -// WASM_TEST_HANDLER(test_db, key_i128i128_min_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_i128i128_under_limit); -// WASM_TEST_HANDLER(test_db, key_i128i128_available_space_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_i128i128_another_under_limit); -// WASM_TEST_HANDLER(test_db, key_i64i64i64_setup_limit); -// WASM_TEST_HANDLER(test_db, key_i64i64i64_min_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_i64i64i64_under_limit); -// WASM_TEST_HANDLER(test_db, key_i64i64i64_available_space_exceed_limit); -// WASM_TEST_HANDLER(test_db, key_i64i64i64_another_under_limit); - - WASM_TEST_HANDLER(test_db, primary_i64_general); - WASM_TEST_HANDLER(test_db, primary_i64_lowerbound); - WASM_TEST_HANDLER(test_db, primary_i64_upperbound); - WASM_TEST_HANDLER(test_db, idx64_general); - WASM_TEST_HANDLER(test_db, idx64_lowerbound); - WASM_TEST_HANDLER(test_db, idx64_upperbound); - -// //test crypto -// WASM_TEST_HANDLER(test_crypto, test_sha256); -// WASM_TEST_HANDLER(test_crypto, sha256_no_data); -// WASM_TEST_HANDLER(test_crypto, asert_sha256_false); -// WASM_TEST_HANDLER(test_crypto, asert_sha256_true); -// WASM_TEST_HANDLER(test_crypto, asert_no_data); -// -// //test transaction -// WASM_TEST_HANDLER(test_transaction, send_message); -// WASM_TEST_HANDLER(test_transaction, send_message_empty); -// WASM_TEST_HANDLER(test_transaction, send_message_max); -// WASM_TEST_HANDLER(test_transaction, send_message_large); -// WASM_TEST_HANDLER(test_transaction, send_message_recurse); -// WASM_TEST_HANDLER(test_transaction, send_message_inline_fail); -// WASM_TEST_HANDLER(test_transaction, send_transaction); -// WASM_TEST_HANDLER(test_transaction, send_transaction_empty); -// WASM_TEST_HANDLER(test_transaction, send_transaction_max); -// WASM_TEST_HANDLER(test_transaction, send_transaction_large); -// -// //test chain -// WASM_TEST_HANDLER(test_chain, test_activeprods); -// -// // test string -// WASM_TEST_HANDLER(test_string, construct_with_size); -// WASM_TEST_HANDLER(test_string, construct_with_data); -// WASM_TEST_HANDLER(test_string, construct_with_data_copied); -// WASM_TEST_HANDLER(test_string, construct_with_data_partially); -// WASM_TEST_HANDLER(test_string, copy_constructor); -// WASM_TEST_HANDLER(test_string, assignment_operator); -// WASM_TEST_HANDLER(test_string, index_operator); -// WASM_TEST_HANDLER(test_string, index_out_of_bound); -// WASM_TEST_HANDLER(test_string, substring); -// WASM_TEST_HANDLER(test_string, substring_out_of_bound); -// WASM_TEST_HANDLER(test_string, concatenation_null_terminated); -// WASM_TEST_HANDLER(test_string, concatenation_non_null_terminated); -// WASM_TEST_HANDLER(test_string, assign); -// WASM_TEST_HANDLER(test_string, comparison_operator); -// WASM_TEST_HANDLER(test_string, print_null_terminated); -// WASM_TEST_HANDLER(test_string, print_non_null_terminated); -// WASM_TEST_HANDLER(test_string, print_unicode); -// WASM_TEST_HANDLER(test_string, valid_utf8); -// WASM_TEST_HANDLER(test_string, invalid_utf8); -// WASM_TEST_HANDLER(test_string, string_literal); -// -// // test fixed_point -// WASM_TEST_HANDLER(test_fixedpoint, create_instances); -// WASM_TEST_HANDLER(test_fixedpoint, test_addition); -// WASM_TEST_HANDLER(test_fixedpoint, test_subtraction); -// WASM_TEST_HANDLER(test_fixedpoint, test_multiplication); -// WASM_TEST_HANDLER(test_fixedpoint, test_division); -// -// -// // test double -// WASM_TEST_HANDLER(test_real, create_instances); -// WASM_TEST_HANDLER(test_real, test_addition); -// WASM_TEST_HANDLER(test_real, test_multiplication); -// WASM_TEST_HANDLER(test_real, test_division); -// -// // test account -// WASM_TEST_HANDLER(test_account, test_balance_acc1); -// + //test_math + WASM_TEST_HANDLER(test_math, test_multeq); + WASM_TEST_HANDLER(test_math, test_diveq); + WASM_TEST_HANDLER(test_math, test_i64_to_double); + WASM_TEST_HANDLER(test_math, test_double_to_i64); + WASM_TEST_HANDLER(test_math, test_diveq_by_0); + WASM_TEST_HANDLER(test_math, test_double_api); + WASM_TEST_HANDLER(test_math, test_double_api_div_0); + + //test crypto + WASM_TEST_HANDLER(test_crypto, test_recover_key); + WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_true); + WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_false); + WASM_TEST_HANDLER(test_crypto, test_sha1); + WASM_TEST_HANDLER(test_crypto, test_sha256); + WASM_TEST_HANDLER(test_crypto, test_sha512); + WASM_TEST_HANDLER(test_crypto, test_ripemd160); + WASM_TEST_HANDLER(test_crypto, sha1_no_data); + WASM_TEST_HANDLER(test_crypto, sha256_no_data); + WASM_TEST_HANDLER(test_crypto, sha512_no_data); + WASM_TEST_HANDLER(test_crypto, ripemd160_no_data); + WASM_TEST_HANDLER(test_crypto, sha256_null); + WASM_TEST_HANDLER(test_crypto, assert_sha256_false); + WASM_TEST_HANDLER(test_crypto, assert_sha256_true); + WASM_TEST_HANDLER(test_crypto, assert_sha1_false); + WASM_TEST_HANDLER(test_crypto, assert_sha1_true); + WASM_TEST_HANDLER(test_crypto, assert_sha512_false); + WASM_TEST_HANDLER(test_crypto, assert_sha512_true); + WASM_TEST_HANDLER(test_crypto, assert_ripemd160_false); + WASM_TEST_HANDLER(test_crypto, assert_ripemd160_true); + + //test transaction + WASM_TEST_HANDLER(test_transaction, test_tapos_block_num); + WASM_TEST_HANDLER(test_transaction, test_tapos_block_prefix); + WASM_TEST_HANDLER(test_transaction, send_action); + WASM_TEST_HANDLER(test_transaction, send_action_inline_fail); + WASM_TEST_HANDLER(test_transaction, send_action_empty); + WASM_TEST_HANDLER(test_transaction, send_action_large); + WASM_TEST_HANDLER(test_transaction, send_action_recurse); + WASM_TEST_HANDLER(test_transaction, test_read_transaction); + WASM_TEST_HANDLER(test_transaction, test_transaction_size); + WASM_TEST_HANDLER(test_transaction, send_transaction); + WASM_TEST_HANDLER(test_transaction, send_transaction_empty); + WASM_TEST_HANDLER(test_transaction, send_transaction_large); + WASM_TEST_HANDLER(test_transaction, send_action_sender); + + //test chain + WASM_TEST_HANDLER(test_chain, test_activeprods); + + // test fixed_point + WASM_TEST_HANDLER(test_fixedpoint, create_instances); + WASM_TEST_HANDLER(test_fixedpoint, test_addition); + WASM_TEST_HANDLER(test_fixedpoint, test_subtraction); + WASM_TEST_HANDLER(test_fixedpoint, test_multiplication); + WASM_TEST_HANDLER(test_fixedpoint, test_division); + WASM_TEST_HANDLER(test_fixedpoint, test_division_by_0); + + // test double + WASM_TEST_HANDLER(test_real, create_instances); + WASM_TEST_HANDLER(test_real, test_addition); + WASM_TEST_HANDLER(test_real, test_multiplication); + WASM_TEST_HANDLER(test_real, test_division); + WASM_TEST_HANDLER(test_real, test_division_by_0); + + // test checktime + WASM_TEST_HANDLER(test_checktime, checktime_pass); + WASM_TEST_HANDLER(test_checktime, checktime_failure); + //unhandled test call eosio_assert(false, "Unknown Test"); } - } diff --git a/contracts/test_api/test_api.hpp b/contracts/test_api/test_api.hpp index a344a25fb4a4bbb29c88f7c0016ae86243f9ecff..edefdaee1467ca05ecc1d0b3c7c138eb36a044a8 100644 --- a/contracts/test_api/test_api.hpp +++ b/contracts/test_api/test_api.hpp @@ -24,7 +24,7 @@ static constexpr u64 WASM_TEST_ACTION(const char* cls, const char* method) CLASS::METHOD(); \ return; \ } - + #pragma pack(push, 1) struct dummy_action { char a; //1 @@ -32,164 +32,205 @@ struct dummy_action { int c; //4 }; -struct u128_msg { +struct u128_action { unsigned __int128 values[3]; //16*3 }; #pragma pack(pop) static_assert( sizeof(dummy_action) == 13 , "unexpected packing" ); -static_assert( sizeof(u128_msg) == 16*3 , "unexpected packing" ); +static_assert( sizeof(u128_action) == 16*3 , "unexpected packing" ); struct test_types { - static unsigned int types_size(); - static unsigned int char_to_symbol(); - static unsigned int string_to_name(); - static unsigned int name_class(); + static void types_size(); + static void char_to_symbol(); + static void string_to_name(); + static void name_class(); }; struct test_print { static void test_prints(); + static void test_prints_l(); static void test_printi(); static void test_printi128(); static void test_printn(); }; -#define DUMMY_MESSAGE_DEFAULT_A 0x45 -#define DUMMY_MESSAGE_DEFAULT_B 0xab11cd1244556677 -#define DUMMY_MESSAGE_DEFAULT_C 0x7451ae12 +#define DUMMY_ACTION_DEFAULT_A 0x45 +#define DUMMY_ACTION_DEFAULT_B 0xab11cd1244556677 +#define DUMMY_ACTION_DEFAULT_C 0x7451ae12 struct test_action { static void read_action_normal(); static void read_action_to_0(); static void read_action_to_64k(); - static unsigned int require_notice(); - static unsigned int require_auth(); + static void require_notice(); + static void require_auth(); static void assert_false(); static void assert_true(); - static unsigned int now(); - + static void now(); + static void test_abort(); + static void test_current_receiver(); + static void test_current_sender(); + static void test_publication_time(); }; struct test_math { - static unsigned int test_multeq_i128(); - static unsigned int test_diveq_i128(); - static unsigned int test_diveq_i128_by_0(); - static unsigned int test_double_api(); - static unsigned int test_double_api_div_0(); + static void test_multeq(); + static void test_diveq(); + static void test_diveq_by_0(); + static void test_double_api(); + static void test_double_api_div_0(); + static void test_i64_to_double(); + static void test_double_to_i64(); }; struct test_db { - static unsigned int key_i64_general(); - static unsigned int key_i64_remove_all(); - static unsigned int key_i64_small_load(); - static unsigned int key_i64_small_store(); - static unsigned int key_i64_store_scope(); - static unsigned int key_i64_remove_scope(); - static unsigned int key_i64_not_found(); - static unsigned int key_i64_front_back(); - - static unsigned int key_i128i128_general(); - static unsigned int key_i64i64i64_general(); - static unsigned int key_str_general(); - static unsigned int key_str_table(); - - static unsigned int key_str_setup_limit(); - static unsigned int key_str_min_exceed_limit(); - static unsigned int key_str_under_limit(); - static unsigned int key_str_available_space_exceed_limit(); - static unsigned int key_str_another_under_limit(); - - static unsigned int key_i64_setup_limit(); - static unsigned int key_i64_min_exceed_limit(); - static unsigned int key_i64_under_limit(); - static unsigned int key_i64_available_space_exceed_limit(); - static unsigned int key_i64_another_under_limit(); - - static unsigned int key_i128i128_setup_limit(); - static unsigned int key_i128i128_min_exceed_limit(); - static unsigned int key_i128i128_under_limit(); - static unsigned int key_i128i128_available_space_exceed_limit(); - static unsigned int key_i128i128_another_under_limit(); - - static unsigned int key_i64i64i64_setup_limit(); - static unsigned int key_i64i64i64_min_exceed_limit(); - static unsigned int key_i64i64i64_under_limit(); - static unsigned int key_i64i64i64_available_space_exceed_limit(); - static unsigned int key_i64i64i64_another_under_limit(); - + static void key_i64_general(); + static void key_i64_remove_all(); + static void key_i64_small_load(); + static void key_i64_small_store(); + static void key_i64_store_scope(); + static void key_i64_remove_scope(); + static void key_i64_not_found(); + static void key_i64_front_back(); + + static void key_i128i128_general(); + static void key_i64i64i64_general(); + static void key_str_general(); + static void key_str_table(); + + static void key_str_setup_limit(); + static void key_str_min_exceed_limit(); + static void key_str_under_limit(); + static void key_str_available_space_exceed_limit(); + static void key_str_another_under_limit(); + + static void key_i64_setup_limit(); + static void key_i64_min_exceed_limit(); + static void key_i64_under_limit(); + static void key_i64_available_space_exceed_limit(); + static void key_i64_another_under_limit(); + + static void key_i128i128_setup_limit(); + static void key_i128i128_min_exceed_limit(); + static void key_i128i128_under_limit(); + static void key_i128i128_available_space_exceed_limit(); + static void key_i128i128_another_under_limit(); + + static void key_i64i64i64_setup_limit(); + static void key_i64i64i64_min_exceed_limit(); + static void key_i64i64i64_under_limit(); + static void key_i64i64i64_available_space_exceed_limit(); + static void key_i64i64i64_another_under_limit(); + static void primary_i64_general(); static void primary_i64_lowerbound(); static void primary_i64_upperbound(); + static void idx64_general(); static void idx64_lowerbound(); static void idx64_upperbound(); }; struct test_crypto { - static unsigned int test_sha256(); - static unsigned int sha256_no_data(); - static unsigned int asert_sha256_false(); - static unsigned int asert_sha256_true(); - static unsigned int asert_no_data(); + static void test_recover_key(); + static void test_recover_key_assert_true(); + static void test_recover_key_assert_false(); + static void test_sha1(); + static void test_sha256(); + static void test_sha512(); + static void test_ripemd160(); + static void sha1_no_data(); + static void sha256_no_data(); + static void sha512_no_data(); + static void ripemd160_no_data(); + static void sha256_null(); + static void assert_sha256_false(); + static void assert_sha1_false(); + static void assert_sha512_false(); + static void assert_ripemd160_false(); + static void assert_sha256_true(); + static void assert_sha1_true(); + static void assert_sha512_true(); + static void assert_ripemd160_true(); }; struct test_transaction { - - static unsigned int send_message(); - static unsigned int send_message_empty(); - static unsigned int send_message_max(); - static unsigned int send_message_large(); - static unsigned int send_message_recurse(); - static unsigned int send_message_inline_fail(); - static unsigned int send_transaction(); - static unsigned int send_transaction_empty(); - static unsigned int send_transaction_max(); - static unsigned int send_transaction_large(); + static void test_tapos_block_num(); + static void test_tapos_block_prefix(); + static void send_action(); + static void send_action_empty(); + static void send_action_max(); + static void send_action_large(); + static void send_action_recurse(); + static void send_action_inline_fail(); + static void test_read_transaction(); + static void test_transaction_size(); + static void send_transaction(); + static void send_transaction_empty(); + static void send_transaction_max(); + static void send_transaction_large(); + static void send_action_sender(); }; struct test_chain { - static unsigned int test_activeprods(); -}; - -struct test_string { - static unsigned int construct_with_size(); - static unsigned int construct_with_data(); - static unsigned int construct_with_data_copied(); - static unsigned int construct_with_data_partially(); - static unsigned int copy_constructor(); - static unsigned int assignment_operator(); - static unsigned int index_operator(); - static unsigned int index_out_of_bound(); - static unsigned int substring(); - static unsigned int substring_out_of_bound(); - static unsigned int concatenation_null_terminated(); - static unsigned int concatenation_non_null_terminated(); - static unsigned int assign(); - static unsigned int comparison_operator(); - static unsigned int print_null_terminated(); - static unsigned int print_non_null_terminated(); - static unsigned int print_unicode(); - static unsigned int valid_utf8(); - static unsigned int invalid_utf8(); - static unsigned int string_literal(); + static void test_activeprods(); }; struct test_fixedpoint { - static unsigned int create_instances(); - static unsigned int test_addition(); - static unsigned int test_subtraction(); - static unsigned int test_multiplication(); - static unsigned int test_division(); + static void create_instances(); + static void test_addition(); + static void test_subtraction(); + static void test_multiplication(); + static void test_division(); + static void test_division_by_0(); }; struct test_real { - static unsigned int create_instances(); - static unsigned int test_addition(); - static unsigned int test_multiplication(); - static unsigned int test_division(); + static void create_instances(); + static void test_addition(); + static void test_multiplication(); + static void test_division(); + static void test_division_by_0(); +}; + +struct test_compiler_builtins { + static void test_multi3(); + static void test_divti3(); + static void test_divti3_by_0(); + static void test_udivti3(); + static void test_udivti3_by_0(); + static void test_modti3(); + static void test_modti3_by_0(); + static void test_umodti3(); + static void test_umodti3_by_0(); + static void test_lshlti3(); + static void test_lshrti3(); + static void test_ashlti3(); + static void test_ashrti3(); }; -struct test_account { - static unsigned int test_balance_acc1(); +struct test_extended_memory { + static void test_initial_buffer(); + static void test_page_memory(); + static void test_page_memory_exceeded(); + static void test_page_memory_negative_bytes(); }; + +struct test_memory { + static void test_memory_allocs(); + static void test_memory_hunk(); + static void test_memory_hunks(); + static void test_memory_hunks_disjoint(); + static void test_memset_memcpy(); + static void test_memcpy_overlap_start(); + static void test_memcpy_overlap_end(); + static void test_memcmp(); +}; + +struct test_checktime { + static void checktime_pass(); + static void checktime_failure(); +}; + diff --git a/contracts/test_api/test_chain.cpp b/contracts/test_api/test_chain.cpp index 740180187d89fce9e4e9681a849087382529180c..53ee98b499f37f5581f9146971c9d8470e1ce28c 100644 --- a/contracts/test_api/test_chain.cpp +++ b/contracts/test_api/test_chain.cpp @@ -4,7 +4,7 @@ */ #include #include - +#include #include "test_api.hpp" #pragma pack(push, 1) @@ -14,18 +14,15 @@ struct producers { }; #pragma pack(pop) -unsigned int test_chain::test_activeprods() { - producers msg_prods; - read_action(&msg_prods, sizeof(producers)); - - WASM_ASSERT(msg_prods.len == 21, "producers.len != 21"); +void test_chain::test_activeprods() { + producers act_prods; + read_action(&act_prods, sizeof(producers)); + + eosio_assert(act_prods.len == 21, "producers.len != 21"); producers api_prods; get_active_producers(api_prods.producers, sizeof(account_name)*21); - for( int i = 0; i < 21 ; ++i ) { - WASM_ASSERT(api_prods.producers[i] == msg_prods.producers[i], "Active producer"); - } - - return WASM_TEST_PASS; + for( int i = 0; i < 21 ; ++i ) + eosio_assert(api_prods.producers[i] == act_prods.producers[i], "Active producer"); } diff --git a/contracts/test_api/test_checktime.cpp b/contracts/test_api/test_checktime.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c2a4403955bde180d35607d76ce786b3f80524d --- /dev/null +++ b/contracts/test_api/test_checktime.cpp @@ -0,0 +1,25 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include +#include "test_api.hpp" + +void test_checktime::checktime_pass() { + int p = 0; + for ( int i = 0; i < 10000; i++ ) + p += i; + + eosio::print(p); +} + +void test_checktime::checktime_failure() { + int p = 0; + for ( unsigned long long i = 0; i < 10000000000000000000ULL; i++ ) + for ( unsigned long long j = 0; i < 10000000000000000000ULL; i++ ) + p += i+j; + + + eosio::print(p); +} diff --git a/contracts/test_api/test_compiler_builtins.cpp b/contracts/test_api/test_compiler_builtins.cpp new file mode 100644 index 0000000000000000000000000000000000000000..284094adc061cc506db0141f2b17f621f87ee0bb --- /dev/null +++ b/contracts/test_api/test_compiler_builtins.cpp @@ -0,0 +1,397 @@ +/** + * @file test_compiler_builtins.cpp + * @copyright defined in eos/LICENSE.txt + */ + +#include +#include +#include + +#include "test_api.hpp" + +using namespace eosio; +unsigned __int128 operator "" _ULLL( const char* lit ) { + __int128 ret = 0; + size_t i = 0; + bool sign = false; + + if (lit[i] == '-') { + ++i; + sign = true; + } + + if (lit[i] == '+') + ++i; + + for (; lit[i] != '\0' ; ++i) { + const char c = lit[i]; + ret *= 10; + ret += c - '0'; + } + + if (sign) + ret *= -1; + + return ret; +} + +__int128 operator "" _LLL( const char* lit ) { + __int128 ret = 0; + size_t i = 0; + bool sign = false; + + if (lit[i] == '-') { + ++i; + sign = true; + } + + if (lit[i] == '+') + ++i; + + for (; lit[i] != '\0' ; ++i) { + const char c = lit[i]; + ret *= 10; + ret += c - '0'; + } + + if (sign) + ret *= -1; + + return ret; +} + +void test_compiler_builtins::test_multi3() { + /* + * tests for negative values + */ + __int128 res = 0; + __int128 lhs_a = -30; + __int128 rhs_a = 100; + __int128 lhs_b = 100; + __int128 rhs_b = -30; + + __multi3( res, lhs_a, ( lhs_a >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == -3000, "__multi3 result should be -3000" ); + + __multi3( res, lhs_b, ( lhs_b >> 64 ), rhs_b, ( rhs_b >> 64 ) ); + eosio_assert( res == -3000, "__multi3 result should be -3000" ); + + __multi3( res, lhs_a, ( lhs_a >> 64 ), rhs_b, ( rhs_b >> 64 ) ); + eosio_assert( res == 900, "__multi3 result should be 900" ); + + /* + * test for positive values + */ + __multi3( res, lhs_b, ( lhs_b >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 10000, "__multi3 result should be 10000" ); + + /* + * test identity + */ + __multi3( res, 1, 0, rhs_a, rhs_a >> 64 ); + eosio_assert( res == 100, "__multi3 result should be 100" ); + + __multi3( res, 1, 0, rhs_b, rhs_b >> 64 ); + eosio_assert( res == -30, "__multi3 result should be -30" ); +} + +void test_compiler_builtins::test_divti3() { + /* + * test for negative values + */ + __int128 res = 0; + __int128 lhs_a = -30; + __int128 rhs_a = 100; + __int128 lhs_b = 100; + __int128 rhs_b = -30; + + __divti3( res, lhs_a, ( lhs_a >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 0, "__divti3 result should be 0" ); + + __divti3( res, lhs_b, ( lhs_b >> 64 ), rhs_b, ( rhs_b >> 64 ) ); + eosio_assert( res == -3, "__divti3 result should be -3" ); + + __divti3( res, lhs_a, ( lhs_a >> 64 ), rhs_b, ( rhs_b >> 64 ) ); + eosio_assert( res == 1, "__divti3 result should be 1" ); + + /* + * test for positive values + */ + __int128 lhs_c = 3333; + __int128 rhs_c = 3333; + + __divti3( res, lhs_b, ( lhs_b >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 1, "__divti3 result should be 1" ); + + __divti3( res, lhs_b, ( lhs_b >> 64 ), rhs_c, ( rhs_c >> 64 ) ); + eosio_assert( res == 0, "__divti3 result should be 0" ); + + __divti3( res, lhs_c, ( lhs_c >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 33, "__divti3 result should be 33" ); + + /* + * test identity + */ + __divti3( res, lhs_b, ( lhs_b >> 64 ), 1, 0 ); + eosio_assert( res == 100, "__divti3 result should be 100" ); + + __divti3( res, lhs_a, ( lhs_a >> 64 ), 1, 0 ); + eosio_assert( res == -30, "__divti3 result should be -30" ); +} + +void test_compiler_builtins::test_divti3_by_0() { + __int128 res = 0; + + __divti3( res, 100, 0, 0, 0 ); + eosio_assert( false, "Should have eosio_asserted" ); +} + +void test_compiler_builtins::test_udivti3() { + /* + * test for negative values + */ + unsigned __int128 res = 0; + unsigned __int128 lhs_a = -30; + unsigned __int128 rhs_a = 100; + unsigned __int128 lhs_b = 100; + unsigned __int128 rhs_b = -30; + + __udivti3( res, lhs_a, ( lhs_a >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 3402823669209384634633746074317682114_ULLL, "__udivti3 result should be 0" ); + + __udivti3( res, lhs_b, ( lhs_b >> 64 ), rhs_b, ( rhs_b >> 64 ) ); + eosio_assert( res == 0, "__udivti3 result should be 0" ); + + __udivti3( res, lhs_a, ( lhs_a >> 64 ), rhs_b, ( rhs_b >> 64 ) ); + eosio_assert( res == 1, "__udivti3 result should be 1" ); + + /* + * test for positive values + */ + __int128 lhs_c = 3333; + __int128 rhs_c = 3333; + + __udivti3( res, lhs_b, ( lhs_b >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 1, "__divti3 result should be 1" ); + + __udivti3( res, lhs_b, ( lhs_b >> 64 ), rhs_c, ( rhs_c >> 64 ) ); + eosio_assert( res == 0, "__divti3 result should be 0" ); + + __udivti3( res, lhs_c, ( lhs_c >> 64 ), rhs_a, ( rhs_a >> 64 ) ); + eosio_assert( res == 33, "__divti3 result should be 33" ); + + /* + * test identity + */ + __udivti3( res, lhs_b, ( lhs_b >> 64 ), 1, 0 ); + eosio_assert( res == 100, "__divti3 result should be 100" ); + + __udivti3( res, lhs_a, ( lhs_a >> 64 ), 1, 0 ); + eosio_assert( res == -30, "__divti3 result should be -30" ); +} + +void test_compiler_builtins::test_udivti3_by_0() { + unsigned __int128 res = 0; + + __udivti3( res, 100, 0, 0, 0 ); + eosio_assert( false, "Should have eosio_asserted" ); +} + + +void test_compiler_builtins::test_lshlti3() { + __int128 res = 0; + __int128 val = 1; + __int128 test_res = 0; + + test_res = 0x8000000000000000; + test_res <<= 1; + + + __lshlti3( res, val, val >> 64, 0 ); + eosio_assert( res == 1, "__lshlti3 result should be 1" ); + + + __lshlti3( res, val, val >> 64, 1 ); + eosio_assert( res == ( 1 << 1 ), "__lshlti3 result should be 2" ); + + __lshlti3( res, val, ( val >> 64 ), 31 ); + eosio_assert( res == 2147483648_ULLL, "__lshlti3 result should be 2^31" ); + + __lshlti3( res, val, ( val >> 64 ), 63 ); + eosio_assert( res == 9223372036854775808_ULLL, "__lshlti3 result should be 2^63" ); + + __lshlti3( res, val, ( val >> 64 ), 64 ); + eosio_assert( res == test_res, "__lshlti3 result should be 2^64" ); + + __lshlti3( res, val, ( val >> 64 ), 127 ); + test_res <<= 63; + eosio_assert( res == test_res, "__lshlti3 result should be 2^127" ); + + __lshlti3( res, val, ( val >> 64 ), 128 ); + test_res <<= 1; + //should rollover + eosio_assert( res == test_res, "__lshlti3 result should be 2^128" ); +} + +void test_compiler_builtins::test_ashlti3() { + __int128 res = 0; + __int128 val = 1; + __int128 test_res = 0; + + test_res = 0x8000000000000000; + test_res <<= 1; + + __ashlti3( res, val, val >> 64, 0 ); + eosio_assert( res == 1, "__ashlti3 result should be 1" ); + + + __ashlti3( res, val, val >> 64, 1 ); + eosio_assert( res == (1 << 1), "__ashlti3 result should be 2" ); + + __ashlti3( res, val, (val >> 64), 31 ); + eosio_assert( res == 2147483648_ULLL, "__ashlti3 result should be 2^31" ); + + __ashlti3( res, val, (val >> 64), 63 ); + eosio_assert( res == 9223372036854775808_ULLL, "__ashlti3 result should be 2^63" ); + + __ashlti3( res, val, (val >> 64), 64 ); + eosio_assert( res == test_res, "__ashlti3 result should be 2^64" ); + + __ashlti3( res, val, (val >> 64), 127 ); + test_res <<= 63; + eosio_assert( res == test_res, "__ashlti3 result should be 2^127" ); + + __ashlti3( res, val, (val >> 64), 128 ); + test_res <<= 1; + //should rollover + eosio_assert( res == test_res, "__ashlti3 result should be 2^128" ); +} + + +void test_compiler_builtins::test_lshrti3() { + __int128 res = 0; + __int128 val = 0x8000000000000000; + __int128 test_res = 0x8000000000000000; + + val <<= 64; + test_res <<= 64; + + __lshrti3( res, val, (val >> 64), 0 ); + eosio_assert( res == test_res, "__lshrti3 result should be 2^127" ); + + __lshrti3( res, val, (val >> 64), 1 ); + eosio_assert( res == 85070591730234615865843651857942052864_ULLL, "__lshrti3 result should be 2^126" ); + + __lshrti3( res, val, (val >> 64), 63 ); + eosio_assert( res == 18446744073709551616_ULLL, "__lshrti3 result should be 2^64" ); + + __lshrti3( res, val, (val >> 64), 64 ); + eosio_assert( res == 9223372036854775808_ULLL, "__lshrti3 result should be 2^63" ); + + __lshrti3( res, val, (val >> 64), 96 ); + eosio_assert( res == 2147483648_ULLL, "__lshrti3 result should be 2^31" ); + + __lshrti3( res, val, (val >> 64), 127 ); + eosio_assert( res == 0x1, "__lshrti3 result should be 2^0" ); +} + +void test_compiler_builtins::test_ashrti3() { + __int128 res = 0; + __int128 test = 1; + __int128 val = -170141183460469231731687303715884105728_LLL; + + test <<= 127; + + __ashrti3( res, val, (val >> 64), 0 ); + eosio_assert( res == -170141183460469231731687303715884105728_LLL, "__ashrti3 result should be -2^127" ); + + __ashrti3(res, val, (val >> 64), 1 ); + eosio_assert( res == -85070591730234615865843651857942052864_LLL, "__ashrti3 result should be -2^126" ); + + __ashrti3(res, val, (val >> 64), 2 ); + eosio_assert( res == test >> 2, "__ashrti3 result should be -2^125" ); + + __ashrti3( res, val, (val >> 64), 64 ); + eosio_assert( res == test >> 64, "__ashrti3 result should be -2^63" ); + + __ashrti3( res, val, (val >> 64), 95 ); + eosio_assert( res == test >> 95, "__ashrti3 result should be -2^31" ); + + __ashrti3( res, val, (val >> 64), 127 ); + eosio_assert( res == test >> 127, "__ashrti3 result should be -2^0" ); +} + + +void test_compiler_builtins::test_modti3() { + __int128 res = 0; + __int128 lhs_a = -30; + __int128 rhs_a = 100; + __int128 lhs_b = 30; + __int128 rhs_b = -100; + + __modti3( res, lhs_a, lhs_a >> 64, rhs_a, rhs_a >> 64 ); + eosio_assert( res == -30, "__modti3 result should be -30" ); + + __modti3( res, lhs_b, lhs_b >> 64, rhs_b, rhs_b >> 64 ); + eosio_assert( res == 30, "__modti3 result should be 30" ); + + __modti3( res, lhs_a, lhs_a >> 64, rhs_b, rhs_b >> 64 ); + eosio_assert( res == -30, "__modti3 result should be -30" ); + + __modti3( res, rhs_a, rhs_a >> 64, lhs_b, lhs_b >> 64 ); + eosio_assert( res == 10, "__modti3 result should be 10" ); + + __modti3( res, rhs_a, rhs_a >> 64, rhs_b, rhs_b >> 64 ); + eosio_assert( res == 0, "__modti3 result should be 0" ); + + __modti3( res, rhs_a, rhs_a >> 64, rhs_a, rhs_a >> 64 ); + eosio_assert( res == 0, "__modti3 result should be 0" ); + + __modti3( res, 0, 0, rhs_a, rhs_a >> 64 ); + eosio_assert( res == 0, "__modti3 result should be 0" ); +} + +void test_compiler_builtins::test_modti3_by_0() { + __int128 res = 0; + __int128 lhs = 100; + + __modti3( res, lhs, lhs >> 64, 0, 0 ); + eosio_assert( false, "should have thrown an error" ); +} + +void test_compiler_builtins::test_umodti3() { + unsigned __int128 res = 0; + unsigned __int128 lhs_a = -30; + unsigned __int128 rhs_a = 100; + unsigned __int128 lhs_b = 30; + unsigned __int128 rhs_b = -100; + + __umodti3( res, lhs_a, lhs_a >> 64, rhs_a, rhs_a >> 64 ); + eosio_assert( res == -30, "__modti3 result should be -30" ); + + __umodti3( res, lhs_b, lhs_b >> 64, rhs_b, rhs_b >> 64 ); + eosio_assert( res == 30, "__modti3 result should be 30" ); + + __umodti3( res, lhs_a, lhs_a >> 64, rhs_b, rhs_b >> 64 ); + eosio_assert( res == -30, "__modti3 result should be -30" ); + + __umodti3( res, rhs_a, rhs_a >> 64, lhs_b, lhs_b >> 64 ); + eosio_assert( res == 10, "__modti3 result should be 10" ); + + __umodti3( res, rhs_a, rhs_a >> 64, rhs_b, rhs_b >> 64 ); + eosio_assert( res == 0, "__modti3 result should be 0" ); + + __umodti3( res, rhs_a, rhs_a >> 64, rhs_a, rhs_a >> 64 ); + eosio_assert( res == 0, "__modti3 result should be 0" ); + + __umodti3( res, 0, 0, rhs_a, rhs_a >> 64 ); + eosio_assert( res == 0, "__modti3 result should be 0" ); +} + +void test_compiler_builtins::test_umodti3_by_0() { + unsigned __int128 res = 0; + unsigned __int128 lhs = 100; + + __umodti3( res, lhs, lhs >> 64, 0, 0 ); + eosio_assert( false, "should have thrown an error" ); +} diff --git a/contracts/test_api/test_crypto.cpp b/contracts/test_api/test_crypto.cpp index 04e7eff078e5cdd06d7105ef6e4e0cfb24fe5911..ce703a0d63958bf3a213c6c4d1f90e6982f4bab7 100644 --- a/contracts/test_api/test_crypto.cpp +++ b/contracts/test_api/test_crypto.cpp @@ -2,51 +2,168 @@ * @file * @copyright defined in eos/LICENSE.txt */ -#include +#include #include +#include #include "test_api.hpp" +#define WASM_TEST_FAIL 1 static const char test1[] = "abc"; -static const unsigned char test1_ok[] = { +static const unsigned char test1_ok_1[] = { + 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, + 0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, + 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d +}; + +static const unsigned char test1_ok_256[] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }; +static const unsigned char test1_ok_512[] = { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f +}; + +static const unsigned char test1_ok_ripe[] = { + 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, + 0x9b, 0x04, 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, + 0xf1, 0x5a, 0x0b, 0xfc +}; + const char test2[] = ""; -const unsigned char test2_ok[] = { +static const unsigned char test2_ok_1[] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, + 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, + 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 +}; + +const unsigned char test2_ok_256[] = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }; +const unsigned char test2_ok_512[] = { + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e +}; + +const unsigned char test2_ok_ripe[] = { + 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, + 0x61, 0x28, 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, + 0xb2, 0x25, 0x8d, 0x31 +}; + static const char test3[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; -static const unsigned char test3_ok[] = { +static const unsigned char test3_ok_1[] = { + 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, + 0x6e, 0xba, 0xae, 0x4a, 0xa1, 0xf9, 0x51, + 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 +}; + +static const unsigned char test3_ok_256[] = { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }; +static const unsigned char test3_ok_512[] = { + 0x20, 0x4a, 0x8f, 0xc6, 0xdd, 0xa8, 0x2f, 0x0a, + 0x0c, 0xed, 0x7b, 0xeb, 0x8e, 0x08, 0xa4, 0x16, + 0x57, 0xc1, 0x6e, 0xf4, 0x68, 0xb2, 0x28, 0xa8, + 0x27, 0x9b, 0xe3, 0x31, 0xa7, 0x03, 0xc3, 0x35, + 0x96, 0xfd, 0x15, 0xc1, 0x3b, 0x1b, 0x07, 0xf9, + 0xaa, 0x1d, 0x3b, 0xea, 0x57, 0x78, 0x9c, 0xa0, + 0x31, 0xad, 0x85, 0xc7, 0xa7, 0x1d, 0xd7, 0x03, + 0x54, 0xec, 0x63, 0x12, 0x38, 0xca, 0x34, 0x45 +}; + +static const unsigned char test3_ok_ripe[] = { + 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, + 0xe4, 0x05, 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, + 0xda, 0x62, 0xeb, 0x2b +}; + static const char test4[] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; -static const unsigned char test4_ok[] = { +static const unsigned char test4_ok_1[] = { + 0xa4, 0x9b, 0x24, 0x46, 0xa0, 0x2c, 0x64, + 0x5b, 0xf4, 0x19, 0xf9, 0x95, 0xb6, 0x70, + 0x91, 0x25, 0x3a, 0x04, 0xa2, 0x59 +}; + +static const unsigned char test4_ok_256[] = { 0xcf, 0x5b, 0x16, 0xa7, 0x78, 0xaf, 0x83, 0x80, 0x03, 0x6c, 0xe5, 0x9e, 0x7b, 0x04, 0x92, 0x37, 0x0b, 0x24, 0x9b, 0x11, 0xe8, 0xf0, 0x7a, 0x51, 0xaf, 0xac, 0x45, 0x03, 0x7a, 0xfe, 0xe9, 0xd1 }; +static const unsigned char test4_ok_512[] = { + 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 +}; + +static const unsigned char test4_ok_ripe[] = { + 0x6f, 0x3f, 0xa3, 0x9b, 0x6b, 0x50, 0x3c, 0x38, + 0x4f, 0x91, 0x9a, 0x49, 0xa7, 0xaa, 0x5c, 0x2c, + 0x08, 0xbd, 0xfb, 0x45 +}; + static const char test5[] = "message digest"; -static const unsigned char test5_ok[] = { +static const unsigned char test5_ok_1[] = { + 0xc1, 0x22, 0x52, 0xce, 0xda, 0x8b, 0xe8, + 0x99, 0x4d, 0x5f, 0xa0, 0x29, 0x0a, 0x47, + 0x23, 0x1c, 0x1d, 0x16, 0xaa, 0xe3 +}; + +static const unsigned char test5_ok_256[] = { 0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50 }; +static const unsigned char test5_ok_512[] = { + 0x10, 0x7d, 0xbf, 0x38, 0x9d, 0x9e, 0x9f, 0x71, + 0xa3, 0xa9, 0x5f, 0x6c, 0x05, 0x5b, 0x92, 0x51, + 0xbc, 0x52, 0x68, 0xc2, 0xbe, 0x16, 0xd6, 0xc1, + 0x34, 0x92, 0xea, 0x45, 0xb0, 0x19, 0x9f, 0x33, + 0x09, 0xe1, 0x64, 0x55, 0xab, 0x1e, 0x96, 0x11, + 0x8e, 0x8a, 0x90, 0x5d, 0x55, 0x97, 0xb7, 0x20, + 0x38, 0xdd, 0xb3, 0x72, 0xa8, 0x98, 0x26, 0x04, + 0x6d, 0xe6, 0x66, 0x87, 0xbb, 0x42, 0x0e, 0x7c +}; + +static const unsigned char test5_ok_ripe[] = { + 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, + 0x72, 0xb8, 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, + 0x21, 0x59, 0x5f, 0x36 +}; + extern "C" { uint32_t my_strlen(const char *str) { uint32_t len = 0; @@ -68,49 +185,158 @@ extern "C" { } -unsigned int test_crypto::test_sha256() { +struct sig_hash_key { + checksum256 hash; + public_key pk; + signature sig; +}; + +void test_crypto::test_recover_key_assert_true() { + sig_hash_key sh; + int read = read_action( (char*)&sh, sizeof(sh) ); + public_key public_key; + assert_recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), (const char*)&sh.pk, sizeof(sh.pk) ); +} + +void test_crypto::test_recover_key_assert_false() { + sig_hash_key sh; + int read = read_action( (char*)&sh, sizeof(sh) ); + assert_recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), (const char*)&sh.pk, sizeof(sh.pk) ); + eosio_assert( false, "should have thrown an error" ); +} + +void test_crypto::test_recover_key() { + sig_hash_key sh; + int read = read_action( (char*)&sh, sizeof(sh) ); + public_key pk; + int recovered = recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), pk.data, sizeof(pk) ); + for ( int i=0; i < sizeof(pk); i++ ) + if ( pk.data[i] != sh.pk.data[i] ) + eosio_assert( false, "public key does not match" ); +} + +void test_crypto::test_sha1() { + checksum160 tmp; - checksum tmp; + sha1( (char *)test1, my_strlen(test1), &tmp ); + eosio_assert( my_memcmp((void *)test1_ok_1, &tmp, sizeof(checksum160)), "sha1 test1" ); + + sha1( (char *)test3, my_strlen(test3), &tmp ); + eosio_assert( my_memcmp((void *)test3_ok_1, &tmp, sizeof(checksum160)), "sha1 test3" ); + + sha1( (char *)test4, my_strlen(test4), &tmp ); + eosio_assert( my_memcmp((void *)test4_ok_1, &tmp, sizeof(checksum160)), "sha1 test4" ); + + sha1( (char *)test5, my_strlen(test5), &tmp ); + eosio_assert( my_memcmp((void *)test5_ok_1, &tmp, sizeof(checksum160)), "sha1 test5" ); +} + +void test_crypto::test_sha256() { + + checksum256 tmp; sha256( (char *)test1, my_strlen(test1), &tmp ); - WASM_ASSERT( my_memcmp((void *)test1_ok, &tmp, sizeof(checksum)), "sha256 test1" ); + eosio_assert( my_memcmp((void *)test1_ok_256, &tmp, sizeof(checksum256)), "sha256 test1" ); sha256( (char *)test3, my_strlen(test3), &tmp ); - WASM_ASSERT( my_memcmp((void *)test3_ok, &tmp, sizeof(checksum)), "sha256 test3" ); + eosio_assert( my_memcmp((void *)test3_ok_256, &tmp, sizeof(checksum256)), "sha256 test3" ); sha256( (char *)test4, my_strlen(test4), &tmp ); - WASM_ASSERT( my_memcmp((void *)test4_ok, &tmp, sizeof(checksum)), "sha256 test4" ); + eosio_assert( my_memcmp((void *)test4_ok_256, &tmp, sizeof(checksum256)), "sha256 test4" ); sha256( (char *)test5, my_strlen(test5), &tmp ); - WASM_ASSERT( my_memcmp((void *)test5_ok, &tmp, sizeof(checksum)), "sha256 test5" ); + eosio_assert( my_memcmp((void *)test5_ok_256, &tmp, sizeof(checksum256)), "sha256 test5" ); +} + +void test_crypto::test_sha512() { + + checksum512 tmp; + + sha512( (char *)test1, my_strlen(test1), &tmp ); + eosio_assert( my_memcmp((void *)test1_ok_512, &tmp, sizeof(checksum512)), "sha512 test1" ); - return WASM_TEST_PASS; + sha512( (char *)test3, my_strlen(test3), &tmp ); + eosio_assert( my_memcmp((void *)test3_ok_512, &tmp, sizeof(checksum512)), "sha512 test3" ); + + sha512( (char *)test4, my_strlen(test4), &tmp ); + eosio_assert( my_memcmp((void *)test4_ok_512, &tmp, sizeof(checksum512)), "sha512 test4" ); + + sha512( (char *)test5, my_strlen(test5), &tmp ); + eosio_assert( my_memcmp((void *)test5_ok_512, &tmp, sizeof(checksum512)), "sha512 test5" ); } -unsigned int test_crypto::sha256_no_data() { +void test_crypto::test_ripemd160() { + + checksum160 tmp; - checksum tmp; + ripemd160( (char *)test1, my_strlen(test1), &tmp ); + eosio_assert( my_memcmp((void *)test1_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test1" ); + + ripemd160( (char *)test3, my_strlen(test3), &tmp ); + eosio_assert( my_memcmp((void *)test3_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test3" ); + + ripemd160( (char *)test4, my_strlen(test4), &tmp ); + eosio_assert( my_memcmp((void *)test4_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test4" ); + + ripemd160( (char *)test5, my_strlen(test5), &tmp ); + eosio_assert( my_memcmp((void *)test5_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test5" ); +} + +void test_crypto::sha256_null() { + checksum256 tmp; + int a = 3; + int* b = &a; + sha256(nullptr, 100, &tmp); + //eosio_assert(false, "should've thrown an error"); +} + +void test_crypto::sha1_no_data() { + + checksum160 tmp; + + sha1( (char *)test2, my_strlen(test2), &tmp ); + eosio_assert( my_memcmp((void *)test2_ok_1, &tmp, sizeof(checksum160)), "sha1 test2" ); +} + +void test_crypto::sha256_no_data() { + + checksum256 tmp; sha256( (char *)test2, my_strlen(test2), &tmp ); - WASM_ASSERT( my_memcmp((void *)test2_ok, &tmp, sizeof(checksum)), "sha256 test2" ); + eosio_assert( my_memcmp((void *)test2_ok_256, &tmp, sizeof(checksum256)), "sha256 test2" ); +} + +void test_crypto::sha512_no_data() { - return WASM_TEST_PASS; + checksum512 tmp; + + sha512( (char *)test2, my_strlen(test2), &tmp ); + eosio_assert( my_memcmp((void *)test2_ok_512, &tmp, sizeof(checksum512)), "sha512 test2" ); } -unsigned int test_crypto::asert_sha256_false() { +void test_crypto::ripemd160_no_data() { + + checksum160 tmp; + + ripemd160( (char *)test2, my_strlen(test2), &tmp ); + eosio_assert( my_memcmp((void *)test2_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test2" ); +} + + +void test_crypto::assert_sha256_false() { - checksum tmp; + checksum256 tmp; sha256( (char *)test1, my_strlen(test1), &tmp ); tmp.hash[0] ^= (uint64_t)(-1); assert_sha256( (char *)test1, my_strlen(test1), &tmp); - - return WASM_TEST_FAIL; + + eosio_assert(false, "should have failed"); } -unsigned int test_crypto::asert_sha256_true() { +void test_crypto::assert_sha256_true() { - checksum tmp; + checksum256 tmp; sha256( (char *)test1, my_strlen(test1), &tmp ); assert_sha256( (char *)test1, my_strlen(test1), &tmp); @@ -123,14 +349,91 @@ unsigned int test_crypto::asert_sha256_true() { sha256( (char *)test5, my_strlen(test5), &tmp ); assert_sha256( (char *)test5, my_strlen(test5), &tmp); +} + +void test_crypto::assert_sha1_false() { + + checksum160 tmp; - return WASM_TEST_PASS; + sha1( (char *)test1, my_strlen(test1), &tmp ); + tmp.hash[0] ^= (uint64_t)(-1); + assert_sha1( (char *)test1, my_strlen(test1), &tmp); + + eosio_assert(false, "should have failed"); } -unsigned int test_crypto::asert_no_data() { + +void test_crypto::assert_sha1_true() { - checksum *tmp = (checksum*)test2_ok; - assert_sha256( (char *)test2, my_strlen(test2), tmp); + checksum160 tmp; + + sha1( (char *)test1, my_strlen(test1), &tmp ); + assert_sha1( (char *)test1, my_strlen(test1), &tmp); - return WASM_TEST_FAIL; -} \ No newline at end of file + sha1( (char *)test3, my_strlen(test3), &tmp ); + assert_sha1( (char *)test3, my_strlen(test3), &tmp); + + sha1( (char *)test4, my_strlen(test4), &tmp ); + assert_sha1( (char *)test4, my_strlen(test4), &tmp); + + sha1( (char *)test5, my_strlen(test5), &tmp ); + assert_sha1( (char *)test5, my_strlen(test5), &tmp); +} + +void test_crypto::assert_sha512_false() { + + checksum512 tmp; + + sha512( (char *)test1, my_strlen(test1), &tmp ); + tmp.hash[0] ^= (uint64_t)(-1); + assert_sha512( (char *)test1, my_strlen(test1), &tmp); + + eosio_assert(false, "should have failed"); +} + + +void test_crypto::assert_sha512_true() { + + checksum512 tmp; + + sha512( (char *)test1, my_strlen(test1), &tmp ); + assert_sha512( (char *)test1, my_strlen(test1), &tmp); + + sha512( (char *)test3, my_strlen(test3), &tmp ); + assert_sha512( (char *)test3, my_strlen(test3), &tmp); + + sha512( (char *)test4, my_strlen(test4), &tmp ); + assert_sha512( (char *)test4, my_strlen(test4), &tmp); + + sha512( (char *)test5, my_strlen(test5), &tmp ); + assert_sha512( (char *)test5, my_strlen(test5), &tmp); +} + +void test_crypto::assert_ripemd160_false() { + + checksum160 tmp; + + ripemd160( (char *)test1, my_strlen(test1), &tmp ); + tmp.hash[0] ^= (uint64_t)(-1); + assert_ripemd160( (char *)test1, my_strlen(test1), &tmp); + + eosio_assert(false, "should have failed"); +} + + +void test_crypto::assert_ripemd160_true() { + + checksum160 tmp; + + ripemd160( (char *)test1, my_strlen(test1), &tmp ); + assert_ripemd160( (char *)test1, my_strlen(test1), &tmp); + + ripemd160( (char *)test3, my_strlen(test3), &tmp ); + assert_ripemd160( (char *)test3, my_strlen(test3), &tmp); + + ripemd160( (char *)test4, my_strlen(test4), &tmp ); + assert_ripemd160( (char *)test4, my_strlen(test4), &tmp); + + ripemd160( (char *)test5, my_strlen(test5), &tmp ); + assert_ripemd160( (char *)test5, my_strlen(test5), &tmp); +} diff --git a/contracts/test_api/test_fixedpoint.cpp b/contracts/test_api/test_fixedpoint.cpp index 2a9fe61a5aa68b1a3f12a19a45e81e2a0bc596f5..0a0f163b537cc413d8eb9a991a07d603764caf3c 100644 --- a/contracts/test_api/test_fixedpoint.cpp +++ b/contracts/test_api/test_fixedpoint.cpp @@ -1,17 +1,17 @@ #include -#include +#include #include "test_api.hpp" using namespace eosio; -unsigned int test_fixedpoint::create_instances() +void test_fixedpoint::create_instances() { { // Various ways to create fixed_point128 fixed_point128<18> a(12345667); fixed_point128<18> b(12345667); fixed_point128<16> c(12345667); - WASM_ASSERT(b == a, "fixed_point128 instances comparison with same number of decimals"); - WASM_ASSERT(c == a, "fixed_point128 instances with different number of decimals"); + eosio_assert(b == a, "fixed_point128 instances comparison with same number of decimals"); + eosio_assert(c == a, "fixed_point128 instances with different number of decimals"); } { @@ -19,8 +19,8 @@ unsigned int test_fixedpoint::create_instances() fixed_point64<5> a(12345667); fixed_point64<5> b(12345667); fixed_point64<5> c(12345667); - WASM_ASSERT(b == a, "fixed_point64 instances comparison with same number of decimals"); - WASM_ASSERT(c == a, "fixed_point64 instances with different number of decimals"); + eosio_assert(b == a, "fixed_point64 instances comparison with same number of decimals"); + eosio_assert(c == a, "fixed_point64 instances with different number of decimals"); } { @@ -28,15 +28,12 @@ unsigned int test_fixedpoint::create_instances() fixed_point32<18> a(12345667); fixed_point32<18> b(12345667); fixed_point32<16> c(12345667); - WASM_ASSERT(b == a, "fixed_point32 instances comparison with same number of decimals"); - WASM_ASSERT(c == a, "fixed_point32 instances with different number of decimals"); + eosio_assert(b == a, "fixed_point32 instances comparison with same number of decimals"); + eosio_assert(c == a, "fixed_point32 instances with different number of decimals"); } - - - return WASM_TEST_PASS; } -unsigned int test_fixedpoint::test_addition() +void test_fixedpoint::test_addition() { { // Various ways to create fixed_point32 @@ -44,7 +41,7 @@ unsigned int test_fixedpoint::test_addition() fixed_point32<0> b(100); fixed_point32<0> c = a + b; fixed_point32<0> d = 200; - WASM_ASSERT(c == d, "fixed_point32 instances addition with zero decmimals"); + eosio_assert(c == d, "fixed_point32 instances addition with zero decmimals"); } { // Various ways to create fixed_point64 @@ -52,13 +49,11 @@ unsigned int test_fixedpoint::test_addition() fixed_point64<0> b(100); fixed_point64<0> c = a + b; fixed_point64<0> d = 200; - WASM_ASSERT(c == d, "fixed_point64 instances addition with zero decmimals"); + eosio_assert(c == d, "fixed_point64 instances addition with zero decmimals"); } - - return WASM_TEST_PASS; }; -unsigned int test_fixedpoint::test_subtraction() +void test_fixedpoint::test_subtraction() { { // Various ways to create fixed_point64 @@ -66,7 +61,12 @@ unsigned int test_fixedpoint::test_subtraction() fixed_point64<0> b(100); fixed_point64<0> c = a - b; fixed_point64<0> d = 0; - WASM_ASSERT(c == d, "fixed_point64 instances subtraction with zero decmimals"); + eosio_assert(c == d, "fixed_point64 instances subtraction with zero decmimals"); + + fixed_point64<0> a1(0); + fixed_point64<0> c1 = a1 - b; + fixed_point64<0> d1 = -100; + eosio_assert(c1 == d1, "fixed_point64 instances subtraction with zero decmimals"); } { // Various ways to create fixed_point32 @@ -74,13 +74,18 @@ unsigned int test_fixedpoint::test_subtraction() fixed_point32<0> b(100); fixed_point32<0> c = a - b; fixed_point32<0> d = 0; - WASM_ASSERT(c == d, "fixed_point32 instances subtraction with zero decmimals"); - } + eosio_assert(c == d, "fixed_point32 instances subtraction with zero decmimals"); - return WASM_TEST_PASS; + // Various ways to create fixed_point32 + fixed_point32<0> a1(0); + fixed_point32<0> c1 = a1 - b; + fixed_point32<0> d1 = -100; + eosio_assert(c1 == d1, "fixed_point32 instances subtraction with zero decmimals"); + + } }; -unsigned int test_fixedpoint::test_multiplication() +void test_fixedpoint::test_multiplication() { { // Various ways to create fixed_point64 @@ -88,7 +93,7 @@ unsigned int test_fixedpoint::test_multiplication() fixed_point64<0> b(200); fixed_point128<0> c = a * b; fixed_point128<0> d(200*100); - WASM_ASSERT(c == d, "fixed_point64 instances multiplication result in fixed_point128"); + eosio_assert(c == d, "fixed_point64 instances multiplication result in fixed_point128"); } { @@ -97,13 +102,11 @@ unsigned int test_fixedpoint::test_multiplication() fixed_point32<0> b(200); fixed_point64<0> c = a * b; fixed_point64<0> d(200*100); - WASM_ASSERT(c == d, "fixed_point32 instances multiplication result in fixed_point64"); + eosio_assert(c == d, "fixed_point32 instances multiplication result in fixed_point64"); } - return WASM_TEST_PASS; - } -unsigned int test_fixedpoint::test_division() +void test_fixedpoint::test_division() { { uint64_t lhs = 10000000; @@ -114,7 +117,8 @@ unsigned int test_fixedpoint::test_division() fixed_point128<5> c = a / b; fixed_point128<5> e = fixed_divide<5>(lhs, rhs); - WASM_ASSERT(c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128"); + print(e); + eosio_assert(c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128"); } @@ -127,11 +131,23 @@ unsigned int test_fixedpoint::test_division() fixed_point64<5> c = a / b; fixed_point64<5> e = fixed_divide<5>(lhs, rhs); - WASM_ASSERT(c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128"); + eosio_assert(c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128"); } - return WASM_TEST_PASS; - } +void test_fixedpoint::test_division_by_0() +{ + { + uint64_t lhs = 10000000; + uint64_t rhs = 0; + + fixed_point64<0> a(lhs); + fixed_point64<0> b(rhs); + + fixed_point128<5> e = fixed_divide<5>(lhs, rhs); + eosio_assert(false, "should've thrown an error"); + + } + } diff --git a/contracts/test_api/test_math.cpp b/contracts/test_api/test_math.cpp index 8b6c2793c91dd7c9e72a78845a8f2f72a9380fbc..f080474b4343407921ce038c67277807a991a928 100644 --- a/contracts/test_api/test_math.cpp +++ b/contracts/test_api/test_math.cpp @@ -4,71 +4,116 @@ #include "test_api.hpp" -unsigned int test_math::test_multeq_i128() { - u128_msg msg; - auto n = read_action(&msg, sizeof(u128_msg)); - WASM_ASSERT( n == sizeof(u128_msg), "test_multeq_i128 n == sizeof(u128_msg)" ); - multeq_i128(msg.values, msg.values+1); - WASM_ASSERT( msg.values[0] == msg.values[2], "test_multeq_i128 msg.values[0] == msg.values[2]" ); - return WASM_TEST_PASS; +using namespace eosio; + +void test_math::test_multeq() { + u128_action act; + auto n = read_action(&act, sizeof(u128_action)); + eosio_assert( n == sizeof(u128_action), "test_multeq n == sizeof(u128_action)" ); + + uint128_t self = *(act.values); + uint128_t other = *(act.values+1); + eosio::multeq(self, other); + eosio_assert( self == act.values[2], "test_multeq act.values[0] == act.values[2]" ); } -unsigned int test_math::test_diveq_i128() { - u128_msg msg; - auto n = read_action(&msg, sizeof(u128_msg)); - WASM_ASSERT( n == sizeof(u128_msg), "test_diveq_i128 n == sizeof(u128_msg)" ); - diveq_i128(msg.values, msg.values+1); - WASM_ASSERT( msg.values[0] == msg.values[2], "test_diveq_i128 msg.values[0] == msg.values[2]" ); - return WASM_TEST_PASS; +void test_math::test_diveq() { + u128_action act; + auto n = read_action(&act, sizeof(u128_action)); + eosio_assert( n == sizeof(u128_action), "test_diveq n == sizeof(u128_action)" ); + + uint128_t self = *(act.values); + uint128_t other = *(act.values+1); + + eosio::diveq(self, other); + eosio_assert( self == act.values[2], "test_diveq act.values[0] == act.values[2]" ); } -unsigned int test_math::test_diveq_i128_by_0() { +void test_math::test_diveq_by_0() { unsigned __int128 a = 100; unsigned __int128 b = 0; - diveq_i128(&a, &b); - return WASM_TEST_PASS; + eosio::diveq(a, b); } + + +void test_math::test_i64_to_double() +{ + uint64_t i[4]; + read_action(&i, sizeof(i)); -unsigned int test_math::test_double_api() { + uint64_t d = i64_to_double(2); + eosio_assert(i[0] == d, "test_i64_to_double i[0] == d"); + + d = i64_to_double(-2); + eosio_assert(i[1] == d, "test_i64_to_double i[1] == d"); + + d = i64_to_double(100000); + eosio_assert(i[2] == d, "test_i64_to_double i[2] == d"); + + d = i64_to_double(-100000); + eosio_assert(i[3] == d, "test_i64_to_double i[3] == d"); + + d = i64_to_double(0); + eosio_assert(0 == d, "test_i64_to_double 0 == d"); +} + +void test_math::test_double_to_i64() +{ + uint64_t d[4]; + read_action(&d, sizeof(d)); + + int64_t i = double_to_i64(d[0]); + eosio_assert(2 == i, "test_double_to_i64 2 == i"); + + i = double_to_i64(d[1]); + eosio_assert(-2 == i, "test_double_to_i64 -2 == i"); + + i = double_to_i64(d[2]); + eosio_assert(100000 == i, "test_double_to_i64 100000 == i"); + + i = double_to_i64(d[3]); + eosio_assert(-100000 == i, "test_double_to_i64 -100000 == i"); + + i = double_to_i64(0); + eosio_assert(0 == i, "test_double_to_i64 0 == i"); +} + +void test_math::test_double_api() { uint64_t res = double_mult( double_div( i64_to_double(2), i64_to_double(7) ), double_add( i64_to_double(3), i64_to_double(2) ) ); - WASM_ASSERT( double_to_i64(res) == 1, "double funcs"); + eosio_assert( double_to_i64(res) == 1, "double funcs"); res = double_eq( double_div( i64_to_double(5), i64_to_double(9) ), double_div( i64_to_double(5), i64_to_double(9) ) ); - WASM_ASSERT(res == 1, "double_eq"); + eosio_assert(res == 1, "double_eq"); res = double_gt( double_div( i64_to_double(9999999), i64_to_double(7777777) ), double_div( i64_to_double(9999998), i64_to_double(7777777) ) ); - WASM_ASSERT(res == 1, "double_gt"); + eosio_assert(res == 1, "double_gt"); res = double_lt( double_div( i64_to_double(9999998), i64_to_double(7777777) ), double_div( i64_to_double(9999999), i64_to_double(7777777) ) ); - WASM_ASSERT(res == 1, "double_lt"); - - return WASM_TEST_PASS; + eosio_assert(res == 1, "double_lt"); } -unsigned int test_math::test_double_api_div_0() { - - double_div( i64_to_double(1), - double_add( +void test_math::test_double_api_div_0() { + double_div( i64_to_double(1), + double_add( i64_to_double(-5), i64_to_double(5) - ) - ); + )); - return WASM_TEST_PASS; + eosio_assert(false, "should've thrown an error"); } diff --git a/contracts/test_api/test_print.cpp b/contracts/test_api/test_print.cpp index b1e151671d608af5a0eb01057a3b3d087c22bc2b..fe2ba04771632f6421a63c948a7d64ef5a7ee3c0 100644 --- a/contracts/test_api/test_print.cpp +++ b/contracts/test_api/test_print.cpp @@ -5,6 +5,16 @@ #include #include "test_api.hpp" +using namespace eosio; + +void test_print::test_prints_l() { + char ab[] = { 'a', 'b' }; + const char test[] = "test"; + prints_l(ab, 2); + prints_l(ab, 1); + prints_l(ab, 0); + prints_l(test, sizeof(test)-1); +} void test_print::test_prints() { prints("ab"); diff --git a/contracts/test_api/test_real.cpp b/contracts/test_api/test_real.cpp index 8a8d7ae5ace868849c4c8c7140745a64acff09c6..a2a1bed4724d0ad64a256881a60b5ee9c65b19ae 100644 --- a/contracts/test_api/test_real.cpp +++ b/contracts/test_api/test_real.cpp @@ -1,34 +1,39 @@ #include -#include +#include #include "test_api.hpp" using namespace eosio; -unsigned int test_real::create_instances() { +void test_real::create_instances() { real lhs1(5); - WASM_ASSERT(lhs1.value() == 5, "real instance value is wrong"); - return WASM_TEST_PASS; + eosio_assert(lhs1.value() == 5, "real instance value is wrong"); } -unsigned int test_real::test_division() { +void test_real::test_division() { real lhs1(5); real rhs1(10); real result1 = lhs1 / rhs1; uint64_t a = double_div(i64_to_double(5), i64_to_double(10)); - WASM_ASSERT(a == result1.value(), "real division result is wrong"); - return WASM_TEST_PASS; + eosio_assert(a == result1.value(), "real division result is wrong"); } -unsigned int test_real::test_multiplication() { +void test_real::test_division_by_0() { + real lhs1(5); + real rhs1(0); + real result1 = lhs1 / rhs1; + + eosio_assert(false, "should've thrown an error"); +} + +void test_real::test_multiplication() { real lhs1(5); real rhs1(10); real result1 = lhs1 * rhs1; uint64_t res = double_mult( 5, 10 ); - WASM_ASSERT(res == result1.value(), "real multiplication result is wrong"); - return WASM_TEST_PASS; + eosio_assert(res == result1.value(), "real multiplication result is wrong"); } -unsigned int test_real::test_addition() +void test_real::test_addition() { real lhs1(5); real rhs1(10); @@ -43,9 +48,7 @@ unsigned int test_real::test_addition() real sum = result1+result2; uint64_t c = double_add( a, b ); - WASM_ASSERT(sum.value() == c, "real addition operation result is wrong"); - - return WASM_TEST_PASS; + eosio_assert(sum.value() == c, "real addition operation result is wrong"); } diff --git a/contracts/test_api/test_string.cpp b/contracts/test_api/test_string.cpp deleted file mode 100644 index 7399bbcd3f3ffa592cedb15518f670c5ce0f7920..0000000000000000000000000000000000000000 --- a/contracts/test_api/test_string.cpp +++ /dev/null @@ -1,387 +0,0 @@ -#include -#include - -#include "test_api.hpp" - -unsigned int test_string::construct_with_size() { - - size_t size1 = 100; - eosio::string str1(size1); - - WASM_ASSERT( str1.get_size() == size1, "str1.get_size() == size1" ); - WASM_ASSERT( str1.is_own_memory() == true, "str1.is_own_memory() == true" ); - - size_t size2 = 0; - eosio::string str2(size2); - - WASM_ASSERT( str2.get_size() == size2, "str2.get_size() == size2" ); - WASM_ASSERT( str2.get_data() == nullptr, "str2.get_data() == nullptr" ); - WASM_ASSERT( str2.is_own_memory() == false, "str2.is_own_memory() == false" ); - - return WASM_TEST_PASS; -} - - -unsigned int test_string::construct_with_data() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str1(data, size, false); - - WASM_ASSERT( str1.get_size() == size, "str1.get_size() == size" ); - WASM_ASSERT( str1.get_data() == data, "str1.get_data() == data" ); - WASM_ASSERT( str1.is_own_memory() == false, "str1.is_own_memory() == false" ); - - eosio::string str2(data, 0, false); - - WASM_ASSERT( str2.get_size() == 0, "str2.get_size() == 0" ); - WASM_ASSERT( str2.get_data() == nullptr, "str2.get_data() == nullptr" ); - WASM_ASSERT( str2.is_own_memory() == false, "str2.is_own_memory() == false" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::construct_with_data_partially() { - char data[] = "abcdefghij"; - size_t substr_size = 5; - size_t offset = 2; - - eosio::string str(data + offset, substr_size, false); - - WASM_ASSERT( str.get_size() == substr_size, "str.get_size() == substr_size" ); - WASM_ASSERT( str.get_data() == data + offset, "str.get_data() == data + offset" ); - for (uint8_t i = offset; i < substr_size; i++) { - WASM_ASSERT( str[i] == data[offset + i], "str[i] == data[offset + i]" ); - } - WASM_ASSERT( str.is_own_memory() == false, "str.is_own_memory() == false" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::construct_with_data_copied() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str1(data, size, true); - - WASM_ASSERT( str1.get_size() == size, "str1.get_size() == size" ); - WASM_ASSERT( str1.get_data() != data, "str1.get_data() != data" ); - for (uint8_t i = 0; i < size; i++) { - WASM_ASSERT( str1[i] == data[i], "str1[i] == data[i]" ); - } - WASM_ASSERT( str1.is_own_memory() == true, "str.is_own_memory() == true" ); - - eosio::string str2(data, 0, true); - - WASM_ASSERT( str2.get_size() == 0, "str2.get_size() == 0" ); - WASM_ASSERT( str2.get_data() == nullptr, "str2.get_data() == nullptr" ); - WASM_ASSERT( str2.is_own_memory() == false, "str2.is_own_memory() == false" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::copy_constructor() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str1(data, size, true); - - eosio::string str2 = str1; - - WASM_ASSERT( str1.get_size() == str2.get_size(), "str1.get_size() == str2.get_size()" ); - WASM_ASSERT( str1.get_data() == str2.get_data(), "str1.get_data() == str2.getget_data_size()" ); - WASM_ASSERT( str1.is_own_memory() == str2.is_own_memory(), "str1.is_own_memory() == str2.is_own_memory()" ); - WASM_ASSERT( str1.get_refcount() == str2.get_refcount(), "str1.get_refcount() == str2.get_refcount()" ); - WASM_ASSERT( str1.get_refcount() == 2, "str1.refcount() == 2" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::assignment_operator() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str1(data, size, true); - - eosio::string str2; - str2 = str1; - - WASM_ASSERT( str1.get_size() == str2.get_size(), "str1.get_size() == str2.get_size()" ); - WASM_ASSERT( str1.get_data() == str2.get_data(), "str1.get_data() == str2.getget_data_size()" ); - WASM_ASSERT( str1.is_own_memory() == str2.is_own_memory(), "str1.is_own_memory() == str2.is_own_memory()" ); - WASM_ASSERT( str1.get_refcount() == str2.get_refcount(), "str1.get_refcount() == str2.get_refcount()" ); - WASM_ASSERT( str1.get_refcount() == 2, "str1.refcount() == 2" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::index_operator() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str(data, size, false); - - for (uint8_t i = 0; i < size; i++) { - WASM_ASSERT( str[i] == data[i], "str[i] == data[i]" ); - } - - return WASM_TEST_PASS; -} - -unsigned int test_string::index_out_of_bound() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str(data, size, false); - char c = str[size]; - - return WASM_TEST_PASS; -} - -unsigned int test_string::substring() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str(data, size, false); - - size_t substr_size = 5; - size_t offset = 2; - eosio::string substr = str.substr(offset, substr_size, false); - - WASM_ASSERT( substr.get_size() == substr_size, "str.get_size() == substr_size" ); - WASM_ASSERT( substr.get_data() == str.get_data() + offset, "substr.get_data() == str.get_data() + offset" ); - for (uint8_t i = offset; i < substr_size; i++) { - WASM_ASSERT( substr[i] == str[offset + i], "substr[i] == str[offset + i]" ); - } - WASM_ASSERT( substr.is_own_memory() == false, "substr.is_own_memory() == false" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::substring_out_of_bound() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str(data, size, false); - - size_t substr_size = size; - size_t offset = 1; - eosio::string substr = str.substr(offset, substr_size, false); - - return WASM_TEST_PASS; -} - -unsigned int test_string::concatenation_null_terminated() { - char data1[] = "abcdefghij"; - - size_t size1 = sizeof(data1)/sizeof(char); - eosio::string str1(data1, size1, false); - - char data2[] = "klmnoppqrst"; - size_t size2 = sizeof(data2)/sizeof(char); - eosio::string str2(data2, size2, false); - - str1 += str2; - - WASM_ASSERT( str1.get_data() != data1, "str1.get_data() != data1" ); - WASM_ASSERT( str1.get_size() == size1 + size2 - 1, "str1.get_size == size1 + size2 - 1" ); - for (uint8_t i = 0; i < size1 - 1; i++) { - WASM_ASSERT( str1[i] == data1[i], "str1[i] == data1[i]" ); - } - for (uint8_t i = 0; i < size2; i++) { - WASM_ASSERT( str1[size1 - 1 + i] == data2[i], "str1[i] == data2[i]" ); - } - - return WASM_TEST_PASS; -} - -unsigned int test_string::concatenation_non_null_terminated() { - char data1[] = {'a','b','c','d','e','f','g','h','i','j'}; - - size_t size1 = sizeof(data1)/sizeof(char); - eosio::string str1(data1, size1, false); - - char data2[] = {'k','l','m','n','o','p','q','r','s','t'}; - size_t size2 = sizeof(data2)/sizeof(char); - eosio::string str2(data2, size2, false); - - str1 += str2; - - WASM_ASSERT( str1.get_data() != data1, "str1.get_data() != data1" ); - WASM_ASSERT( str1.get_size() == size1 + size2, "str1.get_size == size1 + size2" ); - for (uint8_t i = 0; i < size1; i++) { - WASM_ASSERT( str1[i] == data1[i], "str1[i] == data1[i]" ); - } - for (uint8_t i = 0; i < size2; i++) { - WASM_ASSERT( str1[size1 + i] == data2[i], "str1[i] == data2[i]" ); - } - - return WASM_TEST_PASS; -} - -unsigned int test_string::assign() { - char data[] = "abcdefghij"; - size_t size = sizeof(data)/sizeof(char); - - eosio::string str(100); - str.assign(data, size, true); - - WASM_ASSERT( str.get_size() == size, "str.get_size() == size" ); - WASM_ASSERT( str.get_data() != data, "str.get_data() != data" ); - for (uint8_t i = 0; i < size; i++) { - WASM_ASSERT( str[i] == data[i], "str[i] == data[i]" ); - } - WASM_ASSERT( str.is_own_memory() == true, "str.is_own_memory() == true" ); - - str.assign(data, 0, true); - - WASM_ASSERT( str.get_size() == 0, "str.get_size() == 0" ); - WASM_ASSERT( str.get_data() == nullptr, "str.get_data() == nullptr" ); - WASM_ASSERT( str.is_own_memory() == false, "str.is_own_memory() == false" ); - - return WASM_TEST_PASS; -} - - -unsigned int test_string::comparison_operator() { - char data1[] = "abcdefghij"; - size_t size1 = sizeof(data1)/sizeof(char); - eosio::string str1(data1, size1, false); - - char data2[] = "abcdefghij"; - size_t size2 = sizeof(data2)/sizeof(char); - eosio::string str2(data2, size2, false); - - char data3[] = "klmno"; - size_t size3 = sizeof(data3)/sizeof(char); - eosio::string str3(data3, size3, false); - - char data4[] = "aaaaaaaaaaaaaaa"; - size_t size4 = sizeof(data4)/sizeof(char); - eosio::string str4(data4, size4, false); - - char data5[] = "你好"; - size_t size5 = sizeof(data5)/sizeof(char); - eosio::string str5(data5, size5, false); - - char data6[] = "你好嗎?"; - size_t size6 = sizeof(data6)/sizeof(char); - eosio::string str6(data6, size6, false); - - char data7[] = {'a', 'b', 'c', 'd', 'e'}; - size_t size7 = sizeof(data7)/sizeof(char); - eosio::string str7(data7, size7, false); - - char data8[] = {'a', 'b', 'c'}; - size_t size8 = sizeof(data8)/sizeof(char); - eosio::string str8(data8, size8, false); - - WASM_ASSERT( str1 == str2, "str1 == str2" ); - WASM_ASSERT( str1 != str3, "str1 != str3" ); - WASM_ASSERT( str1 < str3, "str1 < str3" ); - WASM_ASSERT( str2 > str4, "str2 > str4" ); - WASM_ASSERT( str1.compare(str2) == 0, "str1.compare(str2) == 0" ); - WASM_ASSERT( str1.compare(str3) < 0, "str1.compare(str3) < 0" ); - WASM_ASSERT( str1.compare(str4) > 0, "str1.compare(str4) > 0" ); - WASM_ASSERT( str5.compare(str6) < 0, "st5.compare(str6) < 0" ); - WASM_ASSERT( str7.compare(str8) > 0, "str7.compare(str8) > 0" ); - - return WASM_TEST_PASS; -} - -unsigned int test_string::print_null_terminated() { - char data[] = "Hello World!"; - - size_t size = sizeof(data)/sizeof(char); - eosio::string str(data, size, false); - - eosio::print(str); - - return WASM_TEST_PASS; -} - -unsigned int test_string::print_non_null_terminated() { - char data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; - - size_t size = sizeof(data)/sizeof(char); - eosio::string str(data, size, false); - - eosio::print(str); - - return WASM_TEST_PASS; -} - -unsigned int test_string::print_unicode() { - char data[] = "你好,世界!"; - - size_t size = sizeof(data)/sizeof(char); - eosio::string str(data, size, false); - - eosio::print(str); - - return WASM_TEST_PASS; -} - -unsigned int test_string::valid_utf8() { - // Roman alphabet is 1 byte UTF-8 - char data[] = "abcdefghij"; - uint32_t size = sizeof(data)/sizeof(char); - eosio::string str(data, size, false); - assert_is_utf8(str.get_data(), str.get_size(), "the string should be a valid utf8 string"); - - // Greek character is 2 bytes UTF-8 - char greek_str_data[] = "γειά σου κόσμος"; - uint32_t greek_str_size = sizeof(greek_str_data)/sizeof(char); - eosio::string valid_greek_str(greek_str_data, greek_str_size, false); - assert_is_utf8(valid_greek_str.get_data(), valid_greek_str.get_size(), "the string should be a valid utf8 string"); - - // Common chinese character is 3 bytes UTF-8 - char chinese_str_data1[] = "你好,世界!"; - uint32_t chinese_str_size1 = sizeof(chinese_str_data1)/sizeof(char); - eosio::string valid_chinese_str1(chinese_str_data1, chinese_str_size1, false); - assert_is_utf8(valid_chinese_str1.get_data(), valid_chinese_str1.get_size(), "the string should be a valid utf8 string"); - - // The following chinese character is 4 bytes UTF-8 - char chinese_str_data2[] = "𥄫"; - uint32_t chinese_str_size2 = sizeof(chinese_str_data2)/sizeof(char); - eosio::string valid_chinese_str2(chinese_str_data2, chinese_str_size2, false); - assert_is_utf8(valid_chinese_str2.get_data(), valid_chinese_str2.get_size(), "the string should be a valid utf8 string"); - - return WASM_TEST_PASS; -} - -unsigned int test_string::invalid_utf8() { - // The following common chinese character is 3 bytes UTF-8 - char chinese_str_data[] = "你好,世界!"; - uint32_t chinese_str_size = sizeof(chinese_str_data)/sizeof(char); - // If it is not multiple of 3, then it is invalid - eosio::string invalid_chinese_str(chinese_str_data, 5, false); - assert_is_utf8(invalid_chinese_str.get_data(), invalid_chinese_str.get_size(), "the string should be a valid utf8 string"); - - return WASM_TEST_PASS; -} - - -unsigned int test_string::string_literal() { - // Construct - char data1[] = "abcdefghij"; - char data2[] = "klmnopqrstuvwxyz"; - - eosio::string str = "abcdefghij"; - - WASM_ASSERT( str.get_size() == 11, "data1 str.get_size() == 11" ); - for (uint8_t i = 0; i < 11; i++) { - WASM_ASSERT( str[i] == data1[i], "data1 str[i] == data1[i]" ); - } - WASM_ASSERT( str.is_own_memory() == true, "data1 str.is_own_memory() == true" ); - - str = "klmnopqrstuvwxyz"; - - WASM_ASSERT( str.get_size() == 17, "data2 str.get_size() == 17" ); - for (uint8_t i = 0; i < 17; i++) { - WASM_ASSERT( str[i] == data2[i], "data2 str[i] == data2[i]" ); - } - WASM_ASSERT( str.is_own_memory() == true, "data2 str.is_own_memory() == true" ); - - return WASM_TEST_PASS; -} diff --git a/contracts/test_api/test_transaction.cpp b/contracts/test_api/test_transaction.cpp index 5404bd65c05f42bd6cef6eec87cc97bd9d58cadc..6ec784d737c6655fb9838aebc781f8a49dddea87 100644 --- a/contracts/test_api/test_transaction.cpp +++ b/contracts/test_api/test_transaction.cpp @@ -4,106 +4,194 @@ */ #include #include +#include #include "test_api.hpp" -unsigned int test_transaction::send_message() { - dummy_action payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action)); - message_send(msg); - return WASM_TEST_PASS; +#pragma pack(push, 1) +template +struct test_action_action { + static account_name get_account() { + return account_name(ACCOUNT); + } + + static action_name get_name() { + return action_name(NAME); + } + + vector data; + + template + friend DataStream& operator << ( DataStream& ds, const test_action_action& a ) { + for ( auto c : a.data ) + ds << c; + return ds; + } + /* + template + friend DataStream& operator >> ( DataStream& ds, test_action_action& a ) { + return ds; + } + */ +}; + +template +struct test_dummy_action { + static account_name get_account() { + return account_name(ACCOUNT); + } + + static action_name get_name() { + return action_name(NAME); + } + char a; + unsigned long long b; + int32_t c; + + template + friend DataStream& operator << ( DataStream& ds, const test_dummy_action& a ) { + ds << a.a; + ds << a.b; + ds << a.c; + return ds; + } + + template + friend DataStream& operator >> ( DataStream& ds, test_dummy_action& a ) { + ds >> a.a; + ds >> a.b; + ds >> a.c; + return ds; + } +}; +#pragma pack(pop) + +void copy_data(char* data, size_t data_len, vector& data_out) { + for (int i=0; i < data_len; i++) + data_out.push_back(data[i]); } -unsigned int test_transaction::send_message_empty() { - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "assert_true"), nullptr, 0); - message_send(msg); - return WASM_TEST_PASS; +void test_transaction::send_action() { + test_dummy_action test_action = {DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C}; + action act(vector{{N(testapi), N(active)}}, test_action); + act.send(); } -/** - * cause failure due to too many pending inline messages - */ -unsigned int test_transaction::send_message_max() { - dummy_action payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - for (int i = 0; i < 10; i++) { - message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action)); - } +void test_transaction::send_action_empty() { + test_action_action test_action; - return WASM_TEST_FAIL; + action act(vector{{N(testapi), N(active)}}, test_action); + + act.send(); } /** - * cause failure due to a large message payload + * cause failure due to a large action payload */ -unsigned int test_transaction::send_message_large() { +void test_transaction::send_action_large() { char large_message[8 * 1024]; - message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), large_message, sizeof(large_message)); - return WASM_TEST_FAIL; + test_action_action test_action; + copy_data(large_message, 8*1024, test_action.data); + action act(vector{{N(testapi), N(active)}}, test_action); + act.send(); + eosio_assert(false, "send_message_large() should've thrown an error"); } /** * cause failure due recursive loop */ -unsigned int test_transaction::send_message_recurse() { +void test_transaction::send_action_recurse() { char buffer[1024]; uint32_t size = read_action(buffer, 1024); - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_transaction", "send_message_recurse"), buffer, size); - message_send(msg); - return WASM_TEST_PASS; + + test_action_action test_action; + copy_data(buffer, 1024, test_action.data); + action act(vector{{N(testapi), N(active)}}, test_action); + + act.send(); } /** * cause failure due to inline TX failure */ -unsigned int test_transaction::send_message_inline_fail() { - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "assert_false"), nullptr, 0); - message_send(msg); - return WASM_TEST_PASS; +void test_transaction::send_action_inline_fail() { + test_action_action test_action; + + action act(vector{{N(testapi), N(active)}}, test_action); + + act.send(); } -unsigned int test_transaction::send_transaction() { - dummy_action payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), &payload, sizeof(dummy_action)); - +void test_transaction::test_tapos_block_prefix() { + int tbp; + read_action( (char*)&tbp, sizeof(int) ); + eosio_assert( tbp == tapos_block_prefix(), "tapos_block_prefix does not match" ); +} - auto trx = transaction_create(); - transaction_require_scope(trx, N(testapi)); - transaction_add_message(trx, msg); - transaction_send(trx); - return WASM_TEST_PASS; +void test_transaction::test_tapos_block_num() { + int tbn; + read_action( (char*)&tbn, sizeof(int) ); + eosio_assert( tbn == tapos_block_num(), "tapos_block_num does not match" ); } -unsigned int test_transaction::send_transaction_empty() { - auto trx = transaction_create(); - transaction_require_scope(trx, N(testapi)); - transaction_send(trx); - return WASM_TEST_FAIL; + +void test_transaction::test_read_transaction() { + checksum256 h; + transaction t; + char* p = (char*)&t; + uint64_t read = read_transaction( (char*)&t, sizeof(t) ); + sha256(p, read, &h); + printhex( &h, sizeof(h) ); } -/** - * cause failure due to too many pending deferred transactions - */ -unsigned int test_transaction::send_transaction_max() { - for (int i = 0; i < 10; i++) { - transaction_create(); - } +void test_transaction::test_transaction_size() { + uint32_t trans_size = 0; + read_action( (char*)&trans_size, sizeof(uint32_t) ); + eosio_assert( trans_size == transaction_size(), "transaction size does not match" ); +} - return WASM_TEST_FAIL; +void test_transaction::send_transaction() { + dummy_action payload = {DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C}; + + test_action_action test_action; + copy_data((char*)&payload, sizeof(dummy_action), test_action.data); + + auto trx = transaction(); + trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); + trx.send(0); +} + +void test_transaction::send_action_sender() { + account_name cur_send; + read_action( &cur_send, sizeof(account_name) ); + test_action_action test_action; + copy_data((char*)&cur_send, sizeof(account_name), test_action.data); + + auto trx = transaction(); + trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); + trx.send(0); +} + +void test_transaction::send_transaction_empty() { + auto trx = transaction(); + trx.send(0); + + eosio_assert(false, "send_transaction_empty() should've thrown an error"); } /** * cause failure due to a large transaction size */ -unsigned int test_transaction::send_transaction_large() { - auto trx = transaction_create(); - transaction_require_scope(trx, N(testapi)); +void test_transaction::send_transaction_large() { + auto trx = transaction(); for (int i = 0; i < 32; i ++) { - char large_message[4 * 1024]; - auto msg = message_create(N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal"), large_message, sizeof(large_message)); - transaction_add_message(trx, msg); + char large_message[1024]; + test_action_action test_action; + copy_data(large_message, 1024, test_action.data); + trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); } - transaction_send(trx); - return WASM_TEST_FAIL; -} + trx.send(0); + eosio_assert(false, "send_transaction_large() should've thrown an error"); +} diff --git a/contracts/test_api/test_types.cpp b/contracts/test_api/test_types.cpp index 18395fc5220471dfa93e33be9ff72e3243c83f91..28a8ac32f8418afe1ec40cdd1d4ec7e694eaaed2 100644 --- a/contracts/test_api/test_types.cpp +++ b/contracts/test_api/test_types.cpp @@ -2,107 +2,99 @@ * @file * @copyright defined in eos/LICENSE.txt */ -#include +#include #include "test_api.hpp" -unsigned int test_types::types_size() { +void test_types::types_size() { - WASM_ASSERT( sizeof(int64_t) == 8, "int64_t size != 8"); - WASM_ASSERT( sizeof(uint64_t) == 8, "uint64_t size != 8"); - WASM_ASSERT( sizeof(uint32_t) == 4, "uint32_t size != 4"); - WASM_ASSERT( sizeof(int32_t) == 4, "int32_t size != 4"); - WASM_ASSERT( sizeof(uint128_t) == 16, "uint128_t size != 16"); - WASM_ASSERT( sizeof(int128_t) == 16, "int128_t size != 16"); - WASM_ASSERT( sizeof(uint8_t) == 1, "uint8_t size != 1"); - - WASM_ASSERT( sizeof(account_name) == 8, "account_name size != 8"); - WASM_ASSERT( sizeof(token_name) == 8, "token_name size != 8"); - WASM_ASSERT( sizeof(table_name) == 8, "table_name size != 8"); - WASM_ASSERT( sizeof(time) == 4, "time size != 4"); - WASM_ASSERT( sizeof(uint256) == 32, "uint256 != 32" ); + eosio_assert( sizeof(int64_t) == 8, "int64_t size != 8"); + eosio_assert( sizeof(uint64_t) == 8, "uint64_t size != 8"); + eosio_assert( sizeof(uint32_t) == 4, "uint32_t size != 4"); + eosio_assert( sizeof(int32_t) == 4, "int32_t size != 4"); + eosio_assert( sizeof(uint128_t) == 16, "uint128_t size != 16"); + eosio_assert( sizeof(int128_t) == 16, "int128_t size != 16"); + eosio_assert( sizeof(uint8_t) == 1, "uint8_t size != 1"); - return WASM_TEST_PASS; + eosio_assert( sizeof(account_name) == 8, "account_name size != 8"); + eosio_assert( sizeof(token_name) == 8, "token_name size != 8"); + eosio_assert( sizeof(table_name) == 8, "table_name size != 8"); + eosio_assert( sizeof(time) == 4, "time size != 4"); + eosio_assert( sizeof(uint256) == 32, "uint256 != 32" ); } -unsigned int test_types::char_to_symbol() { +void test_types::char_to_symbol() { - WASM_ASSERT( eosio::char_to_symbol('1') == 1, "eosio::char_to_symbol('1') != 1"); - WASM_ASSERT( eosio::char_to_symbol('2') == 2, "eosio::char_to_symbol('2') != 2"); - WASM_ASSERT( eosio::char_to_symbol('3') == 3, "eosio::char_to_symbol('3') != 3"); - WASM_ASSERT( eosio::char_to_symbol('4') == 4, "eosio::char_to_symbol('4') != 4"); - WASM_ASSERT( eosio::char_to_symbol('5') == 5, "eosio::char_to_symbol('5') != 5"); - WASM_ASSERT( eosio::char_to_symbol('a') == 6, "eosio::char_to_symbol('a') != 6"); - WASM_ASSERT( eosio::char_to_symbol('b') == 7, "eosio::char_to_symbol('b') != 7"); - WASM_ASSERT( eosio::char_to_symbol('c') == 8, "eosio::char_to_symbol('c') != 8"); - WASM_ASSERT( eosio::char_to_symbol('d') == 9, "eosio::char_to_symbol('d') != 9"); - WASM_ASSERT( eosio::char_to_symbol('e') == 10, "eosio::char_to_symbol('e') != 10"); - WASM_ASSERT( eosio::char_to_symbol('f') == 11, "eosio::char_to_symbol('f') != 11"); - WASM_ASSERT( eosio::char_to_symbol('g') == 12, "eosio::char_to_symbol('g') != 12"); - WASM_ASSERT( eosio::char_to_symbol('h') == 13, "eosio::char_to_symbol('h') != 13"); - WASM_ASSERT( eosio::char_to_symbol('i') == 14, "eosio::char_to_symbol('i') != 14"); - WASM_ASSERT( eosio::char_to_symbol('j') == 15, "eosio::char_to_symbol('j') != 15"); - WASM_ASSERT( eosio::char_to_symbol('k') == 16, "eosio::char_to_symbol('k') != 16"); - WASM_ASSERT( eosio::char_to_symbol('l') == 17, "eosio::char_to_symbol('l') != 17"); - WASM_ASSERT( eosio::char_to_symbol('m') == 18, "eosio::char_to_symbol('m') != 18"); - WASM_ASSERT( eosio::char_to_symbol('n') == 19, "eosio::char_to_symbol('n') != 19"); - WASM_ASSERT( eosio::char_to_symbol('o') == 20, "eosio::char_to_symbol('o') != 20"); - WASM_ASSERT( eosio::char_to_symbol('p') == 21, "eosio::char_to_symbol('p') != 21"); - WASM_ASSERT( eosio::char_to_symbol('q') == 22, "eosio::char_to_symbol('q') != 22"); - WASM_ASSERT( eosio::char_to_symbol('r') == 23, "eosio::char_to_symbol('r') != 23"); - WASM_ASSERT( eosio::char_to_symbol('s') == 24, "eosio::char_to_symbol('s') != 24"); - WASM_ASSERT( eosio::char_to_symbol('t') == 25, "eosio::char_to_symbol('t') != 25"); - WASM_ASSERT( eosio::char_to_symbol('u') == 26, "eosio::char_to_symbol('u') != 26"); - WASM_ASSERT( eosio::char_to_symbol('v') == 27, "eosio::char_to_symbol('v') != 27"); - WASM_ASSERT( eosio::char_to_symbol('w') == 28, "eosio::char_to_symbol('w') != 28"); - WASM_ASSERT( eosio::char_to_symbol('x') == 29, "eosio::char_to_symbol('x') != 29"); - WASM_ASSERT( eosio::char_to_symbol('y') == 30, "eosio::char_to_symbol('y') != 30"); - WASM_ASSERT( eosio::char_to_symbol('z') == 31, "eosio::char_to_symbol('z') != 31"); + eosio_assert( eosio::char_to_symbol('1') == 1, "eosio::char_to_symbol('1') != 1"); + eosio_assert( eosio::char_to_symbol('2') == 2, "eosio::char_to_symbol('2') != 2"); + eosio_assert( eosio::char_to_symbol('3') == 3, "eosio::char_to_symbol('3') != 3"); + eosio_assert( eosio::char_to_symbol('4') == 4, "eosio::char_to_symbol('4') != 4"); + eosio_assert( eosio::char_to_symbol('5') == 5, "eosio::char_to_symbol('5') != 5"); + eosio_assert( eosio::char_to_symbol('a') == 6, "eosio::char_to_symbol('a') != 6"); + eosio_assert( eosio::char_to_symbol('b') == 7, "eosio::char_to_symbol('b') != 7"); + eosio_assert( eosio::char_to_symbol('c') == 8, "eosio::char_to_symbol('c') != 8"); + eosio_assert( eosio::char_to_symbol('d') == 9, "eosio::char_to_symbol('d') != 9"); + eosio_assert( eosio::char_to_symbol('e') == 10, "eosio::char_to_symbol('e') != 10"); + eosio_assert( eosio::char_to_symbol('f') == 11, "eosio::char_to_symbol('f') != 11"); + eosio_assert( eosio::char_to_symbol('g') == 12, "eosio::char_to_symbol('g') != 12"); + eosio_assert( eosio::char_to_symbol('h') == 13, "eosio::char_to_symbol('h') != 13"); + eosio_assert( eosio::char_to_symbol('i') == 14, "eosio::char_to_symbol('i') != 14"); + eosio_assert( eosio::char_to_symbol('j') == 15, "eosio::char_to_symbol('j') != 15"); + eosio_assert( eosio::char_to_symbol('k') == 16, "eosio::char_to_symbol('k') != 16"); + eosio_assert( eosio::char_to_symbol('l') == 17, "eosio::char_to_symbol('l') != 17"); + eosio_assert( eosio::char_to_symbol('m') == 18, "eosio::char_to_symbol('m') != 18"); + eosio_assert( eosio::char_to_symbol('n') == 19, "eosio::char_to_symbol('n') != 19"); + eosio_assert( eosio::char_to_symbol('o') == 20, "eosio::char_to_symbol('o') != 20"); + eosio_assert( eosio::char_to_symbol('p') == 21, "eosio::char_to_symbol('p') != 21"); + eosio_assert( eosio::char_to_symbol('q') == 22, "eosio::char_to_symbol('q') != 22"); + eosio_assert( eosio::char_to_symbol('r') == 23, "eosio::char_to_symbol('r') != 23"); + eosio_assert( eosio::char_to_symbol('s') == 24, "eosio::char_to_symbol('s') != 24"); + eosio_assert( eosio::char_to_symbol('t') == 25, "eosio::char_to_symbol('t') != 25"); + eosio_assert( eosio::char_to_symbol('u') == 26, "eosio::char_to_symbol('u') != 26"); + eosio_assert( eosio::char_to_symbol('v') == 27, "eosio::char_to_symbol('v') != 27"); + eosio_assert( eosio::char_to_symbol('w') == 28, "eosio::char_to_symbol('w') != 28"); + eosio_assert( eosio::char_to_symbol('x') == 29, "eosio::char_to_symbol('x') != 29"); + eosio_assert( eosio::char_to_symbol('y') == 30, "eosio::char_to_symbol('y') != 30"); + eosio_assert( eosio::char_to_symbol('z') == 31, "eosio::char_to_symbol('z') != 31"); for(unsigned char i = 0; i<255; i++) { if((i >= 'a' && i <= 'z') || (i >= '1' || i <= '5')) continue; - WASM_ASSERT( eosio::char_to_symbol(i) == 0, "eosio::char_to_symbol() != 0"); + eosio_assert( eosio::char_to_symbol(i) == 0, "eosio::char_to_symbol() != 0"); } - - return WASM_TEST_PASS; } -unsigned int test_types::string_to_name() { +void test_types::string_to_name() { - WASM_ASSERT( eosio::string_to_name("a") == N(a) , "eosio::string_to_name(a)" ); - WASM_ASSERT( eosio::string_to_name("ba") == N(ba) , "eosio::string_to_name(ba)" ); - WASM_ASSERT( eosio::string_to_name("cba") == N(cba) , "eosio::string_to_name(cba)" ); - WASM_ASSERT( eosio::string_to_name("dcba") == N(dcba) , "eosio::string_to_name(dcba)" ); - WASM_ASSERT( eosio::string_to_name("edcba") == N(edcba) , "eosio::string_to_name(edcba)" ); - WASM_ASSERT( eosio::string_to_name("fedcba") == N(fedcba) , "eosio::string_to_name(fedcba)" ); - WASM_ASSERT( eosio::string_to_name("gfedcba") == N(gfedcba) , "eosio::string_to_name(gfedcba)" ); - WASM_ASSERT( eosio::string_to_name("hgfedcba") == N(hgfedcba) , "eosio::string_to_name(hgfedcba)" ); - WASM_ASSERT( eosio::string_to_name("ihgfedcba") == N(ihgfedcba) , "eosio::string_to_name(ihgfedcba)" ); - WASM_ASSERT( eosio::string_to_name("jihgfedcba") == N(jihgfedcba) , "eosio::string_to_name(jihgfedcba)" ); - WASM_ASSERT( eosio::string_to_name("kjihgfedcba") == N(kjihgfedcba) , "eosio::string_to_name(kjihgfedcba)" ); - WASM_ASSERT( eosio::string_to_name("lkjihgfedcba") == N(lkjihgfedcba) , "eosio::string_to_name(lkjihgfedcba)" ); - WASM_ASSERT( eosio::string_to_name("mlkjihgfedcba") == N(mlkjihgfedcba) , "eosio::string_to_name(mlkjihgfedcba)" ); - WASM_ASSERT( eosio::string_to_name("mlkjihgfedcba1") == N(mlkjihgfedcba2) , "eosio::string_to_name(mlkjihgfedcba2)" ); - WASM_ASSERT( eosio::string_to_name("mlkjihgfedcba55") == N(mlkjihgfedcba14) , "eosio::string_to_name(mlkjihgfedcba14)" ); - - WASM_ASSERT( eosio::string_to_name("azAA34") == N(azBB34) , "eosio::string_to_name N(azBB34)" ); - WASM_ASSERT( eosio::string_to_name("AZaz12Bc34") == N(AZaz12Bc34) , "eosio::string_to_name AZaz12Bc34" ); - WASM_ASSERT( eosio::string_to_name("AAAAAAAAAAAAAAA") == eosio::string_to_name("BBBBBBBBBBBBBDDDDDFFFGG") , "eosio::string_to_name BBBBBBBBBBBBBDDDDDFFFGG" ); - - return WASM_TEST_PASS; + eosio_assert( eosio::string_to_name("a") == N(a) , "eosio::string_to_name(a)" ); + eosio_assert( eosio::string_to_name("ba") == N(ba) , "eosio::string_to_name(ba)" ); + eosio_assert( eosio::string_to_name("cba") == N(cba) , "eosio::string_to_name(cba)" ); + eosio_assert( eosio::string_to_name("dcba") == N(dcba) , "eosio::string_to_name(dcba)" ); + eosio_assert( eosio::string_to_name("edcba") == N(edcba) , "eosio::string_to_name(edcba)" ); + eosio_assert( eosio::string_to_name("fedcba") == N(fedcba) , "eosio::string_to_name(fedcba)" ); + eosio_assert( eosio::string_to_name("gfedcba") == N(gfedcba) , "eosio::string_to_name(gfedcba)" ); + eosio_assert( eosio::string_to_name("hgfedcba") == N(hgfedcba) , "eosio::string_to_name(hgfedcba)" ); + eosio_assert( eosio::string_to_name("ihgfedcba") == N(ihgfedcba) , "eosio::string_to_name(ihgfedcba)" ); + eosio_assert( eosio::string_to_name("jihgfedcba") == N(jihgfedcba) , "eosio::string_to_name(jihgfedcba)" ); + eosio_assert( eosio::string_to_name("kjihgfedcba") == N(kjihgfedcba) , "eosio::string_to_name(kjihgfedcba)" ); + eosio_assert( eosio::string_to_name("lkjihgfedcba") == N(lkjihgfedcba) , "eosio::string_to_name(lkjihgfedcba)" ); + eosio_assert( eosio::string_to_name("mlkjihgfedcba") == N(mlkjihgfedcba) , "eosio::string_to_name(mlkjihgfedcba)" ); + eosio_assert( eosio::string_to_name("mlkjihgfedcba1") == N(mlkjihgfedcba2) , "eosio::string_to_name(mlkjihgfedcba2)" ); + eosio_assert( eosio::string_to_name("mlkjihgfedcba55") == N(mlkjihgfedcba14) , "eosio::string_to_name(mlkjihgfedcba14)" ); + + eosio_assert( eosio::string_to_name("azAA34") == N(azBB34) , "eosio::string_to_name N(azBB34)" ); + eosio_assert( eosio::string_to_name("AZaz12Bc34") == N(AZaz12Bc34) , "eosio::string_to_name AZaz12Bc34" ); + eosio_assert( eosio::string_to_name("AAAAAAAAAAAAAAA") == eosio::string_to_name("BBBBBBBBBBBBBDDDDDFFFGG") , "eosio::string_to_name BBBBBBBBBBBBBDDDDDFFFGG" ); } -unsigned int test_types::name_class() { +void test_types::name_class() { - WASM_ASSERT ( eosio::name(eosio::string_to_name("azAA34")).value == N(azAA34), "eosio::name != N(azAA34)" ); - WASM_ASSERT ( eosio::name(eosio::string_to_name("AABBCC")).value == 0, "eosio::name != N(0)" ); - WASM_ASSERT ( eosio::name(eosio::string_to_name("AA11")).value == N(AA11), "eosio::name != N(AA11)" ); - WASM_ASSERT ( eosio::name(eosio::string_to_name("11AA")).value == N(11), "eosio::name != N(11)" ); - WASM_ASSERT ( eosio::name(eosio::string_to_name("22BBCCXXAA")).value == N(22), "eosio::name != N(22)" ); - WASM_ASSERT ( eosio::name(eosio::string_to_name("AAAbbcccdd")) == eosio::name(eosio::string_to_name("AAAbbcccdd")), "eosio::name == eosio::name" ); + eosio_assert( eosio::name(eosio::string_to_name("azAA34")).value == N(azAA34), "eosio::name != N(azAA34)" ); + eosio_assert( eosio::name(eosio::string_to_name("AABBCC")).value == 0, "eosio::name != N(0)" ); + eosio_assert( eosio::name(eosio::string_to_name("AA11")).value == N(AA11), "eosio::name != N(AA11)" ); + eosio_assert( eosio::name(eosio::string_to_name("11AA")).value == N(11), "eosio::name != N(11)" ); + eosio_assert( eosio::name(eosio::string_to_name("22BBCCXXAA")).value == N(22), "eosio::name != N(22)" ); + eosio_assert( eosio::name(eosio::string_to_name("AAAbbcccdd")) == eosio::name(eosio::string_to_name("AAAbbcccdd")), "eosio::name == eosio::name" ); uint64_t tmp = eosio::name(eosio::string_to_name("11bbcccdd")); - WASM_ASSERT(N(11bbcccdd) == tmp, "N(11bbcccdd) == tmp"); - - return WASM_TEST_PASS; + eosio_assert(N(11bbcccdd) == tmp, "N(11bbcccdd) == tmp"); } diff --git a/contracts/test_api_db/CMakeLists.txt b/contracts/test_api_db/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0121439dbf15429d80daaf5bbc4584ee1efe4d0f --- /dev/null +++ b/contracts/test_api_db/CMakeLists.txt @@ -0,0 +1,5 @@ +add_wast_executable(TARGET test_api_db + INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" + LIBRARIES libc++ libc eosiolib + DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/contracts/test_api_db/test_api_db.cpp b/contracts/test_api_db/test_api_db.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be7e8d898257653a20b9ac572d25fcca8414dfa9 --- /dev/null +++ b/contracts/test_api_db/test_api_db.cpp @@ -0,0 +1,31 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include "../test_api/test_api.hpp" + +#include "test_db.cpp" + +extern "C" { + + void init() { + + } + + void apply( unsigned long long code, unsigned long long action ) { + + WASM_TEST_HANDLER(test_db, primary_i64_general); + WASM_TEST_HANDLER(test_db, primary_i64_lowerbound); + WASM_TEST_HANDLER(test_db, primary_i64_upperbound); + WASM_TEST_HANDLER(test_db, idx64_general); + WASM_TEST_HANDLER(test_db, idx64_lowerbound); + WASM_TEST_HANDLER(test_db, idx64_upperbound); + + WASM_TEST_HANDLER(test_db, key_str_general); + + //unhandled test call + eosio_assert(false, "Unknown Test"); + } + +} diff --git a/contracts/test_api/test_db.cpp b/contracts/test_api_db/test_db.cpp similarity index 79% rename from contracts/test_api/test_db.cpp rename to contracts/test_api_db/test_db.cpp index da780b2db843ca18c26612e07e3da6a99305b885..29fce5f243ada5102ef8cf6969fc78b62bf19f64 100644 --- a/contracts/test_api/test_db.cpp +++ b/contracts/test_api_db/test_db.cpp @@ -3,7 +3,7 @@ #include #include #include -#include "test_api.hpp" +#include "../test_api/test_api.hpp" int primary[11] = {0,1,2,3,4,5,6,7,8,9,10}; int secondary[11] = {7,0,1,3,6,9,10,2,4,5,8}; @@ -64,13 +64,25 @@ extern "C" { char *ptr = (char *)vptr; while(size--) { *(ptr++)=val; } } - uint32_t my_strlen(const char *str); - bool my_memcmp(void *s1, void *s2, uint32_t n); + uint32_t my_strlen(const char *str) { + uint32_t len = 0; + while(str[len]) ++len; + return len; + } + bool my_memcmp(void *s1, void *s2, uint32_t n) { + unsigned char *c1 = (unsigned char*)s1; + unsigned char *c2 = (unsigned char*)s2; + for (uint32_t i = 0; i < n; i++) { + if (c1[i] != c2[i]) { + return false; + } + } + return true; + } } #if 0 - -unsigned int test_db::key_str_table() { +void test_db::key_str_table() { const char* keys[] = { "alice", "bob", "carol", "dave" }; const char* vals[] = { "data1", "data2", "data3", "data4" }; @@ -78,100 +90,96 @@ unsigned int test_db::key_str_table() { const char* atr[] = { "atr", "atr", "atr", "atr" }; const char* ztr[] = { "ztr", "ztr", "ztr", "ztr" }; - eosio::var_table StringTableAtr; - eosio::var_table StringTableZtr; - eosio::var_table StringTableStr; + eosio::var_table StringTableAtr; + eosio::var_table StringTableZtr; + eosio::var_table StringTableStr; uint32_t res = 0; // fill some data in contiguous tables for( int ii = 0; ii < 4; ++ii ) { res = StringTableAtr.store( (char*)keys[ii], STRLEN(keys[ii]), (char*)atr[ii], STRLEN(atr[ii]) ); - eos_assert( res != 0, "atr" ); + eosio_assert( res != 0, "atr" ); res = StringTableZtr.store( (char*)keys[ii], STRLEN(keys[ii]), (char*)ztr[ii], STRLEN(ztr[ii]) ); - eos_assert(res != 0, "ztr" ); + eosio_assert(res != 0, "ztr" ); } char tmp[64]; res = StringTableStr.store ((char *)keys[0], STRLEN(keys[0]), (char *)vals[0], STRLEN(vals[0])); - eos_assert(res != 0, "store alice" ); + eosio_assert(res != 0, "store alice" ); res = StringTableStr.store((char *)keys[1], STRLEN(keys[1]), (char *)vals[1], STRLEN(vals[1]) ); - eos_assert(res != 0, "store bob" ); + eosio_assert(res != 0, "store bob" ); res = StringTableStr.store((char *)keys[2], STRLEN(keys[2]), (char *)vals[2], STRLEN(vals[2]) ); - eos_assert(res != 0, "store carol" ); + eosio_assert(res != 0, "store carol" ); res = StringTableStr.store((char *)keys[3], STRLEN(keys[3]), (char *)vals[3], STRLEN(vals[3]) ); - eos_assert(res != 0, "store dave" ); + eosio_assert(res != 0, "store dave" ); res = StringTableStr.load((char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "load alice"); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "load alice"); res = StringTableStr.load((char *)keys[1], STRLEN(keys[1]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "load bob"); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "load bob"); res = StringTableStr.load((char *)keys[2], STRLEN(keys[2]), tmp, 64); - eos_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "load carol"); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "load carol"); res = StringTableStr.load((char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "load dave"); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "load dave"); res = StringTableStr.previous((char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "back carol"); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "back carol"); res = StringTableStr.previous((char *)keys[2], STRLEN(keys[2]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "back dave"); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "back dave"); res = StringTableStr.previous((char *)keys[1], STRLEN(keys[1]), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "back alice"); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "back alice"); res = StringTableStr.previous((char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == -1, "no prev"); + eosio_assert(res == -1, "no prev"); res = StringTableStr.next((char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "next bob"); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "next bob"); res = StringTableStr.next((char *)keys[1], STRLEN(keys[1]), tmp, 64); - eos_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "next carol"); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "next carol"); res = StringTableStr.next((char *)keys[2], STRLEN(keys[2]), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "next dave"); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "next dave"); res = StringTableStr.next((char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == -1, "no next"); + eosio_assert(res == -1, "no next"); res = StringTableStr.next((char *)keys[0], STRLEN(keys[0]), tmp, 0); - eos_assert(res == 0, "next 0"); + eosio_assert(res == 0, "next 0"); - res = StringTableStr.front(tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "front alice"); + res = StringTableStr.front((char*)keys[0], STRLEN(keys[0]), tmp, 64); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "front alice"); - res = StringTableStr.back(tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "back dave"); + res = StringTableStr.back((char*)keys[0], STRLEN(keys[0]), tmp, 64); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "back dave"); res = StringTableStr.lower_bound((char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "lowerbound alice"); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "lowerbound alice"); res = StringTableStr.upper_bound((char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "upperbound bob"); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "upperbound bob"); res = StringTableStr.lower_bound((char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "upperbound dave"); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "upperbound dave"); res = StringTableStr.upper_bound((char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == -1, "no upper_bound"); + eosio_assert(res == -1, "no upper_bound"); - return 1; // WASM_TEST_PASS; } - #endif -#if 0 - -unsigned int test_db::key_str_general() { +void test_db::key_str_general() { const char* keys[] = { "alice", "bob", "carol", "dave" }; const char* vals[] = { "data1", "data2", "data3", "data4" }; @@ -183,111 +191,100 @@ unsigned int test_db::key_str_general() { //fill some data in contiguous tables for(int i=0; i < 4; ++i) { - res = store_str(current_receiver(), N(atr), (char *)keys[i], STRLEN(keys[i]), (char *)atr[i], STRLEN(atr[i]) ); - eos_assert(res != 0, "atr" ); + res = store_str(current_receiver(), N(atr), N(testapi), (char *)keys[i], STRLEN(keys[i]), (char *)atr[i], STRLEN(atr[i]) ); + eosio_assert(res != 0, "atr" ); - res = store_str(current_receiver(), N(ztr), (char *)keys[i], STRLEN(keys[i]), (char *)ztr[i], STRLEN(ztr[i]) ); - eos_assert(res != 0, "ztr" ); + res = store_str(current_receiver(), N(ztr), N(testapi), (char *)keys[i], STRLEN(keys[i]), (char *)ztr[i], STRLEN(ztr[i]) ); + eosio_assert(res != 0, "ztr" ); } char tmp[64]; - res = store_str(current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), (char *)vals[0], STRLEN(vals[0]) ); - eos_assert(res != 0, "store alice" ); + res = store_str(current_receiver(), N(str), N(testapi), (char *)keys[0], STRLEN(keys[0]), (char *)vals[0], STRLEN(vals[0]) ); + eosio_assert(res != 0, "store alice" ); + + res = store_str(current_receiver(), N(str), N(testapi), (char *)keys[1], STRLEN(keys[1]), (char *)vals[1], STRLEN(vals[1]) ); + eosio_assert(res != 0, "store bob" ); - res = store_str(current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), (char *)vals[1], STRLEN(vals[1]) ); - eos_assert(res != 0, "store bob" ); + res = store_str(current_receiver(), N(str), N(testapi), (char *)keys[2], STRLEN(keys[2]), (char *)vals[2], STRLEN(vals[2]) ); + eosio_assert(res != 0, "store carol" ); - res = store_str(current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), (char *)vals[2], STRLEN(vals[2]) ); - eos_assert(res != 0, "store carol" ); + res = store_str(current_receiver(), N(str), N(testapi), (char *)keys[3], STRLEN(keys[3]), (char *)vals[3], STRLEN(vals[3]) ); + eosio_assert(res != 0, "store dave" ); - res = store_str(current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), (char *)vals[3], STRLEN(vals[3]) ); - eos_assert(res != 0, "store dave" ); - res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "load alice"); + res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "load alice"); - res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "load bob"); + res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "load bob"); - res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); - eos_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "load carol"); + res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "load carol"); - res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "load dave"); + res = load_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "load dave"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "back carol"); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "back carol"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "back dave"); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "back dave"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "back alice"); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "back alice"); res = previous_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == -1, "no prev"); + eosio_assert(res == 0, "no prev"); - res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "next bob"); + res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "next bob"); - res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); - eos_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "next carol"); + res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[1], STRLEN(keys[1]), tmp, 64); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void *)vals[2], (void *)tmp, res), "next carol"); - res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "next dave"); - - res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == -1, "no next"); - - res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 0); - eos_assert(res == 0, "next 0"); - - res = front_str(current_receiver(), current_receiver(), N(str), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "front alice"); - - res = back_str(current_receiver(), current_receiver(), N(str), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "back dave"); + res = next_str(current_receiver(), current_receiver(), N(str), (char *)keys[2], STRLEN(keys[2]), tmp, 64); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "next dave"); res = lower_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "lowerbound alice"); + eosio_assert(res == STRLEN(vals[0]) && my_memcmp((void *)vals[0], (void *)tmp, res), "lowerbound alice"); - res = upper_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); - eos_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "upperbound bob"); + res = upper_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[0], STRLEN(keys[0]), tmp, 64); + eosio_assert(res == STRLEN(vals[1]) && my_memcmp((void *)vals[1], (void *)tmp, res), "upperbound bob"); - res = lower_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "upperbound dave"); + res = lower_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); + eosio_assert(res == STRLEN(vals[3]) && my_memcmp((void *)vals[3], (void *)tmp, res), "upperbound dave"); - res = upper_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); - eos_assert(res == -1, "no upper_bound"); + res = upper_bound_str(current_receiver(), current_receiver(), N(str), (char *)keys[3], STRLEN(keys[3]), tmp, 64); + eosio_assert(res == 0, "no upper_bound"); - return 1;//WASM_TEST_PASS; -} + res = update_str(current_receiver(), N(str), N(testapi), (char *)keys[3], STRLEN(keys[3]), (char *)vals[2], STRLEN(vals[2]) ); + eosio_assert(res != 0, "store dave" ); -#endif + res = load_str(current_receiver(), current_receiver(), N(str), (char*)keys[3], STRLEN(keys[3]), tmp, 64 ); + eosio_assert(res == STRLEN(vals[2]) && my_memcmp((void*)vals[2], (void*)tmp, res), "load updated carol" ); +} #if 0 - -unsigned int test_db::key_i64_general() { +void test_db::key_i64_general() { uint32_t res = 0; - test_model alice{ N(alice), 20, 4234622}; test_model bob { N(bob), 15, 11932435}; test_model carol{ N(carol), 30, 545342453}; test_model dave { N(dave), 46, 6535354}; res = store_i64(current_receiver(), N(test_table), &dave, sizeof(test_model)); - eos_assert(res != 0, "store dave" ); + eosio_assert(res != 0, "store dave" ); res = store_i64(current_receiver(), N(test_table), &carol, sizeof(test_model)); - eos_assert(res != 0, "store carol" ); + eosio_assert(res != 0, "store carol" ); res = store_i64(current_receiver(), N(test_table), &bob, sizeof(test_model)); - eos_assert(res != 0, "store bob" ); + eosio_assert(res != 0, "store bob" ); res = store_i64(current_receiver(), N(test_table), &alice, sizeof(test_model)); - eos_assert(res != 0, "store alice" ); + eosio_assert(res != 0, "store alice" ); //fill with different ages in adjacent tables dave.age=123; store_i64(current_receiver(), N(test_tabld), &dave, sizeof(test_model)); @@ -302,56 +299,56 @@ unsigned int test_db::key_i64_general() { test_model tmp; res = front_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "front_i64 1"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "front_i64 1"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "front_i64 2"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "front_i64 2"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol previous"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol previous"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob previous"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob previous"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "alice previous"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "alice previous"); res = previous_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "previous null"); + eosio_assert(res == 0, "previous null"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob next"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob next"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol next"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol next"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "dave next"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "dave next"); res = next_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "next null"); + eosio_assert(res == 0, "next null"); my_memset(&alice, 0, sizeof(test_model)); - eos_assert(alice.name == 0 && alice.age == 0 && alice.phone == 0, "my_memset"); + eosio_assert(alice.name == 0 && alice.age == 0 && alice.phone == 0, "my_memset"); alice.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alice, sizeof(test_model)); - eos_assert(res == sizeof(test_model) && alice.age == 20 && alice.phone == 4234622, "alice error 1"); + eosio_assert(res == sizeof(test_model) && alice.age == 20 && alice.phone == 4234622, "alice error 1"); alice.age = 21; alice.phone = 1234; res = store_i64(current_receiver(), N(test_table), &alice, sizeof(test_model)); - eos_assert(res == 0, "store alice 2" ); + eosio_assert(res == 0, "store alice 2" ); my_memset(&alice, 0, sizeof(test_model)); alice.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alice, sizeof(test_model)); - eos_assert(res == sizeof(test_model) && alice.age == 21 && alice.phone == 1234, "alice error 2"); + eosio_assert(res == sizeof(test_model) && alice.age == 21 && alice.phone == 1234, "alice error 2"); my_memset(&bob, 0, sizeof(test_model)); bob.name = N(bob); @@ -363,72 +360,72 @@ unsigned int test_db::key_i64_general() { dave.name = N(dave); res = load_i64(current_receiver(), current_receiver(), N(test_table), &bob, sizeof(test_model)); - eos_assert(res == sizeof(test_model) && bob.age == 15 && bob.phone == 11932435, "bob error 1"); + eosio_assert(res == sizeof(test_model) && bob.age == 15 && bob.phone == 11932435, "bob error 1"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &carol, sizeof(test_model)); - eos_assert(res == sizeof(test_model) && carol.age == 30 && carol.phone == 545342453, "carol error 1"); + eosio_assert(res == sizeof(test_model) && carol.age == 30 && carol.phone == 545342453, "carol error 1"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &dave, sizeof(test_model)); - eos_assert(res == sizeof(test_model) && dave.age == 46 && dave.phone == 6535354, "dave error 1"); + eosio_assert(res == sizeof(test_model) && dave.age == 46 && dave.phone == 6535354, "dave error 1"); res = load_i64(current_receiver(), N(other_code), N(test_table), &alice, sizeof(test_model)); - eos_assert(res == -1, "other_code"); + eosio_assert(res == sizeof(test_model), "other_code"); res = load_i64(current_receiver(), current_receiver(), N(other_table), &alice, sizeof(test_model)); - eos_assert(res == -1, "other_table"); + eosio_assert(res == 0, "other_table"); test_model_v2 alicev2; alicev2.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alicev2, sizeof(test_model_v2)); - eos_assert(res == sizeof(test_model) && alicev2.age == 21 && alicev2.phone == 1234, "alicev2 load"); + eosio_assert(res == sizeof(test_model) && alicev2.age == 21 && alicev2.phone == 1234, "alicev2 load"); alicev2.new_field = 66655444; res = store_i64(current_receiver(), N(test_table), &alicev2, sizeof(test_model_v2)); - eos_assert(res == 0, "store alice 3" ); + eosio_assert(res == 0, "store alice 3" ); my_memset(&alicev2, 0, sizeof(test_model_v2)); alicev2.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &alicev2, sizeof(test_model_v2)); - eos_assert(res == sizeof(test_model_v2) && alicev2.age == 21 && alicev2.phone == 1234 && alicev2.new_field == 66655444, "alice model v2"); + eosio_assert(res == sizeof(test_model_v2) && alicev2.age == 21 && alicev2.phone == 1234 && alicev2.new_field == 66655444, "alice model v2"); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(bob); res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(bob), "lower_bound_i64 bob" ); + eosio_assert(res == sizeof(test_model) && tmp.name == N(bob), "lower_bound_i64 bob" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(boc); res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(carol), "lower_bound_i64 carol" ); + eosio_assert(res == sizeof(test_model) && tmp.name == N(carol), "lower_bound_i64 carol" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(dave); - res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(uint64_t) ); - eos_assert(res == sizeof(uint64_t) && tmp.name == N(dave), "lower_bound_i64 dave" ); + // data packet only big enough for name + res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(uint64_t) ); + eosio_assert(res == sizeof(test_model) && tmp.name == N(dave), "lower_bound_i64 dave" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(davf); res = lower_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(uint64_t) ); - eos_assert(res == -1, "lower_bound_i64 fail" ); + eosio_assert(res == 0, "lower_bound_i64 fail" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(alice); res = upper_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.age == 15 && tmp.name == N(bob), "upper_bound_i64 bob" ); + eosio_assert(res == sizeof(test_model) && tmp.age == 15 && tmp.name == N(bob), "upper_bound_i64 bob" ); my_memset(&tmp, 0, sizeof(test_model)); tmp.name = N(dave); res = upper_bound_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "upper_bound_i64 dave" ); - + eosio_assert(res == 0, "upper_bound_i64 dave" ); test_model_v3 tmp2; tmp2.name = N(alice); res = load_i64(current_receiver(), current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); - eos_assert(res == sizeof(test_model_v2) && + eosio_assert(res == sizeof(test_model_v2) && tmp2.age == 21 && tmp2.phone == 1234 && tmp2.new_field == 66655444, @@ -436,10 +433,10 @@ unsigned int test_db::key_i64_general() { tmp2.another_field = 221122; res = update_i64(current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); - eos_assert(res == 1, "update_i64"); + eosio_assert(res == 1, "update_i64"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); - eos_assert(res == sizeof(test_model_v3) && + eosio_assert(res == sizeof(test_model_v3) && tmp2.age == 21 && tmp2.phone == 1234 && tmp2.new_field == 66655444 && @@ -448,10 +445,10 @@ unsigned int test_db::key_i64_general() { tmp2.age = 11; res = update_i64(current_receiver(), N(test_table), &tmp2, sizeof(uint64_t)+1 ); - eos_assert(res == 1, "update_i64 small"); + eosio_assert(res == 1, "update_i64 small"); res = load_i64(current_receiver(), current_receiver(), N(test_table), &tmp2, sizeof(test_model_v3)); - eos_assert(res == sizeof(test_model_v3) && + eosio_assert(res == sizeof(test_model_v3) && tmp2.age == 11 && tmp2.phone == 1234 && tmp2.new_field == 66655444 && @@ -462,106 +459,93 @@ unsigned int test_db::key_i64_general() { //Remove dummy records uint64_t tables[] { N(test_tabld), N(test_tablf) }; for(auto& t : tables) { - while( front_i64( current_receiver(), current_receiver(), t, &tmp, sizeof(test_model) ) != -1 ) { + while( front_i64( current_receiver(), current_receiver(), t, &tmp, sizeof(test_model) ) != 0 ) { remove_i64(current_receiver(), t, &tmp); } } - - return WASM_TEST_PASS; } -#endif - -#if 0 - -unsigned int test_db::key_i64_remove_all() { +void test_db::key_i64_remove_all() { uint32_t res = 0; uint64_t key; key = N(alice); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 1, "remove alice"); + eosio_assert(res == 1, "remove alice"); key = N(bob); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 1, "remove bob"); + eosio_assert(res == 1, "remove bob"); key = N(carol); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 1, "remove carol"); + eosio_assert(res == 1, "remove carol"); key = N(dave); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 1, "remove dave"); + eosio_assert(res == 1, "remove dave"); test_model tmp; res = front_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "front_i64 remove"); + eosio_assert(res == 0, "front_i64 remove"); res = back_i64( current_receiver(), current_receiver(), N(test_table), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "back_i64_i64 remove"); + eosio_assert(res == 0, "back_i64_i64 remove"); key = N(alice); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 0, "remove alice 1"); + eosio_assert(res == 0, "remove alice 1"); key = N(bob); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 0, "remove bob 1"); + eosio_assert(res == 0, "remove bob 1"); key = N(carol); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 0, "remove carol 1"); + eosio_assert(res == 0, "remove carol 1"); key = N(dave); res = remove_i64(current_receiver(), N(test_table), &key); - eos_assert(res == 0, "remove dave 1"); - - - return WASM_TEST_PASS; + eosio_assert(res == 0, "remove dave 1"); } -#endif - -#if 0 - -unsigned int test_db::key_i64_small_load() { +void test_db::key_i64_small_load() { uint64_t dummy = 0; - load_i64(current_receiver(), current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)-1); - return WASM_TEST_PASS; + test_model alice{ N(alice), 20, 4234622}; + // shouldn't throw an error, short circuits out because no table id is found + auto res = load_i64(current_receiver(), current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)-1); + eosio_assert(res == 0, "should have returned 0 on failure"); + store_i64(current_receiver(), N(test_table), &alice, sizeof(test_model)); + load_i64(current_receiver(), current_receiver(), N(test_table), &alice, sizeof(uint64_t)-1); } -unsigned int test_db::key_i64_small_store() { +void test_db::key_i64_small_store() { uint64_t dummy = 0; store_i64(current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)-1); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_store_scope() { +void test_db::key_i64_store_scope() { uint64_t dummy = 0; store_i64(current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_remove_scope() { +void test_db::key_i64_remove_scope() { uint64_t dummy = 0; store_i64(current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_not_found() { +void test_db::key_i64_not_found() { uint64_t dummy = 1000; auto res = load_i64(current_receiver(), current_receiver(), N(just_uint64), &dummy, sizeof(uint64_t)); - eos_assert(res == -1, "i64_not_found load"); + eosio_assert(res == 0, "i64_not_found load"); res = remove_i64(current_receiver(), N(just_uint64), &dummy); - eos_assert(res == 0, "i64_not_found remove"); - return WASM_TEST_PASS; + eosio_assert(res == 0, "i64_not_found remove"); } -unsigned int test_db::key_i64_front_back() { +void test_db::key_i64_front_back() { uint32_t res = 0; @@ -579,70 +563,68 @@ unsigned int test_db::key_i64_front_back() { my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 1"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 1"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 2"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 2"); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "key_i64_front 3"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "key_i64_front 3"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 4"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 4"); uint64_t key = N(carol); remove_i64(current_receiver(), N(b), &key); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 5"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 5"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 6"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 6"); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 7"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 7"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 8"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 8"); key = N(dave); remove_i64(current_receiver(), N(b), &key); res = front_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "key_i64_front 9"); + eosio_assert(res == 0, "key_i64_front 9"); res = back_i64( current_receiver(), current_receiver(), N(b), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "key_i64_front 10"); + eosio_assert(res == 0, "key_i64_front 10"); key = N(bob); remove_i64(current_receiver(), N(a), &key); my_memset(&tmp, 0, sizeof(test_model)); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 11"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 11"); my_memset(&tmp, 0, sizeof(test_model)); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 12"); + eosio_assert(res == sizeof(test_model) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 12"); key = N(alice); remove_i64(current_receiver(), N(a), &key); res = front_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "key_i64_front 13"); + eosio_assert(res == 0, "key_i64_front 13"); res = back_i64( current_receiver(), current_receiver(), N(a), &tmp, sizeof(test_model) ); - eos_assert(res == -1, "key_i64_front 14"); - - return WASM_TEST_PASS; + eosio_assert(res == 0, "key_i64_front 14"); } -unsigned int store_set_in_table(uint64_t table_name) +uint32_t store_set_in_table(uint64_t table_name) { uint32_t res = 0; @@ -650,36 +632,37 @@ unsigned int store_set_in_table(uint64_t table_name) TestModel128x2 alice0{0, 500, N(alice0), table_name}; TestModel128x2 alice1{1, 400, N(alice1), table_name}; TestModel128x2 alice2{2, 300, N(alice2), table_name}; - TestModel128x2 alice22{2, 200, N(alice22), table_name}; + TestModel128x2 alice22{2, 200, N(alice33), table_name}; res = store_i128i128(current_receiver(), table_name, &alice0, sizeof(TestModel128x2)); - eos_assert(res == 1, "store alice0" ); + eosio_assert(res == 1, "store alice0" ); res = store_i128i128(current_receiver(), table_name, &alice1, sizeof(TestModel128x2)); - eos_assert(res == 1, "store alice1" ); + eosio_assert(res == 1, "store alice1" ); res = store_i128i128(current_receiver(), table_name, &alice2, sizeof(TestModel128x2)); - eos_assert(res == 1, "store alice2" ); + eosio_assert(res == 1, "store alice2" ); res = store_i128i128(current_receiver(), table_name, &alice22, sizeof(TestModel128x2)); - eos_assert(res == 1, "store alice22" ); + eosio_assert(res == 1, "store alice22" ); + return res; TestModel128x2 bob0{10, 1, N(bob0), table_name}; TestModel128x2 bob1{11, 2, N(bob1), table_name}; TestModel128x2 bob2{12, 3, N(bob2), table_name}; TestModel128x2 bob3{13, 4, N(bob3), table_name}; res = store_i128i128(current_receiver(), table_name, &bob0, sizeof(TestModel128x2)); - eos_assert(res == 1, "store bob0" ); + eosio_assert(res == 1, "store bob0" ); res = store_i128i128(current_receiver(), table_name, &bob1, sizeof(TestModel128x2)); - eos_assert(res == 1, "store bob1" ); + eosio_assert(res == 1, "store bob1" ); res = store_i128i128(current_receiver(), table_name, &bob2, sizeof(TestModel128x2)); - eos_assert(res == 1, "store bob2" ); + eosio_assert(res == 1, "store bob2" ); res = store_i128i128(current_receiver(), table_name, &bob3, sizeof(TestModel128x2)); - eos_assert(res == 1, "store bob3" ); + eosio_assert(res == 1, "store bob3" ); TestModel128x2 carol0{20, 900, N(carol0), table_name}; TestModel128x2 carol1{21, 800, N(carol1), table_name}; @@ -687,16 +670,16 @@ unsigned int store_set_in_table(uint64_t table_name) TestModel128x2 carol3{23, 600, N(carol3), table_name}; res = store_i128i128(current_receiver(), table_name, &carol0, sizeof(TestModel128x2)); - eos_assert(res == 1, "store carol0" ); + eosio_assert(res == 1, "store carol0" ); res = store_i128i128(current_receiver(), table_name, &carol1, sizeof(TestModel128x2)); - eos_assert(res == 1, "store carol1" ); + eosio_assert(res == 1, "store carol1" ); res = store_i128i128(current_receiver(), table_name, &carol2, sizeof(TestModel128x2)); - eos_assert(res == 1, "store carol2" ); + eosio_assert(res == 1, "store carol2" ); res = store_i128i128(current_receiver(), table_name, &carol3, sizeof(TestModel128x2)); - eos_assert(res == 1, "store carol3" ); + eosio_assert(res == 1, "store carol3" ); TestModel128x2 dave0{30, 8, N(dave0), table_name}; TestModel128x2 dave1{31, 7, N(dave1), table_name}; @@ -704,36 +687,33 @@ unsigned int store_set_in_table(uint64_t table_name) TestModel128x2 dave3{33, 4, N(dave3), table_name}; res = store_i128i128(current_receiver(), table_name, &dave0, sizeof(TestModel128x2)); - eos_assert(res == 1, "store dave0" ); + eosio_assert(res == 1, "store dave0" ); res = store_i128i128(current_receiver(), table_name, &dave1, sizeof(TestModel128x2)); - eos_assert(res == 1, "store dave1" ); + eosio_assert(res == 1, "store dave1" ); res = store_i128i128(current_receiver(), table_name, &dave2, sizeof(TestModel128x2)); - eos_assert(res == 1, "store dave2" ); + eosio_assert(res == 1, "store dave2" ); res = store_i128i128(current_receiver(), table_name, &dave3, sizeof(TestModel128x2)); - eos_assert(res == 1, "store dave3" ); - - return WASM_TEST_PASS; + eosio_assert(res == 1, "store dave3" ); + return res; } -unsigned int store_set_in_table(TestModel3xi64* records, int len, uint64_t table_name) { +void store_set_in_table(TestModel3xi64* records, int len, uint64_t table_name) { uint32_t res = 0; for( int i = 0; i < len; ++i ) { TestModel3xi64 *tmp = records+i; tmp->table = table_name; res = store_i64i64i64(current_receiver(), table_name, tmp, sizeof(TestModel3xi64)); - eos_assert(res == 1, "store_set_in_table" ); + eosio_assert(res == 1, "store_set_in_table" ); } - return res; } -#endif +//TODO fix things #if 0 - -unsigned int test_db::key_i64i64i64_general() { +void test_db::key_i64i64i64_general() { uint32_t res = 0; @@ -772,7 +752,7 @@ unsigned int test_db::key_i64i64i64_general() { eosio::print(msg, " : ", res, " a:", V.a, " b:", V.b, " c:", V.c, " t:", V.table, "inx:", uint64_t(I), " ("); \ eosio::print(BS(res == sizeof(V)), " ", BS(records[I].a == V.a), " ", BS(records[I].b == V.b), " ", BS(records[I].c == V.c), " => ", N(table2), ")\n"); \ } \ - eos_assert( res == sizeof(V) && records[I].a == V.a && records[I].b == V.b && \ + eosio_assert( res == sizeof(V) && records[I].a == V.a && records[I].b == V.b && \ records[I].c == V.c /*&& records[I].table == uint64_t(N(table2))*/, msg); #define LOAD_OK(I, O, T, INX, MSG) \ @@ -783,7 +763,7 @@ unsigned int test_db::key_i64i64i64_general() { #define LOAD_ER(I, O, T, MSG) \ {eosio::remove_reference::type tmp; my_memset(&tmp, 0, sizeof(tmp));tmp = V; \ res = LOAD(I, O, T, tmp); \ - eos_assert(res == -1, MSG)} + eosio_assert(res == -1, MSG)} #define FRONT_OK(I, O, T, INX, MSG) \ {eosio::remove_reference::type tmp; my_memset(&tmp, 0, sizeof(tmp));tmp = V; \ @@ -834,7 +814,7 @@ unsigned int test_db::key_i64i64i64_general() { eosio::remove_reference::type tmp = records[I[j]]; \ res = NEXT(I, i64i64i64, N(table2), tmp);\ if(j+1::type tmp = records[I[j]]; \ res = PREV(I, i64i64i64, N(table2), tmp);\ if(j>0){ TABLE1_ASSERT(I[j-1], tmp, "i64x3 PREV " #I " ok "); } \ - else { eos_assert(res == -1, "i64x3 PREV " #I " fail "); }\ + else { eosio_assert(res == -1, "i64x3 PREV " #I " fail "); }\ } while(--j>0); \ } @@ -888,7 +868,7 @@ unsigned int test_db::key_i64i64i64_general() { do { \ eosio::remove_reference::type tmp = records[j]; \ res = UPPER(I, i64i64i64, N(table2), tmp);\ - if(res == -1) { eos_assert(I##_ub[j]==-1,"i64x3 UPPER " #I " fail ") } \ + if(res == -1) { eosio_assert(I##_ub[j]==-1,"i64x3 UPPER " #I " fail ") } \ else { TABLE1_ASSERT(I##_ub[j], tmp, "i64x3 UPPER " #I " ok "); } \ } while(++j key + value bytes: 8 Bytes // 8 + 32 = 40 Bytes (not enough space) store_str(N(dblimits), N(dblstr), &key, 1, &value, 1); - return WASM_TEST_PASS; } -unsigned int test_db::key_str_under_limit() +void test_db::key_str_under_limit() { // assuming max memory: 5 MBytes // assuming row overhead: 16 Bytes @@ -1174,10 +1147,9 @@ unsigned int test_db::key_str_under_limit() store_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); } eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_str_available_space_exceed_limit() +void test_db::key_str_available_space_exceed_limit() { // key length: 30 bytes // value length: 16323 bytes @@ -1189,10 +1161,9 @@ unsigned int test_db::key_str_available_space_exceed_limit() char* value = static_cast(eosio::malloc(value_size)); store_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_str_another_under_limit() +void test_db::key_str_another_under_limit() { // 16K bytes remaining // key length: 30 bytes @@ -1222,11 +1193,9 @@ unsigned int test_db::key_str_another_under_limit() value = static_cast(eosio::realloc(value, value_size)); update_str(N(dblimits), N(dblstr), key, sizeof(key), value, value_size); eosio::free(value); - - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_setup_limit() +void test_db::key_i64_setup_limit() { // assuming max memory: 5M Bytes // assuming row overhead: 16 Bytes @@ -1242,19 +1211,17 @@ unsigned int test_db::key_i64_setup_limit() store_i64(N(dblimits), N(dbli64), (char*)value, value_size); } eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_min_exceed_limit() +void test_db::key_i64_min_exceed_limit() { // will allocate 8 + 32 Bytes // at 5M Byte limit, so cannot store anything uint64_t value = (uint64_t)-1; store_i64(N(dblimits), N(dbli64), (char*)&value, sizeof(uint64_t)); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_under_limit() +void test_db::key_i64_under_limit() { // updating keys' values // key length: 8 bytes @@ -1270,10 +1237,9 @@ unsigned int test_db::key_i64_under_limit() } // 262,144 Bytes remaining eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_available_space_exceed_limit() +void test_db::key_i64_available_space_exceed_limit() { // 262,144 Bytes remaining // key length: 8 bytes @@ -1285,10 +1251,9 @@ unsigned int test_db::key_i64_available_space_exceed_limit() value[0] = 1024 * 2; store_i64(N(dblimits), N(dbli64), (char*)value, value_size); eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64_another_under_limit() +void test_db::key_i64_another_under_limit() { // 262,144 Bytes remaining // key length: 8 bytes @@ -1320,11 +1285,9 @@ unsigned int test_db::key_i64_another_under_limit() // 32 Bytes remaining (smallest row entry is 40 Bytes) eosio::free(value); - - return WASM_TEST_PASS; } -unsigned int test_db::key_i128i128_setup_limit() +void test_db::key_i128i128_setup_limit() { // assuming max memory: 5M Bytes // assuming row overhead: 16 Bytes @@ -1341,10 +1304,9 @@ unsigned int test_db::key_i128i128_setup_limit() store_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); } eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i128i128_min_exceed_limit() +void test_db::key_i128i128_min_exceed_limit() { // will allocate 32 + 32 Bytes // at 5M Byte limit, so cannot store anything @@ -1353,10 +1315,9 @@ unsigned int test_db::key_i128i128_min_exceed_limit() value[0] = (uint128_t)-1; value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)&value, value_size); - return WASM_TEST_PASS; } -unsigned int test_db::key_i128i128_under_limit() +void test_db::key_i128i128_under_limit() { // updating keys' values // keys length: 32 bytes @@ -1373,10 +1334,9 @@ unsigned int test_db::key_i128i128_under_limit() } // 262,144 Bytes remaining eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i128i128_available_space_exceed_limit() +void test_db::key_i128i128_available_space_exceed_limit() { // 262,144 Bytes remaining // keys length: 32 bytes @@ -1389,10 +1349,9 @@ unsigned int test_db::key_i128i128_available_space_exceed_limit() value[1] = value[0] + 1; store_i128i128(N(dblimits), N(dbli128i128), (char*)value, value_size); eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i128i128_another_under_limit() +void test_db::key_i128i128_another_under_limit() { // 262,144 Bytes remaining // keys length: 32 bytes @@ -1428,10 +1387,9 @@ unsigned int test_db::key_i128i128_another_under_limit() eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64i64i64_setup_limit() +void test_db::key_i64i64i64_setup_limit() { // assuming max memory: 5M Bytes // assuming row overhead: 16 Bytes @@ -1449,10 +1407,9 @@ unsigned int test_db::key_i64i64i64_setup_limit() store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); } eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64i64i64_min_exceed_limit() +void test_db::key_i64i64i64_min_exceed_limit() { // will allocate 24 + 32 Bytes // at 5M Byte limit, so cannot store anything @@ -1462,10 +1419,9 @@ unsigned int test_db::key_i64i64i64_min_exceed_limit() value[1] = value[0] + 1; value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)&value, value_size); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64i64i64_under_limit() +void test_db::key_i64i64i64_under_limit() { // updating keys' values // keys length: 24 bytes @@ -1483,10 +1439,9 @@ unsigned int test_db::key_i64i64i64_under_limit() } // 262,144 Bytes remaining eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64i64i64_available_space_exceed_limit() +void test_db::key_i64i64i64_available_space_exceed_limit() { // 262,144 Bytes remaining // keys length: 24 bytes @@ -1500,10 +1455,9 @@ unsigned int test_db::key_i64i64i64_available_space_exceed_limit() value[2] = value[0] + 2; store_i64i64i64(N(dblimits), N(dbli64i64i64), (char*)value, value_size); eosio::free(value); - return WASM_TEST_PASS; } -unsigned int test_db::key_i64i64i64_another_under_limit() +void test_db::key_i64i64i64_another_under_limit() { // 262,144 Bytes remaining // keys length: 24 bytes @@ -1542,9 +1496,7 @@ unsigned int test_db::key_i64i64i64_another_under_limit() eosio::free(value); - return WASM_TEST_PASS; } - #endif void test_db::primary_i64_general() @@ -1896,3 +1848,4 @@ void test_db::idx64_upperbound() eosio_assert(ub == -1, err.c_str()); } } + diff --git a/contracts/test_api_mem/CMakeLists.txt b/contracts/test_api_mem/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e893b42eb404336a9311918f5b938461cd3cf09d --- /dev/null +++ b/contracts/test_api_mem/CMakeLists.txt @@ -0,0 +1,5 @@ +add_wast_executable( TARGET test_api_mem + INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" + LIBRARIES eosiolib + DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/contracts/test_api_mem/test_api_mem.cpp b/contracts/test_api_mem/test_api_mem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d511ef68e8f9738295745738b65f062450af289 --- /dev/null +++ b/contracts/test_api_mem/test_api_mem.cpp @@ -0,0 +1,41 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include "../test_api/test_api.hpp" + +#include "test_extended_memory.cpp" +#include "test_memory.cpp" + +extern "C" { + + void init() { + + } + + void apply( unsigned long long code, unsigned long long action ) { + + //eosio::print("==> CONTRACT: ", code, " ", action, "\n"); + + //test_extended_memory + WASM_TEST_HANDLER(test_extended_memory, test_initial_buffer); + WASM_TEST_HANDLER(test_extended_memory, test_page_memory); + WASM_TEST_HANDLER(test_extended_memory, test_page_memory_exceeded); + WASM_TEST_HANDLER(test_extended_memory, test_page_memory_negative_bytes); + + //test_memory + WASM_TEST_HANDLER(test_memory, test_memory_allocs); + WASM_TEST_HANDLER(test_memory, test_memory_hunk); + WASM_TEST_HANDLER(test_memory, test_memory_hunks); + WASM_TEST_HANDLER(test_memory, test_memory_hunks_disjoint); + WASM_TEST_HANDLER(test_memory, test_memset_memcpy); + WASM_TEST_HANDLER(test_memory, test_memcpy_overlap_start); + WASM_TEST_HANDLER(test_memory, test_memcpy_overlap_end); + WASM_TEST_HANDLER(test_memory, test_memcmp); + + //unhandled test call + eosio_assert(false, "Unknown Test"); + } + +} diff --git a/contracts/test_api_mem/test_extended_memory.cpp b/contracts/test_api_mem/test_extended_memory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d0ee354d0bfc74e362da0050eff00bde36bc607 --- /dev/null +++ b/contracts/test_api_mem/test_extended_memory.cpp @@ -0,0 +1,111 @@ +#include +#include +#include "../test_api/test_api.hpp" + +using namespace eosio; + +void verify( const void* const ptr, const uint32_t val, const uint32_t size) { + const char* char_ptr = (const char*)ptr; + for (uint32_t i = 0; i < size; ++i) + eosio_assert(static_cast(static_cast(char_ptr[i])) == val, "buffer slot doesn't match"); +} + +#define PRINT_PTR(x) prints("PTR : "); print((uint32_t)x, 4); prints("\n"); + +void test_extended_memory::test_page_memory() { + constexpr uint32_t _64K = 64*1024; + /* + * Test test_extended_memory::test_page_memory `ensure initial page size` + * Given I have not tried to increase the "program break" yet, + * when I call sbrk(0), then I should get the end of the first page, which should be 64K. + */ + auto prev = sbrk(0); + eosio_assert(reinterpret_cast(prev) == _64K, "Should initially have 1 64K page allocated"); + + /* + * Test test_extended_memory::test_page_memory `ensure sbrk returns previous end of program break` + * Given I have not tried to increase memory, + * when I call sbrk(1), then I should get the end of the first page, which should be 64K. + */ + prev = sbrk(1); + eosio_assert(reinterpret_cast(prev) == _64K, "Should still be pointing to the end of the 1st 64K page"); + + /* + * Test test_extended_memory::test_page_memory `ensure sbrk aligns allocations` + * Given that I allocated 1 byte via sbrk, + * when I call sbrk(2), then I should get 8 bytes past the previous end because of maintaining 8 byte alignment. + */ + prev = sbrk(2); + eosio_assert(reinterpret_cast(prev) == _64K+8, "Should point to 8 past the end of 1st 64K page"); + + /* + * Test test_extended_memory::test_page_memory `ensure sbrk aligns allocations 2` + * Given that I allocated 2 bytes via sbrk, + * when I call sbrk(_64K-17), then I should get 8 bytes past the previous end because of maintaining 8 byte alignment. + */ + prev = sbrk(_64K - 17); + eosio_assert(reinterpret_cast(prev) == _64K+16, "Should point to 16 past the end of the 1st 64K page"); + + prev = sbrk(1); + eosio_assert(reinterpret_cast(prev) == 2*_64K, "Should point to the end of the 2nd 64K page"); + + prev = sbrk(_64K); + eosio_assert(reinterpret_cast(prev) == 2*_64K+8, "Should point to 8 past the end of the 2nd 64K page"); + + prev = sbrk(_64K - 15); + eosio_assert(reinterpret_cast(prev) == 3*_64K+8, "Should point to 8 past the end of the 3rd 64K page"); + + prev = sbrk(2*_64K-1); + eosio_assert(reinterpret_cast(prev) == 4*_64K, "Should point to the end of the 4th 64K page"); + + prev = sbrk(2*_64K); + eosio_assert(reinterpret_cast(prev) == 6*_64K, "Should point to the end of the 6th 64K page"); + + prev = sbrk(2*_64K+1); + eosio_assert(reinterpret_cast(prev) == 8*_64K, "Should point to the end of the 8th 64K page"); + + prev = sbrk(6*_64K-15); + eosio_assert(reinterpret_cast(prev) == 10*_64K+8, "Should point to 8 past the end of the 10th 64K page"); + + prev = sbrk(0); + eosio_assert(reinterpret_cast(prev) == 16*_64K, "Should point to 8 past the end of the 16th 64K page"); +} + +void test_extended_memory::test_page_memory_exceeded() { + /* + * Test test_extended_memory::test_page_memory_exceeded `ensure sbrk won't allocation more than 1M of memory` + * Given that I have not tried to increase allocated memory, + * when I increase allocated memory with sbrk(15*64K), then I should get the end of the first page. + */ + auto prev = sbrk(15*64*1024); + eosio_assert(reinterpret_cast(prev) == 64*1024, "Should have allocated 1M of memory"); + + /* + * Test test_extended_memory::test_page_memory_exceeded `ensure sbrk won't allocation more than 1M of memory 2` + */ + prev = sbrk(0); + eosio_assert(reinterpret_cast(prev) == (1024*1024), "Should have allocated 1M of memory"); + sbrk(1); + eosio_assert(0, "Should have thrown exception for trying to allocate too much memory"); +} + +void test_extended_memory::test_page_memory_negative_bytes() { + sbrk(-1); + eosio_assert(0, "Should have thrown exception for trying to remove memory"); +} + +void test_extended_memory::test_initial_buffer() { + // initial buffer should be exhausted at 8192 bytes + // 8176 left ( 12 + ptr header ) + char* ptr1 = (char*)malloc(12); + eosio_assert(ptr1 != nullptr, "should have allocated 12 char buffer"); + + char* ptr2 = (char*)malloc(8159); + eosio_assert(ptr2 != nullptr, "should have allocate 8159 char buffer"); + + // should overrun initial heap, allocated in 2nd heap + char* ptr3 = (char*)malloc(20); + eosio_assert(ptr3 != nullptr, "should have allocated a 20 char buffer"); + verify(ptr3, 0, 20); + +} diff --git a/contracts/test_api_mem/test_memory.cpp b/contracts/test_api_mem/test_memory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..694aa64c77ffce9c177e5ca275375d89d5d7ce30 --- /dev/null +++ b/contracts/test_api_mem/test_memory.cpp @@ -0,0 +1,313 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +//#include +#include + +using namespace eosio; + +void verify_mem(const void* const ptr, const uint32_t val, const uint32_t size) +{ + const char* char_ptr = (const char*)ptr; + for (uint32_t i = 0; i < size; ++i) + { + eosio_assert(static_cast(static_cast(char_ptr[i])) == val, "buf slot doesn't match"); + } +} + +/* +void print(const void* const ptr, const uint32_t size) +{ + const char* char_ptr = (const char*)ptr; + eosio::print("\n{ "); + for (uint32_t i = 0; i < size; ++i) + { + const char* delim = (i % 8 == 7) ? ", " : " "; + eosio::print("", static_cast(static_cast(char_ptr[i])), delim); + } + eosio::print("}\n"); +} +*/ + +/* +* malloc and realloc always allocate on 8 byte boundaries based off of total allocation, so +* if the requested size + the 2 byte header is not divisible by 8, then the allocated space +* will be larger than the requested size +*/ +void test_memory::test_memory_allocs() +{ + char* ptr1 = (char*)malloc(0); + eosio_assert(ptr1 == nullptr, "should not have allocated a 0 char buf"); + + // 20 chars - 20 + 4(header) which is divisible by 8 + ptr1 = (char*)malloc(20); + eosio_assert(ptr1 != nullptr, "should have allocated a 20 char buf"); + verify_mem(ptr1, 0, 20); + // existing memory layout -> |24| + + // 36 chars allocated - 30 + 4 plus an extra 6 to be divisible by 8 + char* ptr1_realloc = (char*)realloc(ptr1, 30); + eosio_assert(ptr1_realloc != nullptr, "should have returned a 30 char buf"); + eosio_assert(ptr1_realloc == ptr1, "should have enlarged the 20 char buf"); + // existing memory layout -> |40| + + // 20 chars allocated + char* ptr2 = (char*)malloc(20); + eosio_assert(ptr2 != nullptr, "should have allocated another 20 char buf"); + eosio_assert(ptr1 + 36 < ptr2, "20 char buf should have been created after ptr1"); // test specific to implementation (can remove for refactor) + verify_mem(ptr1, 0, 36); + eosio_assert(ptr1[36] != 0, "should not have empty bytes following since block allocated"); // test specific to implementation (can remove for refactor) + // existing memory layout -> |40|24| + + //shrink the buffer + ptr1[14] = 0x7e; + // 20 chars allocated (still) + ptr1_realloc = (char*)realloc(ptr1, 15); + eosio_assert(ptr1_realloc != nullptr, "should have returned a 15 char buf"); + eosio_assert(ptr1_realloc == ptr1, "should have shrunk the reallocated 30 char buf"); + verify_mem(ptr1, 0, 14); // test specific to implementation (can remove for refactor) + eosio_assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched"); + // existing memory layout -> |24(shrunk)|16(freed)|24| + + //same size the buffer (verify corner case) + // 20 chars allocated (still) + ptr1_realloc = (char*)realloc(ptr1, 15); + eosio_assert(ptr1_realloc != nullptr, "should have returned a reallocated 15 char buf"); + eosio_assert(ptr1_realloc == ptr1, "should have reallocated 15 char buf as the same buf"); + eosio_assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for unchanged buf"); + + //same size as max allocated buffer -- test specific to implementation (can remove for refactor) + ptr1_realloc = (char*)realloc(ptr1, 30); + eosio_assert(ptr1_realloc != nullptr, "should have returned a 30 char buf"); + eosio_assert(ptr1_realloc == ptr1, "should have increased the buf back to orig max"); //test specific to implementation (can remove for refactor) + eosio_assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for expanded buf"); + + //increase buffer beyond (indicated) allocated space + // 36 chars allocated (still) + ptr1_realloc = (char*)realloc(ptr1, 36); + eosio_assert(ptr1_realloc != nullptr, "should have returned a 36 char buf"); + eosio_assert(ptr1_realloc == ptr1, "should have increased char buf to actual size"); // test specific to implementation (can remove for refactor) + + //increase buffer beyond allocated space + ptr1[35] = 0x7f; + // 44 chars allocated - 37 + 4 plus an extra 7 to be divisible by 8 + ptr1_realloc = (char*)realloc(ptr1, 37); + eosio_assert(ptr1_realloc != nullptr, "should have returned a 37 char buf"); + eosio_assert(ptr1_realloc != ptr1, "should have had to create new 37 char buf from 36 char buf"); + eosio_assert(ptr2 < ptr1_realloc, "should have been created after ptr2"); // test specific to implementation (can remove for refactor) + eosio_assert(ptr1_realloc[14] == 0x7e, "orig 36 char buf's content should be copied"); + eosio_assert(ptr1_realloc[35] == 0x7f, "orig 36 char buf's content should be copied"); + + //realloc with nullptr + char* nullptr_realloc = (char*)realloc(nullptr, 50); + eosio_assert(nullptr_realloc != nullptr, "should have returned a 50 char buf and ignored nullptr"); + eosio_assert(ptr1_realloc < nullptr_realloc, "should have created after ptr1_realloc"); // test specific to implementation (can remove for refactor) + + //realloc with invalid ptr + char* invalid_ptr_realloc = (char*)realloc(nullptr_realloc + 4, 10); + eosio_assert(invalid_ptr_realloc != nullptr, "should have returned a 10 char buf and ignored invalid ptr"); + eosio_assert(nullptr_realloc < invalid_ptr_realloc, "should have created invalid_ptr_realloc after nullptr_realloc"); // test specific to implementation (can remove for refactor) +} + +// this test verifies that malloc can allocate 15 64K pages and treat them as one big heap space (if sbrk is not called in the mean time) +void test_memory::test_memory_hunk() +{ + // try to allocate the largest buffer we can, which is 15 contiguous 64K pages (with the 4 char space for the ptr header) + char* ptr1 = (char*)malloc(15 * 64 * 1024 - 4); + eosio_assert(ptr1 != nullptr, "should have allocated a ~983K char buf"); +} + +void test_memory::test_memory_hunks() +{ + // leave 784 bytes of initial buffer to allocate later (rounds up to nearest 8 byte boundary, + // 16 bytes bigger than remainder left below in 15 64K page heap)) + char* ptr1 = (char*)malloc(7404); + eosio_assert(ptr1 != nullptr, "should have allocated a 7404 char buf"); + + char* last_ptr = nullptr; + // 96 * (10 * 1024 - 15) => 15 ~64K pages with 768 byte buffer left to allocate + for (int i = 0; i < 96; ++i) + { + char* ptr2 = (char*)malloc(10 * 1024 - 15); + eosio_assert(ptr2 != nullptr, "should have allocated a ~10K char buf"); + if (last_ptr != nullptr) + { + // - 15 rounds to -8 + eosio_assert(last_ptr + 10 * 1024 - 8 == ptr2, "should allocate the very next ptr"); // test specific to implementation (can remove for refactor) + } + + last_ptr = ptr2; + } + + // try to allocate a buffer slightly larger than the remaining buffer| 765 + 4 rounds to 776 + char* ptr3 = (char*)malloc(765); + eosio_assert(ptr3 != nullptr, "should have allocated a 772 char buf"); + eosio_assert(ptr1 + 7408 == ptr3, "should allocate the very next ptr after ptr1 in initial heap"); // test specific to implementation (can remove for refactor) + + // use all but 8 chars + char* ptr4 = (char*)malloc(764); + eosio_assert(ptr4 != nullptr, "should have allocated a 764 char buf"); + eosio_assert(last_ptr + 10 * 1024 - 8 == ptr4, "should allocate the very next ptr after last_ptr at end of contiguous heap"); // test specific to implementation (can remove for refactor) + + // use up remaining 8 chars + char* ptr5 = (char*)malloc(4); + eosio_assert(ptr5 != nullptr, "should have allocated a 4 char buf"); + eosio_assert(ptr3 + 776 == ptr5, "should allocate the very next ptr after ptr3 in initial heap"); // test specific to implementation (can remove for refactor) + + // nothing left to allocate + char* ptr6 = (char*)malloc(4); + eosio_assert(ptr6 == nullptr, "should not have allocated a char buf"); +} + +void test_memory::test_memory_hunks_disjoint() +{ + // leave 8 bytes of initial buffer to allocate later + char* ptr1 = (char*)malloc(8 * 1024 - 12); + eosio_assert(ptr1 != nullptr, "should have allocated a 8184 char buf"); + + // can only make 14 extra (64K) heaps for malloc, since calls to sbrk will eat up part + char* loop_ptr1[14]; + // 14 * (64 * 1024 - 28) => 14 ~64K pages with each page having 24 bytes left to allocate + for (int i = 0; i < 14; ++i) + { + // allocates a new heap for each request, since sbrk call doesn't allow contiguous heaps to grow + loop_ptr1[i] = (char*)malloc(64 * 1024 - 28); + eosio_assert(loop_ptr1[i] != nullptr, "should have allocated a 64K char buf"); + + eosio_assert(sbrk(4) != nullptr, "should be able to allocate 8 bytes"); + } + + // the 15th extra heap is reduced in size because of the 14 * 8 bytes allocated by sbrk calls + // will leave 8 bytes to allocate later (verifying that we circle back in the list + char* ptr2 = (char*)malloc(65412); + eosio_assert(ptr2 != nullptr, "should have allocated a 65412 char buf"); + + char* loop_ptr2[14]; + for (int i = 0; i < 14; ++i) + { + // 12 char buffer to leave 8 bytes for another pass + loop_ptr2[i] = (char*)malloc(12); + eosio_assert(loop_ptr2[i] != nullptr, "should have allocated a 12 char buf"); + eosio_assert(loop_ptr1[i] + 64 * 1024 - 24 == loop_ptr2[i], "loop_ptr2[i] should be very next pointer after loop_ptr1[i]"); + } + + // this shows that searching for free ptrs starts at the last loop to find free memory, not at the begining + char* ptr3 = (char*)malloc(4); + eosio_assert(ptr3 != nullptr, "should have allocated a 4 char buf"); + eosio_assert(loop_ptr2[13] + 16 == ptr3, "should allocate the very next ptr after loop_ptr2[13]"); // test specific to implementation (can remove for refactor) + + char* ptr4 = (char*)malloc(4); + eosio_assert(ptr4 != nullptr, "should have allocated a 4 char buf"); + eosio_assert(ptr2 + 65416 == ptr4, "should allocate the very next ptr after ptr2 in last heap"); // test specific to implementation (can remove for refactor) + + char* ptr5 = (char*)malloc(4); + eosio_assert(ptr5 != nullptr, "should have allocated a 4 char buf"); + eosio_assert(ptr1 + 8184 == ptr5, "should allocate the very next ptr after ptr1 in last heap"); // test specific to implementation (can remove for refactor) + + // will eat up remaining memory (14th heap already used up) + char* loop_ptr3[13]; + for (int i = 0; i < 13; ++i) + { + // 4 char buffer to use up buffer + loop_ptr3[i] = (char*)malloc(4); + eosio_assert(loop_ptr3[i] != nullptr, "should have allocated a 4 char buf"); + eosio_assert(loop_ptr2[i] + 16 == loop_ptr3[i], "loop_ptr3[i] should be very next pointer after loop_ptr2[i]"); + } + + char* ptr6 = (char*)malloc(4); + eosio_assert(ptr6 == nullptr, "should not have allocated a char buf"); + + free(loop_ptr1[3]); + free(loop_ptr2[3]); + free(loop_ptr3[3]); + + char* slot3_ptr[64]; + for (int i = 0; i < 64; ++i) + { + slot3_ptr[i] = (char*)malloc(1020); + eosio_assert(slot3_ptr[i] != nullptr, "should have allocated a 1020 char buf"); + if (i == 0) + eosio_assert(loop_ptr1[3] == slot3_ptr[0], "loop_ptr1[3] should be very next pointer after slot3_ptr[0]"); + else + eosio_assert(slot3_ptr[i - 1] + 1024 == slot3_ptr[i], "slot3_ptr[i] should be very next pointer after slot3_ptr[i-1]"); + } + + char* ptr7 = (char*)malloc(4); + eosio_assert(ptr7 == nullptr, "should not have allocated a char buf"); +} + +void test_memory::test_memset_memcpy() +{ + char buf1[40] = {}; + char buf2[40] = {}; + + verify_mem(buf1, 0, 40); + verify_mem(buf2, 0, 40); + + memset(buf1, 0x22, 20); + verify_mem(buf1, 0x22, 20); + verify_mem(&buf1[20], 0, 20); + + memset(&buf2[20], 0xff, 20); + verify_mem(buf2, 0, 20); + verify_mem(&buf2[20], 0xff, 20); + + memcpy(&buf1[10], &buf2[10], 20); + verify_mem(buf1, 0x22, 10); + verify_mem(&buf1[10], 0, 10); + verify_mem(&buf1[20], 0xff, 10); + verify_mem(&buf1[30], 0, 10); + + memset(&buf1[1], 1, 1); + verify_mem(buf1, 0x22, 1); + verify_mem(&buf1[1], 1, 1); + verify_mem(&buf1[2], 0x22, 8); + + // verify adjacent non-overlapping buffers + char buf3[50] = {}; + memset(&buf3[25], 0xee, 25); + verify_mem(buf3, 0, 25); + memcpy(buf3, &buf3[25], 25); + verify_mem(buf3, 0xee, 50); + + memset(buf3, 0, 25); + verify_mem(&buf3[25], 0xee, 25); + memcpy(&buf3[25], buf3, 25); + verify_mem(buf3, 0, 50); +} + +void test_memory::test_memcpy_overlap_start() +{ + char buf3[99] = {}; + memset(buf3, 0xee, 50); + memset(&buf3[50], 0xff, 49); + memcpy(&buf3[49], buf3, 50); +} + + +void test_memory::test_memcpy_overlap_end() +{ + char buf3[99] = {}; + memset(buf3, 0xee, 50); + memset(&buf3[50], 0xff, 49); + memcpy(buf3, &buf3[49], 50); +} + +void test_memory::test_memcmp() +{ + char buf1[] = "abcde"; + char buf2[] = "abcde"; + int32_t res1 = memcmp(buf1, buf2, 6); + eosio_assert(res1 == 0, "first data should be equal to second data"); + + char buf3[] = "abcde"; + char buf4[] = "fghij"; + int32_t res2 = memcmp(buf3, buf4, 6); + eosio_assert(res2 < 0, "first data should be smaller than second data"); + + char buf5[] = "fghij"; + char buf6[] = "abcde"; + int32_t res3 = memcmp(buf5, buf6, 6); + eosio_assert(res3 > 0, "first data should be larger than second data"); +} diff --git a/eosio_build.sh b/eosio_build.sh index a05b8cc1518ebc080d1eb32987c0cc1b2e12c57e..8c62bbaea5c58ab39415f798de5889be4bbb3b9b 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -69,6 +69,12 @@ CXX_COMPILER=g++ C_COMPILER=gcc ;; + "Amazon Linux AMI") + FILE=${WORK_DIR}/scripts/eosio_build_amazon.sh + CMAKE=${HOME}/opt/cmake/bin/cmake + CXX_COMPILER=g++ + C_COMPILER=gcc + ;; *) printf "\n\tUnsupported Linux Distribution. Exiting now.\n\n" exit 1 @@ -85,8 +91,8 @@ fi if [ $ARCH == "Darwin" ]; then - OPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1 - OPENSSL_LIBRARIES=/usr/local/opt/openssl@1.1/lib + OPENSSL_ROOT_DIR=/usr/local/opt/openssl + OPENSSL_LIBRARIES=/usr/local/opt/openssl/lib BINARYEN_BIN=/usr/local/binaryen/bin/ WASM_LLVM_CONFIG=/usr/local/wasm/bin/llvm-config CXX_COMPILER=clang++ @@ -109,8 +115,12 @@ mkdir -p ${BUILD_DIR} cd ${BUILD_DIR} + if [ -z $CMAKE ]; then + CMAKE=$( which cmake ) + fi + # Build EOS - cmake -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ + $CMAKE -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ -DCMAKE_C_COMPILER=${C_COMPILER} -DWASM_LLVM_CONFIG=${WASM_LLVM_CONFIG} \ -DBINARYEN_BIN=${BINARYEN_BIN} -DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR} \ -DOPENSSL_LIBRARIES=${OPENSSL_LIBRARIES} .. @@ -119,7 +129,7 @@ exit -1 fi - make -j$(nproc) VERBOSE=1 + make -j${CPU_CORE} VERBOSE=0 if [ $? -ne 0 ]; then printf "\n\t>>>>>>>>>>>>>>>>>>>> MAKE building EOSIO has exited with the above error.\n\n" diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 244484a53fac0fbc2e46e221ff3bbc8aa925b747..4f3323a1b5e8859aa9acbc17ac82ded02646f6cd 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -102,7 +102,8 @@ 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); + EOS_ASSERT( recurse_depth < config::max_recursion_depth, transaction_exception, "inline action recursion depth reached" ); + apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta, recurse_depth + 1 ); ncontext.exec(); append_results(move(ncontext.results)); } @@ -116,6 +117,7 @@ bool apply_context::is_account( const account_name& account )const { void apply_context::require_authorization( const account_name& account )const { for( const auto& auth : act.authorization ) if( auth.actor == account ) return; + wdump((act)); EOS_ASSERT( false, tx_missing_auth, "missing authority of ${account}", ("account",account)); } void apply_context::require_authorization(const account_name& account, @@ -304,6 +306,45 @@ void apply_context::update_db_usage( const account_name& payer, int64_t delta ) } +int apply_context::get_action( uint32_t type, uint32_t index, char* buffer, size_t buffer_size )const +{ + const transaction& trx = trx_meta.trx(); + const action* act = nullptr; + if( type == 0 ) { + if( index >= trx.context_free_actions.size() ) + return -1; + act = &trx.context_free_actions[index]; + } + else if( type == 1 ) { + if( index >= trx.actions.size() ) + return -1; + act = &trx.actions[index]; + } + + auto ps = fc::raw::pack_size( *act ); + if( ps <= buffer_size ) { + fc::datastream ds(buffer, buffer_size); + fc::raw::pack( ds, *act ); + } + return ps; +} + +int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const { + if( index >= trx_meta.context_free_data.size() ) return -1; + + auto s = trx_meta.context_free_data[index].size(); + + if( buffer_size == 0 ) return s; + + if( buffer_size < s ) + memcpy( buffer, trx_meta.context_free_data.data(), buffer_size ); + else + memcpy( buffer, trx_meta.context_free_data.data(), s ); + + return s; +} + + int apply_context::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( receiver, scope, table ); diff --git a/libraries/chain/block.cpp b/libraries/chain/block.cpp index 975d920876f710b9a4a0c090ea6cc84cea467cef..06264101a3233d846e516df51e1662ee5c1a8124 100644 --- a/libraries/chain/block.cpp +++ b/libraries/chain/block.cpp @@ -42,9 +42,9 @@ namespace eosio { namespace chain { return signee() == expected_signee; } - checksum_type signed_block_summary::calculate_transaction_mroot()const + checksum256_type signed_block_summary::calculate_transaction_mroot()const { - return checksum_type();// TODO ::hash(merkle(ids)); + return checksum256_type();// TODO ::hash(merkle(ids)); } digest_type signed_block::calculate_transaction_merkle_root()const { diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index b70a606e14606a0c09496cb3c5c5eac8a09359ba..785a3c1da61f1f4be8fbc8d49a92297c4a46b89c 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -34,7 +34,6 @@ #include #include -#include #include namespace eosio { namespace chain { @@ -48,9 +47,9 @@ uint32_t chain_controller::blocks_per_round()const { } 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), +:_db( cfg.shared_memory_dir, + (cfg.read_only ? database::read_only : database::read_write), + cfg.shared_memory_size), _block_log(cfg.block_log_dir), _limits(cfg.limits) { @@ -154,7 +153,7 @@ std::vector chain_controller::get_block_ids_on_fork(block_id_type */ void chain_controller::push_block(const signed_block& new_block, uint32_t skip) { try { - with_skip_flags( skip, [&](){ + with_skip_flags( skip, [&](){ return without_pending_transactions( [&]() { return _db.with_write_lock( [&]() { return _push_block(new_block); @@ -255,11 +254,10 @@ 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); - auto result = _push_transaction(std::move(mtrx)); // notify anyone listening to pending transactions - on_pending_transaction(trx); + on_pending_transaction(_pending_transaction_metas.back(), trx); _pending_block->input_transactions.emplace_back(trx); @@ -458,11 +456,11 @@ signed_block chain_controller::generate_block( }); } FC_CAPTURE_AND_RETHROW( (when) ) } -signed_block chain_controller::_generate_block( block_timestamp_type when, - account_name producer, +signed_block chain_controller::_generate_block( block_timestamp_type when, + account_name producer, const private_key_type& block_signing_key ) { try { - + try { uint32_t skip = _skip_flags; uint32_t slot_num = get_slot_at_time( when ); @@ -586,7 +584,7 @@ void chain_controller::__apply_block(const signed_block& next_block) uint32_t skip = _skip_flags; /* - FC_ASSERT((skip & skip_merkle_check) + FC_ASSERT((skip & skip_merkle_check) || next_block.transaction_merkle_root == next_block.calculate_merkle_root(), "", ("next_block.transaction_merkle_root", next_block.transaction_merkle_root) ("calc",next_block.calculate_merkle_root())("next_block",next_block)("id",next_block.id())); @@ -771,13 +769,13 @@ void chain_controller::check_authorization( const vector& actions, if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false) EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig, - "transaction bears irrelevant signatures from these keys: ${keys}", + "transaction bears irrelevant signatures from these keys: ${keys}", ("keys", checker.unused_keys())); } void chain_controller::check_transaction_authorization(const transaction& trx, const vector& signatures, - bool allow_unused_signatures)const + bool allow_unused_signatures)const { check_authorization( trx.actions, trx.get_signature_keys( signatures, chain_id_type{} ), allow_unused_signatures ); } @@ -819,7 +817,7 @@ void chain_controller::validate_uniqueness( const transaction& trx )const { void chain_controller::record_transaction(const transaction& trx) { //Insert transaction into unique transactions database. _db.create([&](transaction_object& transaction) { - transaction.trx_id = trx.id(); + transaction.trx_id = trx.id(); transaction.expiration = trx.expiration; }); } @@ -836,8 +834,8 @@ void chain_controller::validate_tapos(const transaction& trx)const { ("tapos_summary", tapos_block_summary)); } -void chain_controller::validate_referenced_accounts( const transaction& trx )const -{ try { +void chain_controller::validate_referenced_accounts( const transaction& trx )const +{ try { for( const auto& act : trx.actions ) { require_account(act.account); for (const auto& auth : act.authorization ) @@ -890,7 +888,7 @@ const producer_object& chain_controller::validate_block_header(uint32_t skip, co EOS_ASSERT(!next_block.new_producers, block_validate_exception, "Producer changes may only occur at the end of a round."); } - + const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp))); if(!(skip&skip_producer_signature)) @@ -904,7 +902,7 @@ const producer_object& chain_controller::validate_block_header(uint32_t skip, co ("block producer",next_block.producer)("scheduled producer",producer.owner)); } - + return producer; } @@ -917,7 +915,7 @@ void chain_controller::create_block_summary(const signed_block& next_block) { /** * Takes the top config::producer_count producers by total vote excluding any producer whose - * block_signing_key is null. + * block_signing_key is null. */ producer_schedule_type chain_controller::_calculate_producer_schedule()const { producer_schedule_type schedule = get_global_properties().new_active_producers; @@ -934,7 +932,7 @@ producer_schedule_type chain_controller::_calculate_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() ) + if( gpo.pending_active_producers.size() ) return gpo.pending_active_producers.back().second; return gpo.active_producers; } @@ -973,13 +971,13 @@ void chain_controller::update_global_properties(const signed_block& b) { try { active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1}); } - auto& po = _db.get( boost::make_tuple(config::producers_account_name, + auto& po = _db.get( boost::make_tuple(config::producers_account_name, config::active_name ) ); _db.modify(po,[active_producers_authority] (permission_object& po) { po.auth = active_producers_authority; }); } -} FC_CAPTURE_AND_RETHROW() } +} FC_CAPTURE_AND_RETHROW() } void chain_controller::add_checkpoints( const flat_map& checkpts ) { for (const auto& i : checkpts) @@ -1019,12 +1017,12 @@ account_name chain_controller::head_block_producer() const { return {}; } -const producer_object& chain_controller::get_producer(const account_name& owner_name) const +const producer_object& chain_controller::get_producer(const account_name& owner_name) const { try { return _db.get(owner_name); } FC_CAPTURE_AND_RETHROW( (owner_name) ) } -const permission_object& chain_controller::get_permission( const permission_level& level )const +const permission_object& chain_controller::get_permission( const permission_level& level )const { try { return _db.get( boost::make_tuple(level.actor,level.permission) ); } FC_CAPTURE_AND_RETHROW( (level) ) } @@ -1167,7 +1165,7 @@ ProducerRound chain_controller::calculate_next_round(const signed_block& next_bl EOS_ASSERT(boost::range::equal(next_block.producer_changes, changes), block_validate_exception, "Unexpected round changes in new block header", ("expected changes", changes)("block changes", next_block.producer_changes)); - + fc::time_point tp = (fc::time_point)next_block.timestamp; utilities::rand::random rng(tp.sec_since_epoch()); rng.shuffle(schedule); @@ -1229,7 +1227,7 @@ void chain_controller::update_global_dynamic_data(const signed_block& b) { dgp.recent_slots_filled = uint64_t(-1); else dgp.recent_slots_filled = 0; - dgp.block_merkle_root.append( head_block_id() ); + dgp.block_merkle_root.append( head_block_id() ); }); _fork_db.set_max_size( _dgp.head_block_number - _dgp.last_irreversible_block_num + 1 ); @@ -1247,6 +1245,17 @@ void chain_controller::update_signing_producer(const producer_object& signing_pr } ); } +void chain_controller::update_or_create_producers( const producer_schedule_type& producers ) { + for ( auto prod : producers.producers ) { + if ( _db.find(prod.producer_name) == nullptr ) { + _db.create( [&]( auto& pro ) { + pro.owner = prod.producer_name; + pro.signing_key = prod.block_signing_key; + }); + } + } +} + void chain_controller::update_last_irreversible_block() { const global_property_object& gpo = get_global_properties(); @@ -1255,7 +1264,7 @@ 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(), + 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); }); @@ -1308,6 +1317,7 @@ void chain_controller::update_last_irreversible_block() } } if( new_producer_schedule ) { + update_or_create_producers( *new_producer_schedule ); _db.modify( gpo, [&]( auto& props ){ boost::range::remove_erase_if(props.pending_active_producers, [new_last_irreversible_block_num](const typename decltype(props.pending_active_producers)::value_type& v) -> bool { @@ -1352,7 +1362,6 @@ account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const 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; @@ -1406,9 +1415,23 @@ 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().context_free_actions) { + FC_ASSERT( act.authorization.size() == 0, "context free actions cannot require authorization" ); + apply_context context(*this, _db, act, meta); + context.context_free = true; + context.exec(); + fc::move_append(result.action_traces, std::move(context.results.applied_actions)); + FC_ASSERT( result.deferred_transactions.size() == 0 ); + FC_ASSERT( result.canceled_deferred.size() == 0 ); + } + for (const auto &act : meta.trx().actions) { apply_context context(*this, _db, act, meta); context.exec(); + context.used_context_free_api |= act.authorization.size(); + + FC_ASSERT( context.used_context_free_api, "action did not reference database state, it should be moved to context_free_actions", ("act",act) ); fc::move_append(result.action_traces, std::move(context.results.applied_actions)); fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions)); fc::move_append(result.canceled_deferred, std::move(context.results.canceled_deferred)); @@ -1569,7 +1592,7 @@ void chain_controller::update_usage( transaction_metadata& meta, uint32_t act_us 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; - + if( !(_skip_flags & genesis_setup) ) { #warning TODO: restore bandwidth checks /* setting of bandwidth currently not implemented @@ -1618,7 +1641,7 @@ const apply_handler* chain_controller::find_apply_handler( account_name receiver auto native_handler_scope = _apply_handlers.find( receiver ); if( native_handler_scope != _apply_handlers.end() ) { auto handler = native_handler_scope->second.find( make_pair( scope, act ) ); - if( handler != native_handler_scope->second.end() ) + if( handler != native_handler_scope->second.end() ) return &handler->second; } return nullptr; diff --git a/libraries/chain/contracts/abi_serializer.cpp b/libraries/chain/contracts/abi_serializer.cpp index 768891341614f7030a7ae0c25a1649e83a24ef6c..71639bcaf1c76ad8a1f7fdaefb85626f99d9b63e 100644 --- a/libraries/chain/contracts/abi_serializer.cpp +++ b/libraries/chain/contracts/abi_serializer.cpp @@ -63,7 +63,9 @@ namespace eosio { namespace chain { namespace contracts { built_in_types.emplace("string", pack_unpack()); built_in_types.emplace("time", pack_unpack()); built_in_types.emplace("signature", pack_unpack()); - built_in_types.emplace("checksum", pack_unpack()); + built_in_types.emplace("checksum160", pack_unpack()); + built_in_types.emplace("checksum256", pack_unpack()); + built_in_types.emplace("checksum512", pack_unpack()); built_in_types.emplace("field_name", pack_unpack()); built_in_types.emplace("fixed_string32", pack_unpack()); built_in_types.emplace("fixed_string16", pack_unpack()); diff --git a/libraries/chain/include/eosio/chain/account_object.hpp b/libraries/chain/include/eosio/chain/account_object.hpp index d0ea6b9d21850f532ccf78829ab792fed8ef51ac..403c99c19826b34473759d4a9424c71265bb22dd 100644 --- a/libraries/chain/include/eosio/chain/account_object.hpp +++ b/libraries/chain/include/eosio/chain/account_object.hpp @@ -36,6 +36,13 @@ namespace eosio { namespace chain { fc::datastream ds( abi.data(), abi.size() ); fc::raw::pack( ds, a ); } + + eosio::chain::contracts::abi_def get_abi()const { + eosio::chain::contracts::abi_def a; + fc::datastream ds( abi.data(), abi.size() ); + fc::raw::unpack( ds, a ); + return a; + } }; using account_id_type = account_object::id_type; diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index b7d2f935e691a74dd1e537ee2a5864b09aad943f..170e1d2ea31f290f19d3f10a28717a589aaff8b3 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -292,7 +292,7 @@ class apply_context { - apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta) + apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta, uint32_t depth=0) :controller(con), db(db), @@ -302,7 +302,8 @@ class apply_context { used_authorizations(act.authorization.size(), false), trx_meta(trx_meta), idx64(*this), - idx128(*this) + idx128(*this), + recurse_depth(depth) {} void exec(); @@ -327,6 +328,7 @@ class apply_context { template int32_t load_record( const table_id_object& t_id, typename IndexType::value_type::key_type* keys, char* value, size_t valuelen ); + template int32_t front_record( const table_id_object& t_id, typename IndexType::value_type::key_type* keys, char* value, size_t valuelen ); @@ -387,7 +389,9 @@ 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; + bool privileged = false; + bool context_free = false; + bool used_context_free_api = false; chain_controller& mutable_controller; chainbase::database& mutable_db; @@ -423,6 +427,9 @@ class apply_context { void checktime(uint32_t instruction_count) const; + int get_action( uint32_t type, uint32_t index, char* buffer, size_t buffer_size )const; + int get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const; + void update_db_usage( const account_name& payer, int64_t delta ); int db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); void db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ); @@ -436,6 +443,7 @@ class apply_context { generic_index idx64; generic_index idx128; + uint32_t recurse_depth; // how deep inline actions can recurse private: iterator_cache keyval_cache; @@ -635,7 +643,6 @@ using apply_handler = std::function; const auto* obj = db.find(tuple); if( obj ) { - mutable_db.modify( *obj, [&]( auto& o ) { o.value.assign(value, valuelen); }); @@ -700,7 +707,6 @@ using apply_handler = std::function; !impl::record_scope_compare::compare(*itr, keys)) return -1; impl::key_helper::get(keys, *itr); - if (valuelen) { auto copylen = std::min(itr->value.size(), valuelen); if (copylen) { @@ -712,7 +718,7 @@ using apply_handler = std::function; } } - template + template int32_t apply_context::front_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 ); validate_table_key(t_id, get_key_type()); @@ -821,7 +827,7 @@ using apply_handler = std::function; auto pitr = pidx.find(tuple); if(pitr == pidx.end()) - return -1; + return 0; const auto& fidx = db.get_index(); auto itr = fidx.indicies().template project(pitr); @@ -831,11 +837,11 @@ using apply_handler = std::function; if( itr == idx.end() || itr == idx.begin() || itr->t_id != t_id.id || - !impl::key_helper::compare(*itr, keys) ) return -1; + !impl::key_helper::compare(*itr, keys) ) return 0; --itr; - if( itr->t_id != t_id.id ) return -1; + if( itr->t_id != t_id.id ) return 0; impl::key_helper::get(keys, *itr); @@ -860,7 +866,7 @@ using apply_handler = std::function; auto itr = idx.lower_bound(tuple); if( itr == idx.end() || - itr->t_id != t_id.id) return -1; + itr->t_id != t_id.id) return 0; impl::key_helper::get(keys, *itr); @@ -885,7 +891,7 @@ using apply_handler = std::function; auto itr = idx.upper_bound(tuple); if( itr == idx.end() || - itr->t_id != t_id.id ) return -1; + itr->t_id != t_id.id ) return 0; impl::key_helper::get(keys, *itr); diff --git a/libraries/chain/include/eosio/chain/block.hpp b/libraries/chain/include/eosio/chain/block.hpp index fa613ee86650b2d11abe9a28c558e63629b84eb9..34bdfe8272bd2a1766326864738aa7fb9f9fea63 100644 --- a/libraries/chain/include/eosio/chain/block.hpp +++ b/libraries/chain/include/eosio/chain/block.hpp @@ -18,9 +18,9 @@ namespace eosio { namespace chain { block_id_type previous; block_timestamp_type timestamp; - checksum_type transaction_mroot; /// mroot of cycles_summary - checksum_type action_mroot; - checksum_type block_mroot; + checksum256_type transaction_mroot; /// mroot of cycles_summary + checksum256_type action_mroot; + checksum256_type block_mroot; account_name producer; /** @@ -81,26 +81,26 @@ namespace eosio { namespace chain { * * The primary purpose of a block is to define the order in which messages are processed. * - * The secodnary purpose of a block is certify that the messages are valid according to + * The secodnary purpose of a block is certify that the messages are valid according to * a group of 3rd party validators (producers). * * The next purpose of a block is to enable light-weight proofs that a transaction occured * and was considered valid. * * The next purpose is to enable code to generate messages that are certified by the - * producers to be authorized. + * producers to be authorized. * * A block is therefore defined by the ordered set of executed and generated transactions, * and the merkle proof is over set of messages delivered as a result of executing the - * transactions. + * transactions. * * A message is defined by { receiver, code, function, permission, data }, the merkle * tree of a block should be generated over a set of message IDs rather than a set of - * transaction ids. + * transaction ids. */ struct signed_block_summary : public signed_block_header { vector regions; - checksum_type calculate_transaction_mroot()const; + checksum256_type calculate_transaction_mroot()const; }; /** @@ -109,9 +109,16 @@ namespace eosio { namespace chain { * what would be logged to disk to enable the regeneration of blockchain state. * * The transactions are grouped to mirror the cycles in block_summary, generated - * transactions are not included. + * transactions are not included. */ struct signed_block : public signed_block_summary { + signed_block () = default; + signed_block (const signed_block& ) = default; + signed_block (const signed_block_summary& base) + :signed_block_summary (base), + input_transactions() + {} + digest_type calculate_transaction_merkle_root()const; vector input_transactions; /// this is loaded and indexed into map that is referenced by summary }; diff --git a/libraries/chain/include/eosio/chain/chain_controller.hpp b/libraries/chain/include/eosio/chain/chain_controller.hpp index 09b17509f0fa4cce9cd18c3fe3e7863909ce3997..c7e125dec10636bd515ad9b00531353e487767c1 100644 --- a/libraries/chain/include/eosio/chain/chain_controller.hpp +++ b/libraries/chain/include/eosio/chain/chain_controller.hpp @@ -110,7 +110,7 @@ namespace eosio { namespace chain { * This signal is emitted any time a new transaction is added to the pending * block state. */ - signal on_pending_transaction; + signal on_pending_transaction; @@ -128,7 +128,7 @@ namespace eosio { namespace chain { */ 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; + uint32_t blocks_per_round()const; chain_id_type get_chain_id()const { return chain_id_type(); } /// TODO: make this hash of constitution @@ -215,7 +215,7 @@ namespace eosio { namespace chain { clear_pending(); /** after applying f() push previously input transactions on top */ - auto on_exit = fc::make_scoped_exit( [&](){ + auto on_exit = fc::make_scoped_exit( [&](){ for( auto& t : old_input ) { try { if (!is_known_transaction(t.id)) @@ -366,7 +366,7 @@ namespace eosio { namespace chain { validate_tapos(trx); } FC_CAPTURE_AND_RETHROW( (trx) ) } - + /// Validate transaction helpers @{ void validate_uniqueness(const transaction& trx)const; void validate_tapos(const transaction& trx)const; @@ -402,6 +402,7 @@ namespace eosio { namespace chain { void update_usage( transaction_metadata&, uint32_t act_usage ); void update_signing_producer(const producer_object& signing_producer, const signed_block& new_block); void update_last_irreversible_block(); + void update_or_create_producers( const producer_schedule_type& producers); void clear_expired_transactions(); /// @} diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index ec53089e2804812a05a5faf85a764097f80feb89..5e89338e7fa49eec9ff87a91976c1100583968ba 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -115,6 +115,8 @@ namespace eosio { namespace chain { uint16_t region = 0; ///< the computational memory region this transaction applies to. uint16_t ref_block_num = 0; ///< specifies a block num in the last 2^16 blocks. uint32_t ref_block_prefix = 0; ///< specifies the lower 32 bits of the blockid at get_ref_blocknum + uint16_t packed_bandwidth_words = 0; /// number of 8 byte words this transaction can compress into + uint16_t context_free_cpu_bandwidth = 0; /// number of CPU usage units to bill transaction for /** * @return the absolute block number given the relative ref_block_num @@ -132,6 +134,7 @@ namespace eosio { namespace chain { * read and write scopes. */ struct transaction : public transaction_header { + vector context_free_actions; vector actions; transaction_id_type id()const; @@ -152,6 +155,7 @@ namespace eosio { namespace chain { } vector signatures; + vector> context_free_data; ///< for each context-free action, there is an entry here const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id); signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const; @@ -252,9 +256,9 @@ namespace eosio { namespace chain { FC_REFLECT( eosio::chain::permission_level, (actor)(permission) ) FC_REFLECT( eosio::chain::action, (account)(name)(authorization)(data) ) -FC_REFLECT( eosio::chain::transaction_header, (expiration)(region)(ref_block_num)(ref_block_prefix) ) -FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (actions) ) -FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures) ) +FC_REFLECT( eosio::chain::transaction_header, (expiration)(region)(ref_block_num)(ref_block_prefix)(packed_bandwidth_words)(context_free_cpu_bandwidth) ) +FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (context_free_actions)(actions) ) +FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures)(context_free_data) ) FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib)) FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(data) ) FC_REFLECT_DERIVED( eosio::chain::deferred_transaction, (eosio::chain::transaction), (sender_id)(sender)(execute_after) ) diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index cb8bc17033bd25dc8f11cb185aa16bf102af49d7..5a8725e35ec8a91741ddc0a7072764c809bf9bbc 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -27,6 +27,7 @@ class transaction_metadata { // things for packed_transaction optional raw_trx; optional decompressed_trx; + vector> context_free_data; // things for signed/packed transactions optional> signing_keys; diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index e1f40cb318079f895bd5fe35f55645a9ca42b4e5..0b435394f2728457b879947ab16a8d9eeafb8759 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -154,6 +154,9 @@ namespace eosio { namespace chain { using block_id_type = fc::sha256; using checksum_type = fc::sha256; + using checksum256_type = fc::sha256; + using checksum512_type = fc::sha512; + using checksum160_type = fc::ripemd160; using transaction_id_type = checksum_type; using digest_type = checksum_type; using weight_type = uint16_t; diff --git a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp index 6faaed41de906075a09d18e8ce9bf669a3bb4fd0..22cfa4b931cde260828c3817a4324f7875c6d043 100644 --- a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp @@ -153,6 +153,7 @@ public: uint32_t sbrk_bytes; void reset(const info& ); + void prepare( const info& ); void call(const string& entry_point, LiteralList& args, apply_context& context); void call_apply(apply_context&); diff --git a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp index 19b1acdc12dd81b738eca1e2b9964cabc45e9fe7..92a638b9c5fb726fea087c5cb593af19cebf160a 100644 --- a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp @@ -20,7 +20,7 @@ class entry { uint32_t sbrk_bytes; void reset(const info& ); - + void prepare(const info& ); void call(const string &entry_point, const vector &args, apply_context &context); @@ -44,24 +44,29 @@ class entry { struct info { info( const entry &wavm ) { - MemoryInstance* current_memory = Runtime::getDefaultMemory(wavm.instance); default_sbrk_bytes = wavm.sbrk_bytes; - - if(current_memory) { - char *mem_ptr = &memoryRef(current_memory, 0); - const auto allocated_memory = Runtime::getDefaultMemorySize(wavm.instance); - for (uint64_t i = 0; i < allocated_memory; ++i) { - if (mem_ptr[i]) - mem_end = i + 1; - } - mem_image.resize(mem_end); - memcpy(mem_image.data(), mem_ptr, mem_end); + const auto* module = wavm.module; + + //populate the module's data segments in to a vector so the initial state can be + // restored on each invocation + //Be Warned, this may need to be revisited when module imports make sense. The + // code won't handle data segments that initalize an imported memory which I think + // is valid. + for(const DataSegment& data_segment : module->dataSegments) { + FC_ASSERT(data_segment.baseOffset.type == InitializerExpression::Type::i32_const); + FC_ASSERT(module->memories.defs.size()); + const U32 base_offset = data_segment.baseOffset.i32; + const Uptr memory_size = (module->memories.defs[0].type.size.min << IR::numBytesPerPageLog2); + if (base_offset >= memory_size || base_offset + data_segment.data.size() > memory_size) + FC_THROW_EXCEPTION(wasm_execution_error, "WASM data segment outside of valid memory range"); + if (base_offset + data_segment.data.size() > mem_image.size()) + mem_image.resize(base_offset + data_segment.data.size(), 0x00); + memcpy(mem_image.data() + base_offset, data_segment.data.data(), data_segment.data.size()); } } // a clean image of the memory used to sanitize things on checkin size_t mem_start = 0; - size_t mem_end = 1<<16; vector mem_image; uint32_t default_sbrk_bytes = 0; diff --git a/libraries/chain/test/transaction_test.cpp b/libraries/chain/test/transaction_test.cpp index 48a6cc9dd8d6a11323d464d30f980a90592eff5c..d7329fc18fc29fb0cab1c761e6320340e57a37c3 100644 --- a/libraries/chain/test/transaction_test.cpp +++ b/libraries/chain/test/transaction_test.cpp @@ -56,7 +56,7 @@ BOOST_AUTO_TEST_SUITE(transaction_test) { try { - std::string expected = "78da63606060d8bf7ff5eab2198ace8c13962fe3909cb0f114835aa9248866044a3284784ef402d12bde1a19090a1425e6a5e4e72aa42496242a64a416a50200a9d114bb"; + std::string expected = "78da63606060d8bf7ff5eab2198ace0c20c03861f9320ec9091b4f31a8954a826846906888e7442f10bde2ad9191a04051625e4a7eae424a6249a242466a512a00bf3414bb"; transaction trx; trx.region = 0xBFBFU; @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_SUITE(transaction_test) expected.actions.emplace_back(vector{{N(decomp), config::active_name}}, test_action {"random data here"}); - char compressed_tx_raw[] = "78da63606060d8bf7ff5eab2198ace8c13962fe3909cb0f114835aa9248866044a3284784ef402d12bde1a19090a1425e6a5e4e72aa42496242a64a416a50200a9d114bb"; + char compressed_tx_raw[] = "78da63606060d8bf7ff5eab2198ace0c20c03861f9320ec9091b4f31a8954a826846906888e7442f10bde2ad9191a04051625e4a7eae424a6249a242466a512a00bf3414bb"; packed_transaction t; t.data.resize((sizeof(compressed_tx_raw) - 1) / 2); diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a7ff3e77edd27229b91b51bc097210234ea675b4..e0a37c7101f14258ba54c3581214ab39fc4802f1 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -1,10 +1,14 @@ #include #include #include +#include +#include #include #include +#include #include #include +#include #include #include #include @@ -68,8 +72,8 @@ namespace eosio { namespace chain { */ struct code_info { explicit code_info(wavm::info&& wavm_info, binaryen::info&& binaryen_info) - : wavm_info(wavm_info) - , binaryen_info(binaryen_info) + : wavm_info(std::forward(wavm_info)) + , binaryen_info(std::forward(binaryen_info)) {} @@ -168,8 +172,6 @@ namespace eosio { namespace chain { binaryen = binaryen::entry::build(wasm_binary, wasm_binary_size); binaryen_info.emplace(*binaryen); - - } catch (...) { pending_error = std::current_exception(); } @@ -236,6 +238,14 @@ namespace eosio { namespace chain { }); } + //initialize the memory for a cache entry + wasm_cache::entry& prepare_wasm_instance(wasm_cache::entry& wasm_cache_entry, const digest_type& code_id) { + auto& info = (*fetch_info(code_id)).get(); + wasm_cache_entry.wavm.prepare(info.wavm_info); + wasm_cache_entry.binaryen.prepare(info.binaryen_info); + return wasm_cache_entry; + } + // mapping of digest to an entry for the code map _cache; std::mutex _cache_lock; @@ -254,9 +264,10 @@ namespace eosio { namespace chain { // see if there is an available entry in the cache auto result = _my->try_fetch_entry(code_id); if (result) { - return (*result).get(); + wasm_cache::entry& wasm_cache_entry = (*result).get(); + return _my->prepare_wasm_instance(wasm_cache_entry, code_id); } - return _my->fetch_entry(code_id, wasm_binary, wasm_binary_size); + return _my->prepare_wasm_instance(_my->fetch_entry(code_id, wasm_binary, wasm_binary_size), code_id); } @@ -338,18 +349,35 @@ namespace eosio { namespace chain { class context_aware_api { public: - context_aware_api(wasm_interface& wasm) - :context(intrinsics_accessor::get_context(wasm).context) - ,code(intrinsics_accessor::get_context(wasm).code) + context_aware_api(wasm_interface& wasm, bool context_free = false ) + :code(intrinsics_accessor::get_context(wasm).code), + context(intrinsics_accessor::get_context(wasm).context) ,vm(intrinsics_accessor::get_context(wasm).vm) - {} + { + if( context.context_free ) + FC_ASSERT( context_free, "only context free api's can be used in this context" ); + context.used_context_free_api |= !context_free; + } protected: - wasm_cache::entry& code; apply_context& context; + wasm_cache::entry& code; wasm_interface::vm_type vm; + }; +class context_free_api : public context_aware_api { + public: + context_free_api( wasm_interface& wasm ) + :context_aware_api(wasm, true) { + /* the context_free_data is not available during normal application because it is prunable */ + FC_ASSERT( context.context_free, "this API may only be called from context_free apply" ); + } + + int get_context_free_data( uint32_t index, array_ptr buffer, size_t buffer_size )const { + return context.get_context_free_data( index, buffer, buffer_size ); + } +}; class privileged_api : public context_aware_api { public: privileged_api( wasm_interface& wasm ) @@ -366,7 +394,7 @@ class privileged_api : public context_aware_api { * Feature name should be base32 encoded name. */ void activate_feature( int64_t feature_name ) { - FC_ASSERT( !"Unsupported Harfork Detected" ); + FC_ASSERT( !"Unsupported Hardfork Detected" ); } /** @@ -383,7 +411,7 @@ class privileged_api : public context_aware_api { 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" ); + FC_ASSERT( buo.db_usage <= ram_bytes, "attempt to free too much space" ); auto& gdp = context.controller.get_dynamic_global_properties(); context.mutable_db.modify( gdp, [&]( auto& p ) { @@ -411,7 +439,6 @@ class privileged_api : public context_aware_api { 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; @@ -456,9 +483,9 @@ class producer_api : public 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 len = active_producers.size(); size_t cpy_len = std::min(datalen, len); - memcpy(producers, active_producers.data(), cpy_len); + memcpy(producers, active_producers.data(), cpy_len * sizeof(chain::account_name) ); return len; } }; @@ -480,7 +507,7 @@ class crypto_api : public context_aware_api { datastream pubds( pub, publen ); fc::raw::unpack(ds, s); - fc::raw::unpack(ds, p); + fc::raw::unpack(pubds, p); auto check = fc::crypto::public_key( s, digest, false ); FC_ASSERT( check == p, "Error expected key different than recovered key" ); @@ -503,6 +530,22 @@ class crypto_api : public context_aware_api { FC_ASSERT( result == hash_val, "hash miss match" ); } + void assert_sha1(array_ptr data, size_t datalen, const fc::sha1& hash_val) { + auto result = fc::sha1::hash( data, datalen ); + FC_ASSERT( result == hash_val, "hash miss match" ); + } + + void assert_sha512(array_ptr data, size_t datalen, const fc::sha512& hash_val) { + auto result = fc::sha512::hash( data, datalen ); + FC_ASSERT( result == hash_val, "hash miss match" ); + } + + void assert_ripemd160(array_ptr data, size_t datalen, const fc::ripemd160& hash_val) { + auto result = fc::ripemd160::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 ); } @@ -545,10 +588,10 @@ class system_api : public context_aware_api { if( !condition ) edump((message)); FC_ASSERT( condition, "assertion failed: ${s}", ("s",message)); } - + fc::time_point_sec now() { return context.controller.head_block_time(); - } + } }; class action_api : public context_aware_api { @@ -751,13 +794,63 @@ class db_api : public context_aware_api { 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(context.receiver, scope, table); return context.remove_record(t_id, keys); } }; +template<> +class db_api : public context_aware_api { + using KeyType = std::string; + static constexpr int KeyCount = 1; + using KeyArrayType = KeyType[KeyCount]; + using ContextMethodType = int(apply_context::*)(const table_id_object&, const KeyType*, const char*, size_t); + +/* TODO something weird is going on here, will maybe fix before DB changes or this might get + * totally changed anyway + private: + int call(ContextMethodType method, const scope_name& scope, const name& table, account_name bta, + null_terminated_ptr key, size_t key_len, array_ptr data, size_t data_len) { + const auto& t_id = context.find_or_create_table(context.receiver, scope, table); + const KeyType keys((const char*)key.value, key_len); + + const char* record_data = ((const char*)data); + size_t record_len = data_len; + return (context.*(method))(t_id, bta, &keys, record_data, record_len); + } +*/ + public: + using context_aware_api::context_aware_api; + + int store_str(const scope_name& scope, const name& table, const account_name& bta, + null_terminated_ptr key, uint32_t key_len, array_ptr data, size_t data_len) { + const auto& t_id = context.find_or_create_table(context.receiver, scope, table); + const KeyType keys(key.value, key_len); + const char* record_data = ((const char*)data); + size_t record_len = data_len; + return context.store_record(t_id, bta, &keys, record_data, record_len); + //return call(&apply_context::store_record, scope, table, bta, key, key_len, data, data_len); + } + + int update_str(const scope_name& scope, const name& table, const account_name& bta, + null_terminated_ptr key, uint32_t key_len, array_ptr data, size_t data_len) { + const auto& t_id = context.find_or_create_table(context.receiver, scope, table); + const KeyType keys((const char*)key, key_len); + const char* record_data = ((const char*)data); + size_t record_len = data_len; + return context.update_record(t_id, bta, &keys, record_data, record_len); + //return call(&apply_context::update_record, scope, table, bta, key, key_len, data, data_len); + } + + int remove_str(const scope_name& scope, const name& table, array_ptr &key, uint32_t key_len) { + const auto& t_id = context.find_or_create_table(scope, context.receiver, table); + const KeyArrayType k = {std::string(key, key_len)}; + return context.remove_record(t_id, k); + } +}; + template class db_index_api : public context_aware_api { using KeyType = typename IndexType::value_type::key_type; @@ -789,41 +882,105 @@ class db_index_api : public context_aware_api { public: using context_aware_api::context_aware_api; - int load(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - auto res = call(&apply_context::load_record, code, scope, table, data, data_len); - //ilog("LOAD [${scope},${code},${table}] => ${res} :: ${HEX}", ("scope",scope)("code",code)("table",table)("res",res)("HEX", fc::to_hex(data, data_len))); + 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; } - int front(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::front_record, code, scope, table, data, data_len); + int front(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { + auto res = call(&apply_context::front_record, scope, code, table, data, data_len); + return res; } - int back(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::back_record, code, scope, table, data, data_len); + int back(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { + auto res = call(&apply_context::back_record, scope, code, table, data, data_len); + return res; } - int next(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::next_record, code, scope, table, data, data_len); + int next(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { + auto res = call(&apply_context::next_record, scope, code, table, data, data_len); + return res; } - int previous(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::previous_record, code, scope, table, data, data_len); + int previous(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { + auto res = call(&apply_context::previous_record, scope, code, table, data, data_len); + return res; } - int lower_bound(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::lower_bound_record, code, scope, table, data, data_len); + int lower_bound(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { + auto res = call(&apply_context::lower_bound_record, scope, code, table, data, data_len); + return res; } - int upper_bound(const account_name& code, const scope_name& scope, const name& table, array_ptr data, size_t data_len) { - return call(&apply_context::upper_bound_record, code, scope, table, data, data_len); + int upper_bound(const scope_name& scope, const account_name& code, const name& table, array_ptr data, size_t data_len) { + auto res = call(&apply_context::upper_bound_record, scope, code, table, data, data_len); + return res; } }; -class memory_api : public context_aware_api { +template<> +class db_index_api : public context_aware_api { + using KeyType = std::string; + static constexpr int KeyCount = 1; + using KeyArrayType = KeyType[KeyCount]; + 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 &key, uint32_t key_len, array_ptr data, size_t data_len) { + auto maybe_t_id = context.find_table(scope, context.receiver, table); + if (maybe_t_id == nullptr) { + return 0; + } + + const auto& t_id = *maybe_t_id; + //FC_ASSERT(data_len >= KeyCount * sizeof(KeyType), "Data is not long enough to contain keys"); + KeyType keys((const char*)key, key_len); // = reinterpret_cast((char *)data); + + char* record_data = ((char*)data); // + sizeof(KeyArrayType); + size_t record_len = data_len; // - sizeof(KeyArrayType); + + return (context.*(method))(t_id, &keys, record_data, record_len); // + sizeof(KeyArrayType); + } + public: using context_aware_api::context_aware_api; + + int load_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) { + auto res = call(&apply_context::load_record, scope, code, table, key, key_len, data, data_len); + return res; + } + + int front_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::front_record, scope, code, table, key, key_len, data, data_len); + } + + int back_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::back_record, scope, code, table, key, key_len, data, data_len); + } + + int next_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::next_record, scope, code, table, key, key_len, data, data_len); + } + + int previous_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::previous_record, scope, code, table, key, key_len, data, data_len); + } + + int lower_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::lower_bound_record, scope, code, table, key, key_len, data, data_len); + } + + 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 { + public: + memory_api( wasm_interface& wasm ) + :context_aware_api(wasm,true){} char* memcpy( array_ptr dest, array_ptr src, size_t length) { return (char *)::memcpy(dest, src, length); @@ -842,6 +999,10 @@ class memory_api : public context_aware_api { } uint32_t sbrk(int num_bytes) { + // sbrk should only allow for memory to grow + if (num_bytes < 0) + throw eosio::chain::page_memory_error(); + switch(vm) { case wasm_interface::vm_type::wavm: return (uint32_t)code.wavm.sbrk(num_bytes); @@ -855,6 +1016,36 @@ class transaction_api : public context_aware_api { public: using context_aware_api::context_aware_api; + void send_inline( array_ptr data, size_t data_len ) { + // TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size + FC_ASSERT( data_len < config::default_max_inline_action_size, "inline action too big" ); + + action act; + fc::raw::unpack(data, data_len, act); + context.execute_inline(std::move(act)); + } + + void send_deferred( uint32_t sender_id, const fc::time_point_sec& execute_after, array_ptr data, size_t data_len ) { + try { + // TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size + FC_ASSERT(data_len < config::default_max_gen_trx_size, "generated transaction too big"); + + deferred_transaction dtrx; + fc::raw::unpack(data, data_len, dtrx); + dtrx.sender = context.receiver; + dtrx.sender_id = sender_id; + dtrx.execute_after = execute_after; + context.execute_deferred(std::move(dtrx)); + } FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len))); + } +}; + + +class context_free_transaction_api : public context_aware_api { + public: + context_free_transaction_api( wasm_interface& wasm ) + :context_aware_api(wasm,true){} + int read_transaction( array_ptr data, size_t data_len ) { bytes trx = context.get_packed_transaction(); if (data_len >= trx.size()) { @@ -878,42 +1069,230 @@ class transaction_api : public context_aware_api { return context.trx_meta.trx().ref_block_prefix; } - void send_inline( array_ptr data, size_t data_len ) { - // TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size - FC_ASSERT( data_len < config::default_max_inline_action_size, "inline action too big" ); + int get_action( uint32_t type, uint32_t index, array_ptr buffer, size_t buffer_size )const { + return context.get_action( type, index, buffer, buffer_size ); + } - action act; - fc::raw::unpack(data, data_len, act); - context.execute_inline(std::move(act)); +}; + +class compiler_builtins : public context_aware_api { + public: + using context_aware_api::context_aware_api; + void __ashlti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) { + fc::uint128_t i(high, low); + i <<= shift; + ret = (unsigned __int128)i; } + void __ashrti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) { + // retain the signedness + ret = high; + ret <<= 64; + ret |= low; + ret >>= shift; + } - void send_deferred( uint32_t sender_id, const fc::time_point_sec& execute_after, array_ptr data, size_t data_len ) { - try { - // TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size - FC_ASSERT(data_len < config::default_max_gen_trx_size, "generated transaction too big"); + void __lshlti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) { + fc::uint128_t i(high, low); + i <<= shift; + ret = (unsigned __int128)i; + } - deferred_transaction dtrx; - fc::raw::unpack(data, data_len, dtrx); - dtrx.sender = context.receiver; - dtrx.sender_id = sender_id; - dtrx.execute_after = execute_after; - context.execute_deferred(std::move(dtrx)); - } FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len))); + void __lshrti3(__int128& ret, uint64_t low, uint64_t high, uint32_t shift) { + fc::uint128_t i(high, low); + i >>= shift; + ret = (unsigned __int128)i; + } + + void __divti3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) { + __int128 lhs = ha; + __int128 rhs = hb; + + lhs <<= 64; + lhs |= la; + + rhs <<= 64; + rhs |= lb; + + FC_ASSERT(rhs != 0, "divide by zero"); + + lhs /= rhs; + + ret = lhs; + } + + void __udivti3(unsigned __int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) { + unsigned __int128 lhs = ha; + unsigned __int128 rhs = hb; + + lhs <<= 64; + lhs |= la; + + rhs <<= 64; + rhs |= lb; + + FC_ASSERT(rhs != 0, "divide by zero"); + + lhs /= rhs; + ret = lhs; + } + + void __multi3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) { + __int128 lhs = ha; + __int128 rhs = hb; + + lhs <<= 64; + lhs |= la; + + rhs <<= 64; + rhs |= lb; + + lhs *= rhs; + ret = lhs; + } + + void __modti3(__int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) { + __int128 lhs = ha; + __int128 rhs = hb; + + lhs <<= 64; + lhs |= la; + + rhs <<= 64; + rhs |= lb; + + FC_ASSERT(rhs != 0, "divide by zero"); + + lhs %= rhs; + ret = lhs; + } + + void __umodti3(unsigned __int128& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb) { + unsigned __int128 lhs = ha; + unsigned __int128 rhs = hb; + + lhs <<= 64; + lhs |= la; + + rhs <<= 64; + rhs |= lb; + + FC_ASSERT(rhs != 0, "divide by zero"); + + lhs %= rhs; + ret = lhs; } + static constexpr uint32_t SHIFT_WIDTH = (sizeof(uint64_t)*8)-1; }; +class math_api : public context_aware_api { + public: + using context_aware_api::context_aware_api; + + + void diveq_i128(unsigned __int128* self, const unsigned __int128* other) { + fc::uint128_t s(*self); + const fc::uint128_t o(*other); + FC_ASSERT( o != 0, "divide by zero" ); + + s = s/o; + *self = (unsigned __int128)s; + } + + void multeq_i128(unsigned __int128* self, const unsigned __int128* other) { + fc::uint128_t s(*self); + const fc::uint128_t o(*other); + s *= o; + *self = (unsigned __int128)s; + } + + uint64_t double_add(uint64_t a, uint64_t b) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + DOUBLE c = DOUBLE(*reinterpret_cast(&a)) + + DOUBLE(*reinterpret_cast(&b)); + double res = c.convert_to(); + return *reinterpret_cast(&res); + } + + uint64_t double_mult(uint64_t a, uint64_t b) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + DOUBLE c = DOUBLE(*reinterpret_cast(&a)) + * DOUBLE(*reinterpret_cast(&b)); + double res = c.convert_to(); + return *reinterpret_cast(&res); + } + + uint64_t double_div(uint64_t a, uint64_t b) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + DOUBLE divisor = DOUBLE(*reinterpret_cast(&b)); + FC_ASSERT(divisor != 0, "divide by zero"); + DOUBLE c = DOUBLE(*reinterpret_cast(&a)) / divisor; + double res = c.convert_to(); + return *reinterpret_cast(&res); + } + + uint32_t double_eq(uint64_t a, uint64_t b) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + return DOUBLE(*reinterpret_cast(&a)) == DOUBLE(*reinterpret_cast(&b)); + } + + uint32_t double_lt(uint64_t a, uint64_t b) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + return DOUBLE(*reinterpret_cast(&a)) < DOUBLE(*reinterpret_cast(&b)); + } + + uint32_t double_gt(uint64_t a, uint64_t b) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + return DOUBLE(*reinterpret_cast(&a)) > DOUBLE(*reinterpret_cast(&b)); + } + + uint64_t double_to_i64(uint64_t n) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + return DOUBLE(*reinterpret_cast(&n)).convert_to(); + } + + uint64_t i64_to_double(int64_t n) { + using DOUBLE = boost::multiprecision::cpp_bin_float_50; + double res = DOUBLE(n).convert_to(); + return *reinterpret_cast(&res); + } +}; + +REGISTER_INTRINSICS(math_api, + (diveq_i128, void(int, int) ) + (multeq_i128, void(int, int) ) + (double_add, int64_t(int64_t, int64_t) ) + (double_mult, int64_t(int64_t, int64_t) ) + (double_div, int64_t(int64_t, int64_t) ) + (double_eq, int32_t(int64_t, int64_t) ) + (double_lt, int32_t(int64_t, int64_t) ) + (double_gt, int32_t(int64_t, int64_t) ) + (double_to_i64, int64_t(int64_t) ) + (i64_to_double, int64_t(int64_t) ) +); + +REGISTER_INTRINSICS(compiler_builtins, + (__ashlti3, void(int, int64_t, int64_t, int) ) + (__ashrti3, void(int, int64_t, int64_t, int) ) + (__lshlti3, void(int, int64_t, int64_t, int) ) + (__lshrti3, void(int, int64_t, int64_t, int) ) + (__divti3, void(int, int64_t, int64_t, int64_t, int64_t) ) + (__udivti3, void(int, int64_t, int64_t, int64_t, int64_t) ) + (__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)) + (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, @@ -921,7 +1300,7 @@ REGISTER_INTRINSICS(checktime_api, ); REGISTER_INTRINSICS(producer_api, - (get_active_producers, int(int, int)) + (get_active_producers, int(int, int) ) ); REGISTER_INTRINSICS( database_api, @@ -957,17 +1336,20 @@ REGISTER_INTRINSICS( database_api, ); 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)) + (assert_recover_key, void(int, int, int, int, int) ) + (recover_key, int(int, int, int, int, int) ) + (assert_sha256, void(int, int, int) ) + (assert_sha1, void(int, int, int) ) + (assert_sha512, void(int, int, int) ) + (assert_ripemd160, void(int, int, int) ) + (sha1, void(int, int, int) ) + (sha256, void(int, int, int) ) + (sha512, void(int, int, int) ) + (ripemd160, void(int, int, int) ) ); REGISTER_INTRINSICS(string_api, - (assert_is_utf8, void(int, int, int)) + (assert_is_utf8, void(int, int, int) ) ); REGISTER_INTRINSICS(system_api, @@ -985,11 +1367,11 @@ REGISTER_INTRINSICS(action_api, ); REGISTER_INTRINSICS(apply_context, - (require_write_lock, void(int64_t) ) - (require_read_lock, void(int64_t, int64_t) ) - (require_recipient, void(int64_t) ) + (require_write_lock, void(int64_t) ) + (require_read_lock, void(int64_t, int64_t) ) + (require_recipient, void(int64_t) ) (require_authorization, void(int64_t), "require_auth", void(apply_context::*)(const account_name&)const) - (is_account, int(int64_t) ) + (is_account, int(int64_t) ) ); REGISTER_INTRINSICS(console_api, @@ -1002,25 +1384,32 @@ REGISTER_INTRINSICS(console_api, (printhex, void(int, int) ) ); -REGISTER_INTRINSICS(transaction_api, +REGISTER_INTRINSICS(context_free_transaction_api, (read_transaction, int(int, int) ) (transaction_size, int() ) (expiration, int() ) (tapos_block_prefix, int() ) (tapos_block_num, int() ) + (get_action, int (int, int, int, int) ) +); + +REGISTER_INTRINSICS(transaction_api, (send_inline, void(int, int) ) (send_deferred, void(int, int, int, int) ) ); +REGISTER_INTRINSICS(context_free_api, + (get_context_free_data, int(int, int, int) ) +) + REGISTER_INTRINSICS(memory_api, - (memcpy, int(int, int, int) ) - (memmove, int(int, int, int) ) - (memcmp, int(int, int, int) ) - (memset, int(int, int, int) ) - (sbrk, int(int) ) + (memcpy, int(int, int, int) ) + (memmove, int(int, int, int) ) + (memcmp, int(int, int, int) ) + (memset, int(int, int, int) ) + (sbrk, int(int) ) ); - #define DB_METHOD_SEQ(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 ) \ @@ -1050,13 +1439,24 @@ using db_index_api_key64x64x64_value_index_by_scope_secondary = db_index_api; REGISTER_INTRINSICS(db_api_key_value_object, DB_METHOD_SEQ(i64)); -REGISTER_INTRINSICS(db_api_keystr_value_object, DB_METHOD_SEQ(str)); 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, int64_t, int, int, int, int) ) + (update_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (remove_str, int32_t(int64_t, int64_t, int, int) )); REGISTER_INTRINSICS(db_index_api_key_value_index_by_scope_primary, DB_INDEX_METHOD_SEQ(i64)); -REGISTER_INTRINSICS(db_index_api_keystr_value_index_by_scope_primary, DB_INDEX_METHOD_SEQ(str)); +REGISTER_INTRINSICS(db_index_api_keystr_value_index_by_scope_primary, + (load_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (front_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (back_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (next_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (previous_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (lower_bound_str, int32_t(int64_t, int64_t, int64_t, int, int, int, int) ) + (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)); diff --git a/libraries/chain/webassembly/binaryen.cpp b/libraries/chain/webassembly/binaryen.cpp index a55f8d7a73108b977f64a86bd2075360f1c1fec3..89cf36a94440448e2e71d15fa2c3db7abb443dd1 100644 --- a/libraries/chain/webassembly/binaryen.cpp +++ b/libraries/chain/webassembly/binaryen.cpp @@ -62,6 +62,9 @@ void entry::reset(const info& base_info) { interface = nullptr; } +void entry::prepare( const info& base_info) { +} + static Expression* create_call_checktime(Import *checktime, Module &module) { // create a calling expression CallImport *call = module.allocator.alloc(); diff --git a/libraries/chain/webassembly/wavm.cpp b/libraries/chain/webassembly/wavm.cpp index 41740a82951378ee06242215de857c2d51a3cac2..0a17e45f14cb4033e75dc50437e6295f249d376f 100644 --- a/libraries/chain/webassembly/wavm.cpp +++ b/libraries/chain/webassembly/wavm.cpp @@ -108,16 +108,20 @@ void entry::reset(const info& base_info) { MemoryInstance* default_mem = getDefaultMemory(instance); if(default_mem) { shrinkMemory(default_mem, getMemoryNumPages(default_mem) - 1); - - char* memstart = &memoryRef( getDefaultMemory(instance), 0 ); - memset( memstart + base_info.mem_end, 0, ((1<<16) - base_info.mem_end) ); - memcpy( memstart, base_info.mem_image.data(), base_info.mem_end); } - resetGlobalInstances(instance); - sbrk_bytes = base_info.default_sbrk_bytes; } +void entry::prepare( const info& base_info ) { + resetGlobalInstances(instance); + MemoryInstance* memory_instance = getDefaultMemory(instance); + if(memory_instance) { + resetMemory(memory_instance, module->memories.defs[0].type); + + char* memstart = &memoryRef(getDefaultMemory(instance), 0); + memcpy(memstart, base_info.mem_image.data(), base_info.mem_image.size()); + } +} entry entry::build(const char* wasm_binary, size_t wasm_binary_size) { Module* module = new Module(); diff --git a/libraries/fc/include/fc/utility.hpp b/libraries/fc/include/fc/utility.hpp index 07420b9e75d323010c7caec8c33be94f841fee6a..d736ca44dde92a278a6e98b4946f3c5e2ca7bd3a 100644 --- a/libraries/fc/include/fc/utility.hpp +++ b/libraries/fc/include/fc/utility.hpp @@ -54,12 +54,10 @@ namespace fc { const T& min( const T& a, const T& b ) { return a < b ? a: b; } constexpr size_t const_strlen(const char* str) { - size_t res = 0; - while (*str != '\0') { - ++res; - ++str; - } - return res; + int i = 0; + while(*(str+i) != '\0') + i++; + return i; } diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 91ff7d75d4330ded78a3e58c904b9673c5c401f4..8e61b459dcd75c0babbc0f47c2d75fc0399bb55e 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -9,27 +9,29 @@ namespace eosio { namespace testing { using namespace eosio::chain; - /** * @class tester * @brief provides utility function to simplify the creation of unit tests */ - class tester { + class base_tester { public: typedef string action_result; - tester(chain_controller::runtime_limits limits = chain_controller::runtime_limits(), bool process_genesis = true); + base_tester(chain_controller::runtime_limits limits = chain_controller::runtime_limits()); void close(); void open(); - void push_genesis_block(); 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); + action_result push_action(action&& cert_act, uint64_t authorizer); + + transaction_trace push_action( const account_name& code, const action_name& act, const account_name& signer, const variant_object &data ); + + void set_tapos( signed_transaction& trx ) const; void create_accounts( vector names, bool multisig = false ) { @@ -101,6 +103,13 @@ namespace eosio { namespace testing { map chain_transactions; }; + class tester : public base_tester { + public: + tester(chain_controller::runtime_limits limits = chain_controller::runtime_limits()); + + void push_genesis_block(); + }; + /** * Utility predicate to check whether an FC_ASSERT message ends with a given string */ diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index cbd9760c0d6d9d5e11bb23600b40641a50acf2fd..90bb1e4ec768fbd7bbfe4be04df8d14eb0a53565 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -19,7 +19,7 @@ namespace eosio { namespace testing { - tester::tester(chain_controller::runtime_limits limits, bool process_genesis) { + base_tester::base_tester(chain_controller::runtime_limits limits) { cfg.block_log_dir = tempdir.path() / "blocklog"; cfg.shared_memory_dir = tempdir.path() / "shared"; cfg.shared_memory_size = 1024*1024*8; @@ -27,30 +27,23 @@ namespace eosio { namespace testing { cfg.genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000"); cfg.genesis.initial_key = get_public_key( config::system_account_name, "active" ); cfg.limits = limits; - open(); - if (process_genesis) - push_genesis_block(); - } - - void tester::push_genesis_block() { - set_code(config::system_account_name, test_system_wast); - set_abi(config::system_account_name, test_system_abi); } - public_key_type tester::get_public_key( name keyname, string role ) const { + public_key_type base_tester::get_public_key( name keyname, string role ) const { return get_private_key( keyname, role ).get_public_key(); } - private_key_type tester::get_private_key( name keyname, string role ) const { + private_key_type base_tester::get_private_key( name keyname, string role ) const { return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); } - void tester::close() { + void base_tester::close() { control.reset(); chain_transactions.clear(); } - void tester::open() { + + void base_tester::open() { control.reset( new chain_controller(cfg) ); chain_transactions.clear(); control->applied_block.connect([this]( const block_trace& trace ){ @@ -66,7 +59,7 @@ namespace eosio { namespace testing { }); } - signed_block tester::produce_block( fc::microseconds skip_time ) { + signed_block base_tester::produce_block( fc::microseconds skip_time ) { auto head_time = control->head_block_time(); auto next_time = head_time + skip_time; uint32_t slot = control->get_slot_at_time( next_time ); @@ -76,18 +69,16 @@ namespace eosio { namespace testing { return control->generate_block( next_time, sch_pro, priv_key, skip_missed_block_penalty ); } - - void tester::produce_blocks( uint32_t n ) { + void base_tester::produce_blocks( uint32_t n ) { for( uint32_t i = 0; i < n; ++i ) produce_block(); } - void tester::set_tapos( signed_transaction& trx ) const { + void base_tester::set_tapos( signed_transaction& trx ) const { trx.set_reference_block( control->head_block_id() ); } - - void tester::create_account( account_name a, account_name creator, bool multisig ) { + void base_tester::create_account( account_name a, account_name creator, bool multisig ) { signed_transaction trx; set_tapos( trx ); @@ -113,16 +104,16 @@ namespace eosio { namespace testing { push_transaction( trx ); } - transaction_trace tester::push_transaction( packed_transaction& trx ) { + transaction_trace base_tester::push_transaction( packed_transaction& trx ) { return control->push_transaction( trx ); } - transaction_trace tester::push_transaction( signed_transaction& trx ) { + transaction_trace base_tester::push_transaction( signed_transaction& trx ) { auto ptrx = packed_transaction(trx); return push_transaction( ptrx ); } - tester::action_result tester::push_action(action&& cert_act, uint64_t authorizer) { + base_tester::action_result base_tester::push_action(action&& cert_act, uint64_t authorizer) { signed_transaction trx; if (authorizer) { cert_act.authorization = vector{{authorizer, config::active_name}}; @@ -142,7 +133,33 @@ namespace eosio { namespace testing { return success(); } - transaction_trace tester::push_reqauth( account_name from, const vector& auths, const vector& keys ) { + transaction_trace base_tester::push_action( const account_name& code, + const action_name& acttype, + const account_name& actor, + const variant_object& data + ) + { try { + chain::contracts::abi_serializer abis( control->get_database().get(code).get_abi() ); + + string action_type_name = abis.get_action_type(acttype); + + action act; + act.account = code; + act.name = acttype; + act.authorization = vector{{actor, config::active_name}}; + act.data = abis.variant_to_binary(action_type_name, data); + wdump((act)); + + signed_transaction trx; + trx.actions.emplace_back(std::move(act)); + set_tapos(trx); + trx.sign(get_private_key(actor, "active"), chain_id_type()); + wdump((get_public_key( actor, "active" )));; + + return push_transaction(trx); + } FC_CAPTURE_AND_RETHROW( (code)(acttype)(actor) ) } + + transaction_trace base_tester::push_reqauth( account_name from, const vector& auths, const vector& keys ) { variant pretty_trx = fc::mutable_variant_object() ("actions", fc::variants({ fc::mutable_variant_object() @@ -163,8 +180,7 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - - transaction_trace tester::push_nonce(account_name from, const string& v) { + transaction_trace base_tester::push_nonce(account_name from, const string& v) { variant pretty_trx = fc::mutable_variant_object() ("actions", fc::variants({ fc::mutable_variant_object() @@ -189,11 +205,11 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - transaction_trace tester::transfer( account_name from, account_name to, string amount, string memo, account_name currency ) { + transaction_trace base_tester::transfer( account_name from, account_name to, string amount, string memo, account_name currency ) { return transfer( from, to, asset::from_string(amount), memo, currency ); } - transaction_trace tester::transfer( account_name from, account_name to, asset amount, string memo, account_name currency ) { + transaction_trace base_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() @@ -221,7 +237,7 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - void tester::set_authority( account_name account, + void base_tester::set_authority( account_name account, permission_name perm, authority auth, permission_name parent ) { try { @@ -239,7 +255,7 @@ namespace eosio { namespace testing { push_transaction( trx ); } FC_CAPTURE_AND_RETHROW( (account)(perm)(auth)(parent) ) } - void tester::set_code( account_name account, const char* wast ) try { + void base_tester::set_code( account_name account, const char* wast ) try { auto wasm = wast_to_wasm(wast); signed_transaction trx; @@ -256,7 +272,7 @@ namespace eosio { namespace testing { push_transaction( trx ); } FC_CAPTURE_AND_RETHROW( (account)(wast) ) - void tester::set_abi( account_name account, const char* abi_json) { + void base_tester::set_abi( account_name account, const char* abi_json) { auto abi = fc::json::from_string(abi_json).template as(); signed_transaction trx; trx.actions.emplace_back( vector{{account,config::active_name}}, @@ -270,18 +286,18 @@ namespace eosio { namespace testing { push_transaction( trx ); } - bool tester::chain_has_transaction( const transaction_id_type& txid ) const { + bool base_tester::chain_has_transaction( const transaction_id_type& txid ) const { return chain_transactions.count(txid) != 0; } - const transaction_receipt& tester::get_transaction_receipt( const transaction_id_type& txid ) const { + const transaction_receipt& base_tester::get_transaction_receipt( const transaction_id_type& txid ) const { return chain_transactions.at(txid); } /** * Reads balance as stored by generic_currency contract */ - asset tester::get_currency_balance( const account_name& code, + asset base_tester::get_currency_balance( const account_name& code, const symbol& asset_symbol, const account_name& account ) const { const auto& db = control->get_database(); @@ -299,26 +315,26 @@ namespace eosio { namespace testing { return asset(result, asset_symbol); } - vector tester::to_uint8_vector(const string& s) { + vector base_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 base_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) { + uint64_t base_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) { + string base_tester::to_string(fc::variant x) { vector v; fc::from_variant(x, v); string s(v.size(), 0); @@ -326,4 +342,14 @@ namespace eosio { namespace testing { return s; } + tester::tester(chain_controller::runtime_limits limits) + : base_tester(limits) { + push_genesis_block(); + } + + void tester::push_genesis_block() { + set_code(config::system_account_name, test_system_wast); + set_abi(config::system_account_name, test_system_abi); + } + } } /// eosio::test diff --git a/libraries/wasm-jit/Include/Runtime/Runtime.h b/libraries/wasm-jit/Include/Runtime/Runtime.h index d3ebd534b183949463ed63384c4455ad16e9cb03..367e3c175fc863104d82e80cf5e8f7d00dc44473 100644 --- a/libraries/wasm-jit/Include/Runtime/Runtime.h +++ b/libraries/wasm-jit/Include/Runtime/Runtime.h @@ -217,6 +217,7 @@ namespace Runtime RUNTIME_API void runInstanceStartFunc(ModuleInstance* moduleInstance); RUNTIME_API void resetGlobalInstances(ModuleInstance* moduleInstance); + RUNTIME_API void resetMemory(MemoryInstance* memory, IR::MemoryType& newMemoryType); // Gets an object exported by a ModuleInstance by name. RUNTIME_API ObjectInstance* getInstanceExport(ModuleInstance* moduleInstance,const std::string& name); diff --git a/libraries/wasm-jit/Source/Platform/POSIX.cpp b/libraries/wasm-jit/Source/Platform/POSIX.cpp index 95506a6253b52ba8008ef6a4648c17a385487007..92d2778e9bba1be3759cd92e6b0fab4efba28106 100644 --- a/libraries/wasm-jit/Source/Platform/POSIX.cpp +++ b/libraries/wasm-jit/Source/Platform/POSIX.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include diff --git a/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp b/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp index 76647348d33fd9ffca03d5e706980ec0b1515267..3c97f8d8a5b69d55fd5bc2e0c01d61f3b77998c3 100644 --- a/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp +++ b/libraries/wasm-jit/Source/Runtime/LLVMEmitIR.cpp @@ -4,6 +4,7 @@ #include "IR/Operators.h" #include "IR/OperatorPrinter.h" #include "Logging/Logging.h" +#include "llvm/Support/raw_ostream.h" #define ENABLE_LOGGING 0 #define ENABLE_FUNCTION_ENTER_EXIT_HOOKS 0 @@ -42,8 +43,12 @@ namespace LLVMJIT , llvmModule(new llvm::Module("",context)) , diBuilder(*llvmModule) { - diModuleScope = diBuilder.createFile("unknown","unknown"); + diModuleScope = diBuilder.createFile("debug.info","."); +#ifdef _DEBUG + diCompileUnit = diBuilder.createCompileUnit(llvm::dwarf::DW_LANG_C, diModuleScope,"WAVM",0,"",0); +#else diCompileUnit = diBuilder.createCompileUnit(0xffff,diModuleScope,"WAVM",true,"",0); +#endif diValueTypes[(Uptr)ValueType::any] = nullptr; diValueTypes[(Uptr)ValueType::i32] = diBuilder.createBasicType("i32",32,llvm::dwarf::DW_ATE_signed); @@ -58,8 +63,8 @@ namespace LLVMJIT auto i32MaxAsMetadata = llvm::ConstantAsMetadata::get(emitLiteral(I32(INT32_MAX))); likelyFalseBranchWeights = llvm::MDTuple::getDistinct(context,{llvm::MDString::get(context,"branch_weights"),zeroAsMetadata,i32MaxAsMetadata}); likelyTrueBranchWeights = llvm::MDTuple::getDistinct(context,{llvm::MDString::get(context,"branch_weights"),i32MaxAsMetadata,zeroAsMetadata}); - } + } llvm::Module* emit(); }; @@ -267,6 +272,7 @@ namespace LLVMJIT // Cast the pointer to the appropriate type. auto bytePointer = irBuilder.CreateInBoundsGEP(moduleContext.defaultMemoryBase,byteIndex); + return irBuilder.CreatePointerCast(bytePointer,memoryType->getPointerTo()); } @@ -1635,4 +1641,4 @@ namespace LLVMJIT { return EmitModuleContext(module,moduleInstance).emit(); } -} \ No newline at end of file +} diff --git a/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp b/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp index 51652668356f085464ea9d00ff773c29dc3941f8..b695f5cbaeeccd088e237daed2c446fb0e7478bc 100644 --- a/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp +++ b/libraries/wasm-jit/Source/Runtime/LLVMJIT.cpp @@ -4,6 +4,15 @@ #include "Logging/Logging.h" #include "RuntimePrivate.h" +#ifdef _DEBUG +#include +#include +#include +#include +#include +#include +#endif + #ifdef _DEBUG // This needs to be 1 to allow debuggers such as Visual Studio to place breakpoints and step through the JITed code. #define USE_WRITEABLE_JIT_CODE_PAGES 1 @@ -739,7 +748,32 @@ namespace LLVMJIT return reinterpret_cast(jitUnit->symbol->baseAddress); } - + +#ifdef _DEBUG + int isDebuggerPresent() + { + char buff[1024]; + int debuggerPresent = 0; + int status_fd = open("/proc/self/status", O_RDONLY); + if (status_fd == -1) + return 0; + + ssize_t num_read = read(status_fd, buff, sizeof(buff)); + + if (num_read > 0) { + static const char tracerPID[] = "TracerPID:"; + char *tracer_pid; + buff[num_read] = 0; + tracer_pid = strstr(buff, tracerPID); + + if (tracer_pid) + debuggerPresent = !!atoi(tracer_pid + sizeof(tracerPID) -1 ); + } + + return debuggerPresent; + } +#endif + void init() { llvm::InitializeNativeTarget(); diff --git a/libraries/wasm-jit/Source/Runtime/Memory.cpp b/libraries/wasm-jit/Source/Runtime/Memory.cpp index b0d4a8512ab7bae79e8d00b354ae74f3ed474b58..275f2d7caa9d3e5e84ef59406b039a9d07b66db4 100644 --- a/libraries/wasm-jit/Source/Runtime/Memory.cpp +++ b/libraries/wasm-jit/Source/Runtime/Memory.cpp @@ -65,6 +65,8 @@ namespace Runtime { if(memories[memoryIndex] == this) { memories.erase(memories.begin() + memoryIndex); break; } } + + theMemoryInstance = nullptr; } bool isAddressOwnedByMemory(U8* address) @@ -86,6 +88,16 @@ namespace Runtime return Uptr(memory->type.size.max); } + void resetMemory(MemoryInstance* memory, MemoryType& newMemoryType) { + memory->type.size.min = 1; + if(shrinkMemory(memory, memory->numPages - 1) == -1) + causeException(Exception::Cause::outOfMemory); + memset(memory->baseAddress, 0, 1<type = newMemoryType; + if(growMemory(memory, memory->type.size.min - 1) == -1) + causeException(Exception::Cause::outOfMemory); + } + Iptr growMemory(MemoryInstance* memory,Uptr numNewPages) { const Uptr previousNumPages = memory->numPages; diff --git a/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp b/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp index 1ae704b349546f83f456e8bfa98f18be5d462ff5..9da6594af7e89e1ff02f86f75825b11ffc1c45e5 100644 --- a/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp +++ b/libraries/wasm-jit/Source/Runtime/ModuleInstance.cpp @@ -28,6 +28,8 @@ namespace Runtime }; } + MemoryInstance* MemoryInstance::theMemoryInstance = nullptr; + ModuleInstance* instantiateModule(const IR::Module& module,ImportBindings&& imports) { ModuleInstance* moduleInstance = new ModuleInstance( @@ -72,9 +74,11 @@ namespace Runtime } for(const MemoryDef& memoryDef : module.memories.defs) { - auto memory = createMemory(memoryDef.type); - if(!memory) { causeException(Exception::Cause::outOfMemory); } - moduleInstance->memories.push_back(memory); + if(!MemoryInstance::theMemoryInstance) { + MemoryInstance::theMemoryInstance = createMemory(memoryDef.type); + if(!MemoryInstance::theMemoryInstance) { causeException(Exception::Cause::outOfMemory); } + } + moduleInstance->memories.push_back(MemoryInstance::theMemoryInstance); } // Find the default memory and table for the module. @@ -100,32 +104,10 @@ namespace Runtime || table->elements.size() - baseOffset < tableSegment.indices.size()) { causeException(Exception::Cause::invalidSegmentOffset); } } - for(auto& dataSegment : module.dataSegments) - { - MemoryInstance* memory = moduleInstance->memories[dataSegment.memoryIndex]; - - const Value baseOffsetValue = evaluateInitializer(moduleInstance,dataSegment.baseOffset); - errorUnless(baseOffsetValue.type == ValueType::i32); - const U32 baseOffset = baseOffsetValue.i32; - const Uptr numMemoryBytes = (memory->numPages << IR::numBytesPerPageLog2); - if(baseOffset > numMemoryBytes - || numMemoryBytes - baseOffset < dataSegment.data.size()) - { causeException(Exception::Cause::invalidSegmentOffset); } - } - // Copy the module's data segments into the module's default memory. - for(const DataSegment& dataSegment : module.dataSegments) - { - MemoryInstance* memory = moduleInstance->memories[dataSegment.memoryIndex]; - - const Value baseOffsetValue = evaluateInitializer(moduleInstance,dataSegment.baseOffset); - errorUnless(baseOffsetValue.type == ValueType::i32); - const U32 baseOffset = baseOffsetValue.i32; - - assert(baseOffset + dataSegment.data.size() <= (memory->numPages << IR::numBytesPerPageLog2)); - - memcpy(memory->baseAddress + baseOffset,dataSegment.data.data(),dataSegment.data.size()); - } + //Previously, the module instantiation would write in to the memoryInstance here. Don't do that + //since the memoryInstance is shared across all moduleInstances and we could be compiling + //a new instance while another instance is running // Instantiate the module's global definitions. for(const GlobalDef& globalDef : module.globals.defs) diff --git a/libraries/wasm-jit/Source/Runtime/Runtime.cpp b/libraries/wasm-jit/Source/Runtime/Runtime.cpp index be21b4e3cb05b81413078394068c103ce4acb470..7c80b460b313bf8a65f3708f34127b6843de04fe 100644 --- a/libraries/wasm-jit/Source/Runtime/Runtime.cpp +++ b/libraries/wasm-jit/Source/Runtime/Runtime.cpp @@ -56,7 +56,7 @@ namespace Runtime [[noreturn]] void handleHardwareTrap(Platform::HardwareTrapType trapType,Platform::CallStack&& trapCallStack,Uptr trapOperand) { - std::cerr << "handle hadrware trap \n"; + std::cerr << "handle hardware trap\n"; std::vector callStackDescription = describeCallStack(trapCallStack); switch(trapType) diff --git a/libraries/wasm-jit/Source/Runtime/RuntimePrivate.h b/libraries/wasm-jit/Source/Runtime/RuntimePrivate.h index e8a15e3a2fcf2810b1978eab2ef89758ae30a0dc..c180b31330f697f60da5b2f3fa3a0e48ddbb3a40 100644 --- a/libraries/wasm-jit/Source/Runtime/RuntimePrivate.h +++ b/libraries/wasm-jit/Source/Runtime/RuntimePrivate.h @@ -90,6 +90,8 @@ namespace Runtime MemoryInstance(const MemoryType& inType): GCObject(ObjectKind::memory), type(inType), baseAddress(nullptr), numPages(0), endOffset(0), reservedBaseAddress(nullptr), reservedNumPlatformPages(0) {} ~MemoryInstance() override; + + static MemoryInstance* theMemoryInstance; }; // An instance of a WebAssembly global. diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index a929fc296a657f89720c8da6cbd184d65e94fdf6..59248de08f1868d0dcd8a686aa333947bd05cc9b 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -124,26 +124,6 @@ namespace eosio { ordered_blk_ids req_blocks; }; -#if 0 //disabling block summary support - struct processed_trans_summary { - transaction_id_type id; - vector outmsgs; - }; - - struct thread_ids { - vector gen_trx; // is this necessary to send? - vector user_trx; - }; - - using cycle_ids = vector; - #endif - struct block_summary_message { - signed_block_header block_header; -#if 0 //disabling block summary support - vector trx_ids; -#endif - }; - struct sync_request_message { uint32_t start_block; uint32_t end_block; @@ -155,9 +135,10 @@ namespace eosio { notice_message, request_message, sync_request_message, - block_summary_message, + signed_block_summary, + signed_block, signed_transaction, - signed_block>; + packed_transaction>; } // namespace eosio @@ -170,11 +151,6 @@ FC_REFLECT( eosio::handshake_message, (os)(agent)(generation) ) FC_REFLECT( eosio::go_away_message, (reason)(node_id) ) FC_REFLECT( eosio::time_message, (org)(rec)(xmt)(dst) ) -#if 0 //disabling block summary support -FC_REFLECT( eosio::processed_trans_summary, (id)(outmsgs) ) -FC_REFLECT( eosio::thread_ids, (gen_trx)(user_trx) ) -#endif -FC_REFLECT( eosio::block_summary_message, (block_header)/*(trx_ids)*/ ) FC_REFLECT( eosio::notice_message, (known_trx)(known_blocks) ) FC_REFLECT( eosio::request_message, (req_trx)(req_blocks) ) FC_REFLECT( eosio::sync_request_message, (start_block)(end_block) ) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index aa07ef833da2b281c9025ad79d3465cc6d922228..a3851ec0fa56bcfe6bcfb32dfa87ad288dc13636 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -61,34 +61,27 @@ namespace eosio { struct node_transaction_state { transaction_id_type id; - fc::time_point received; - fc::time_point_sec expires; - fc::time_point_sec true_expires; - vector packed_transaction; /// the received raw bundle - uint32_t block_num = -1; /// block transaction was included in - bool validated = false; /// whether or not our node has validated it - }; - - struct update_block_num { - uint16 new_bnum; - update_block_num(uint16 bnum) : new_bnum(bnum) {} - void operator() (node_transaction_state& nts) { - nts.block_num = static_cast(new_bnum); - } + time_point_sec expires; /// time after which this may be purged. + /// Expires increased while the txn is + /// "in flight" to anoher peer + packed_transaction packed_txn; + vector serialized_txn; /// the received raw bundle + uint32_t block_num = 0; /// block transaction was included in + uint32_t true_block = 0; /// used to reset block_uum when request is 0 + uint16_t requests = 0; /// the number of "in flight" requests for this txn }; struct update_entry { - const signed_transaction &txn; - update_entry(const signed_transaction &msg) : txn(msg) {} + const packed_transaction &txn; + update_entry(const packed_transaction &msg) : txn(msg) {} void operator() (node_transaction_state& nts) { - nts.received = fc::time_point::now(); - nts.validated = true; + nts.packed_txn = txn; net_message msg(txn); uint32_t packsiz = fc::raw::pack_size(msg); uint32_t bufsiz = packsiz + sizeof(packsiz); - nts.packed_transaction.resize(bufsiz); - fc::datastream ds( nts.packed_transaction.data(), bufsiz ); + nts.serialized_txn.resize(bufsiz); + fc::datastream ds( nts.serialized_txn.data(), bufsiz ); ds.write( reinterpret_cast(&packsiz), sizeof(packsiz) ); fc::raw::pack( ds, msg ); } @@ -100,8 +93,16 @@ namespace eosio { void operator() (node_transaction_state& nts) { int32_t exp = nts.expires.sec_since_epoch(); nts.expires = fc::time_point_sec (exp + incr * 60); + if( nts.requests == 0 ) { + nts.true_block = nts.block_num; + nts.block_num = 0; + } + nts.requests += incr; + if( nts.requests == 0 ) { + nts.block_num = nts.true_block; + } } - }; + } incr_in_flight(1), decr_in_flight(-1); struct by_expiry; struct by_block_num; @@ -156,7 +157,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< big_msg_manager > big_msg_master; unique_ptr connector_check; unique_ptr transaction_check; @@ -194,7 +195,7 @@ namespace eosio { template void send_all( const net_message &msg, VerifierFunc verify ); - static void transaction_ready( const packed_transaction& txn); + static void transaction_ready( const transaction_metadata&, const packed_transaction& txn); void broadcast_block_impl( const signed_block &sb); bool is_valid( const handshake_message &msg); @@ -219,9 +220,10 @@ namespace eosio { void handle_message( connection_ptr c, const notice_message &msg); void handle_message( connection_ptr c, const request_message &msg); void handle_message( connection_ptr c, const sync_request_message &msg); - void handle_message( connection_ptr c, const block_summary_message &msg); - void handle_message( connection_ptr c, const signed_transaction &msg); + void handle_message( connection_ptr c, const signed_block_summary &msg); void handle_message( connection_ptr c, const signed_block &msg); + void handle_message( connection_ptr c, const packed_transaction &msg); + void handle_message( connection_ptr c, const signed_transaction &msg); void start_conn_timer( ); void start_txn_timer( ); @@ -300,9 +302,24 @@ namespace eosio { transaction_id_type id; bool is_known_by_peer = false; ///< true if we sent or received this trx to this peer or received notice from peer bool is_noticed_to_peer = false; ///< have we sent peer notice we know it (true if we receive from this peer) - uint32_t block_num = -1; ///< the block number the transaction was included in - time_point validated_time; ///< infinity for unvalidated - time_point requested_time; /// incase we fetch large trx + uint32_t block_num = 0; ///< the block number the transaction was included in + time_point requested_time; /// in case we fetch large trx + }; + + struct update_block_num { + uint32_t new_bnum; + update_block_num(uint32_t bnum) : new_bnum(bnum) {} + void operator() (node_transaction_state& nts) { + if (nts.requests ) { + nts.true_block = new_bnum; + } + else { + nts.block_num = new_bnum; + } + } + void operator() (transaction_state& ts) { + ts.block_num = new_bnum; + } }; typedef multi_index_container< @@ -318,10 +335,19 @@ namespace eosio { struct block_state { block_id_type id; bool is_known; - bool is_noticed_to_peer; + bool is_noticed; time_point requested_time; }; + struct update_request_time { + void operator() (struct transaction_state &ts) { + ts.requested_time = time_point::now(); + } + void operator () (struct block_state &bs) { + bs.requested_time = time_point::now(); + } + } set_request_time; + typedef multi_index_container< block_state, indexed_by< @@ -330,11 +356,14 @@ namespace eosio { > block_state_index; - struct make_known { + struct update_known_by_peer { void operator() (block_state& bs) { bs.is_known = true; } - }; + void operator() (transaction_state& ts) { + ts.is_known_by_peer = true; + } + } set_is_known; /** * Index by start_block_num @@ -372,9 +401,6 @@ namespace eosio { message_buffer<1024*1024> pending_message_buffer; vector blk_buffer; - deque< transaction_id_type > txn_queue; - bool halt_txn_send; - struct queued_write { std::shared_ptr> buff; std::function cb; @@ -385,7 +411,6 @@ namespace eosio { handshake_message last_handshake_recv; handshake_message last_handshake_sent; int16_t sent_handshake_count; - deque out_queue; bool connecting; bool syncing; int write_depth; @@ -463,13 +488,12 @@ namespace eosio { void blk_send(const vector &txn_lis); void stop_send(); - void enqueue( const net_message &msg ); + void enqueue( transaction_id_type id ); + void enqueue( const net_message &msg, bool trigger_send = true ); void cancel_sync(go_away_reason); void cancel_fetch(); void flush_queues(); bool enqueue_sync_block(); - void send_next_message(); - void send_next_txn(); void cancel_wait(); void sync_wait(); @@ -477,7 +501,9 @@ namespace eosio { void sync_timeout(boost::system::error_code ec); void fetch_timeout(boost::system::error_code ec); - void queue_write(std::shared_ptr> buff, std::function cb); + void queue_write(std::shared_ptr> buff, + bool trigger_send, + std::function cb); void do_queue_write(); /** \brief Process the next message from the pending message buffer @@ -534,7 +560,7 @@ namespace eosio { 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_block(connection_ptr c, const signed_block_summary &blk, bool accepted); void recv_handshake(connection_ptr c, const handshake_message& msg); void recv_notice(connection_ptr c, const notice_message& msg); @@ -545,17 +571,17 @@ namespace eosio { class big_msg_manager { public: uint32_t just_send_it_max; + connection_ptr pending_txn_source; 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 bcast_block (const signed_block_summary& msg, connection_ptr skip = connection_ptr()); + void bcast_transaction (const transaction_id_type& id, + time_point_sec expiration, + const packed_transaction& msg); + void bcast_rejected_transaction (const packed_transaction& msg); + void recv_block (connection_ptr conn, const signed_block_summary& msg); + void recv_transaction(connection_ptr c); void recv_notice (connection_ptr conn, const notice_message& msg); static const fc::string logger_name; @@ -582,7 +608,6 @@ namespace eosio { last_handshake_recv(), last_handshake_sent(), sent_handshake_count(0), - out_queue(), connecting(false), syncing(false), write_depth(0), @@ -606,7 +631,6 @@ namespace eosio { last_handshake_recv(), last_handshake_sent(), sent_handshake_count(0), - out_queue(), connecting(true), syncing(false), write_depth(0), @@ -649,13 +673,6 @@ namespace eosio { } void connection::flush_queues() { - if (write_depth > 1) { - while (out_queue.size() > 1) { - out_queue.pop_back(); - } - } else { - out_queue.clear(); - } if (write_depth > 0) { while (write_queue.size() > 1) { write_queue.pop_back(); @@ -685,17 +702,22 @@ namespace eosio { } void connection::txn_send_pending(const vector &ids) { - for(auto t : my_impl->local_txns){ - if(t.packed_transaction.size()) { + for(auto tx = my_impl->local_txns.begin(); tx != my_impl->local_txns.end(); ++tx ){ + if(tx->serialized_txn.size() && tx->block_num == 0) { bool found = false; - for(auto l : ids) { - if( l == t.id) { + for(auto known : ids) { + if( known == tx->id) { found = true; break; } } if(!found) { - txn_queue.push_back( t.id ); + my_impl->local_txns.modify(tx,incr_in_flight); + queue_write(std::make_shared>(tx->serialized_txn), + true, + [this, tx](boost::system::error_code ec, std::size_t ) { + my_impl->local_txns.modify(tx, decr_in_flight); + }); } } } @@ -703,10 +725,14 @@ namespace eosio { void connection::txn_send(const vector &ids) { for(auto t : ids) { - auto n = my_impl->local_txns.get().find(t); - if(n != my_impl->local_txns.end() && - n->packed_transaction.size()) { - txn_queue.push_back( t ); + auto tx = my_impl->local_txns.get().find(t); + if( tx != my_impl->local_txns.end() && tx->serialized_txn.size()) { + my_impl->local_txns.modify( tx,incr_in_flight); + queue_write(std::make_shared>(tx->serialized_txn), + true, + [this, tx](boost::system::error_code ec, std::size_t ) { + my_impl->local_txns.modify(tx, decr_in_flight); + }); } } } @@ -778,6 +804,7 @@ namespace eosio { try { optional b = cc.fetch_block_by_id(blkid); if(b) { + fc_dlog(logger,"found block for id at num ${n}",("n",b->block_num())); enqueue(*b); } else { @@ -797,11 +824,11 @@ namespace eosio { break; } } + } void connection::stop_send() { syncing = false; - txn_queue.clear(); } void connection::send_handshake( ) { @@ -838,16 +865,11 @@ namespace eosio { enqueue(xpkt); } - void connection::enqueue( const net_message &m ) { - out_queue.push_back( m ); - if( out_queue.size() == 1 ) { - send_next_message(); - } - } - - void connection::queue_write(std::shared_ptr> buff, std::function cb) { + void connection::queue_write(std::shared_ptr> buff, + bool trigger_send, + std::function cb) { write_queue.push_back({buff, cb}); - if(write_queue.size() == 1) + if(write_queue.size() == 1 && trigger_send) do_queue_write(); } @@ -879,6 +901,7 @@ namespace eosio { return; } conn->write_queue.pop_front(); + conn->enqueue_sync_block(); conn->do_queue_write(); } catch(const std::exception &ex) { @@ -900,8 +923,8 @@ namespace eosio { } void connection::cancel_sync(go_away_reason reason) { - fc_dlog(logger,"cancel sync reason = ${m}, out queue size ${o} peer ${p}", - ("m",reason_str(reason)) ("o", out_queue.size())("p", peer_name())); + fc_dlog(logger,"cancel sync reason = ${m}, write queue size ${o} peer ${p}", + ("m",reason_str(reason)) ("o", write_queue.size())("p", peer_name())); cancel_wait(); flush_queues(); switch (reason) { @@ -922,15 +945,17 @@ namespace eosio { bool connection::enqueue_sync_block() { chain_controller& cc = app().find_plugin()->chain(); + if (!sync_requested) + return false; uint32_t num = ++sync_requested->last; - + bool trigger_send = num == sync_requested->start_block; if(num == sync_requested->end_block) { sync_requested.reset(); } try { fc::optional sb = cc.fetch_block_by_number(num); if(sb) { - enqueue( *sb ); + enqueue( *sb, trigger_send); return true; } } catch ( ... ) { @@ -939,21 +964,18 @@ namespace eosio { return false; } - void connection::send_next_message() { - if( !out_queue.size() ) { - if( !sync_requested || !enqueue_sync_block( ) ) { - send_next_txn(); - } - return; - } - - auto& m = out_queue.front(); + void connection::enqueue( const net_message &m, bool trigger_send ) { + bool close_after_send = false; if(m.contains()) { sync_wait( ); - } else if(m.contains()) { + } + else if(m.contains()) { pending_fetch = m.get(); fetch_wait( ); } + else { + close_after_send = m.contains(); + } uint32_t payload_size = fc::raw::pack_size( m ); char * header = reinterpret_cast(&payload_size); @@ -965,57 +987,18 @@ namespace eosio { fc::datastream ds( send_buffer->data(), buffer_size); ds.write( header, header_size ); fc::raw::pack( ds, m ); - write_depth++; - queue_write(send_buffer, - [this](boost::system::error_code ec, std::size_t ) { + queue_write(send_buffer,trigger_send, + [this, close_after_send](boost::system::error_code ec, std::size_t ) { write_depth--; - if(out_queue.size()) { - if(out_queue.front().contains()) { - elog ("sent a go away message, closing connection to ${p}",("p",peer_name())); - my_impl->close(shared_from_this()); - return; - } - out_queue.pop_front(); + if(close_after_send) { + elog ("sent a go away message, closing connection to ${p}",("p",peer_name())); + my_impl->close(shared_from_this()); + return; } - send_next_message(); }); } - void connection::send_next_txn() { - if( !txn_queue.size() || halt_txn_send) { - return; - } - - size_t limit = min(txn_queue.size(),size_t(1000)); - // we'll make this fc_dlog later - elog("sending up to ${limit} pending transactions to ${p}",("limit",limit)("p",peer_name())); - - size_t count = 0; - connection_wptr c(shared_from_this()); - for(size_t i = 0; i < limit; i++) { - transaction_id_type id = txn_queue.front(); - const auto &tx = my_impl->local_txns.get( ).find( id ); - if( tx == my_impl->local_txns.end() || - tx->true_expires <= time_point::now() || - tx->packed_transaction.size() == 0 ) { - txn_queue.pop_front(); - continue; - } - my_impl->local_txns.modify( tx,update_in_flight(1)); - count++; - txn_queue.pop_front(); - - queue_write(std::make_shared>(tx->packed_transaction), - [this, tx](boost::system::error_code ec, std::size_t ) { - my_impl->local_txns.modify(tx, update_in_flight(-1)); - send_next_message(); - }); - } - // we'll make this fc_dlog later - elog("actually sent ${limit} pending transactions to ${p}",("limit",limit)("p",peer_name())); - } - void connection::cancel_wait() { if (response_expected) response_expected->cancel(); @@ -1381,7 +1364,7 @@ namespace eosio { } } - void sync_manager::recv_block (connection_ptr c, const signed_block &blk, bool accepted) { + void sync_manager::recv_block (connection_ptr c, const signed_block_summary &blk, bool accepted) { if (!accepted) { uint32_t head_num = chain_plug->chain().head_block_num(); if (head_num != last_repeated) { @@ -1399,16 +1382,17 @@ namespace eosio { } last_repeated = 0; + uint32_t blk_num = blk.block_num(); if (state == head_catchup) { fc_dlog (logger, "sync_manager in head_catchup state"); state = in_sync; + block_id_type null_id; for (auto cp : my_impl->connections) { - if (cp->fork_head == block_id_type()) { + if (cp->fork_head == null_id) { continue; } - if (cp->fork_head == blk.id() || - cp->fork_head_num < blk.block_num()) { - c->fork_head = block_id_type(); + if (cp->fork_head == blk.id() || cp->fork_head_num < blk_num) { + c->fork_head = null_id; c->fork_head_num = 0; } else { @@ -1417,14 +1401,13 @@ namespace eosio { } } else if (state == lib_catchup) { - uint32_t num = blk.block_num(); - if( num == sync_known_lib_num ) { + if( blk_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) { + else if (blk_num == sync_last_requested_num) { request_next_chunk(); } else { @@ -1435,29 +1418,24 @@ namespace eosio { //------------------------------------------------------------------------ - 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 big_msg_manager::bcast_block (const signed_block& sb, connection_ptr skip) { - net_message msg(sb); + void big_msg_manager::bcast_block (const signed_block_summary &bsum, connection_ptr skip) { + net_message msg(bsum); uint32_t packsiz = fc::raw::pack_size(msg); uint32_t msgsiz = packsiz + sizeof(packsiz); notice_message pending_notify; - block_id_type bid = sb.id(); + block_id_type bid = bsum.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) { + fc_ilog(logger, "block size is ${ms}, sending notify",("ms", msgsiz)); 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() })); + c->blk_state.insert((block_state){bid,false,true,time_point()}); } else { elog("${p} already has knowledge of block ${b}", ("p",c->peer_name())("b",bid)); @@ -1466,56 +1444,75 @@ namespace eosio { }); } 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() })); + const auto& prev = cp->blk_state.find (bsum.previous); + if (prev != cp->blk_state.end() && !prev->is_known) { + cp->blk_state.insert((block_state){bid,false,true,time_point()}); cp->enqueue( pending_notify ); } else { - cp->enqueue( sb ); + cp->blk_state.insert((block_state){bid,true,true,time_point()}); + cp->enqueue( bsum ); } } } } - void big_msg_manager::bcast_transaction (const signed_transaction& txn, connection_ptr skip) { - transaction_id_type txnid = txn.id(); + void big_msg_manager::bcast_rejected_transaction (const packed_transaction& txn) { + transaction_id_type tid = txn.get_transaction().id(); + fc_wlog(logger,"sending rejected transaction ${tid}",("tid",tid)); + bcast_transaction (tid, time_point_sec(), txn); + } + + void big_msg_manager::bcast_transaction (const transaction_id_type & txnid, + time_point_sec expiration, + const packed_transaction& txn) { + connection_ptr skip; + for (auto ref = req_txn.begin(); ref != req_txn.end(); ++ref) { + if (*ref == txnid) { + skip = pending_txn_source; + pending_txn_source.reset(); + req_txn.erase(ref); + break; + } + } + 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 ) { + bool remember = expiration != time_point_sec(); + uint32_t packsiz = 0; + uint32_t bufsiz = 0; + if (remember) { + net_message msg(txn); + packsiz = fc::raw::pack_size(msg); + 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 ); + node_transaction_state nts = {txnid, + expiration, + txn, + std::move(buff), + 0, 0, 0}; + my_impl->local_txns.insert(std::move(nts)); + } + if( !skip && bufsiz <= just_send_it_max) { + my_impl->send_all( txn, [remember,txnid](connection_ptr c) -> bool { + if( 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() })); + if (remember) { + c->trx_state.insert(transaction_state({txnid,true,true,0,time_point() })); + } fc_dlog(logger, "sending whole txn to ${n}", ("n",c->peer_name() ) ); } return unknown; @@ -1526,17 +1523,17 @@ namespace eosio { 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 { + my_impl->send_all(pending_notify, [skip, remember, 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() })); + fc_ilog(logger, "sending notice to ${n}", ("n",c->peer_name() ) ); + if (remember) { + c->trx_state.insert(transaction_state({txnid,false,true,0, time_point() })); + } } return unknown; }); @@ -1544,53 +1541,31 @@ namespace eosio { } - 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) { + void big_msg_manager::recv_block (connection_ptr c, const signed_block_summary& msg) { + block_id_type blk_id = msg.id(); + uint32_t num = msg.block_num(); 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; + fc_dlog(logger, "received a requested block"); + 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() })); + } + return unknown; + }); + return; } } - 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)) { + if( !my_impl->sync_master->is_active(c) ) { + fc_dlog(logger,"got a block to forward"); net_message nmsg(msg); if(fc::raw::pack_size(nmsg) < just_send_it_max ) { fc_dlog(logger, "forwarding the signed block"); @@ -1602,42 +1577,39 @@ namespace eosio { 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()); + conn->blk_state.modify(b,set_is_known); sendit = true; } } - fc_dlog(logger, "${action} block ${num} to ${c}",("action", sendit ? "sending " : "skipping ")("num",num)("c", conn->peer_name() )); + fc_dlog(logger, "${action} block ${num} to ${c}", + ("action", sendit ? "sending" : "skipping") + ("num",num) + ("c", conn->peer_name() )); return sendit; }); } + else { + 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() })); + } + return unknown; + }); + } } 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_transaction (connection_ptr c) { + pending_txn_source = c; } void big_msg_manager::recv_notice (connection_ptr c, const notice_message& msg) { @@ -1651,8 +1623,8 @@ namespace eosio { 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( ) } ); + c->trx_state.insert( (transaction_state){t,true,true,0, + time_point()} ); req.req_trx.ids.push_back( t ); req_txn.push_back( t ); @@ -1676,10 +1648,8 @@ namespace eosio { } 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()}); + if (!b) { + c->blk_state.insert((block_state){blkid,true,true,time_point::now()}); send_req = true; req.req_blocks.ids.push_back( blkid ); req_blks.push_back( blkid ); @@ -2100,7 +2070,7 @@ namespace eosio { break; } case normal: { - bm_master->recv_notice (c, msg); + big_msg_master->recv_notice (c, msg); } } @@ -2119,7 +2089,7 @@ namespace eosio { break; } case normal : { - bm_master->recv_notice (c, msg); + big_msg_master->recv_notice (c, msg); break; } default: { @@ -2139,7 +2109,7 @@ namespace eosio { c->blk_send_branch( ); break; case normal : - fc_dlog(logger, "got a normal request_message from ${p}", ("p",c->peer_name())); + fc_dlog(logger, "got a normal block request_message from ${p}", ("p",c->peer_name())); c->blk_send(msg.req_blocks.ids); break; default:; @@ -2172,51 +2142,19 @@ namespace eosio { } } - void net_plugin_impl::handle_message( connection_ptr , const block_summary_message &) { -#if 0 // function is obsolete -#endif - } - - - void net_plugin_impl::handle_message( connection_ptr c, const signed_transaction &msg) { + void net_plugin_impl::handle_message( connection_ptr c, const packed_transaction &msg) { fc_dlog(logger, "got a signed transaction from ${p}", ("p",c->peer_name())); - transaction_id_type txnid = msg.id(); - auto entry = local_txns.get().find( txnid ); - if(entry != local_txns.end( ) ) { - if( entry->validated ) { - fc_dlog(logger, "the txnid is known and validated, so short circuit" ); - return; - } - } if( sync_master->is_active(c) ) { fc_dlog(logger, "got a txn during sync - dropping"); return; } - if(entry != local_txns.end( ) ) { - local_txns.modify( entry, update_entry( msg ) ); - } - - auto tx = c->trx_state.find(txnid); - if( tx == c->trx_state.end()) { - c->trx_state.insert((transaction_state){txnid,true,true,(uint32_t)msg.ref_block_num, - fc::time_point(),fc::time_point()}); - } else { - struct trx_mod { - uint16 block; - trx_mod( uint16 bn) : block(bn) {} - void operator( )( transaction_state &t) { - t.is_known_by_peer = true; - t.block_num = static_cast(block); - } - }; - c->trx_state.modify(tx,trx_mod(msg.ref_block_num)); - } + big_msg_master->recv_transaction(c); try { - // TODO: avoid this reserialization by adjusting messages to deal with packed transactions. - chain_plug->accept_transaction( packed_transaction(msg) ); + chain_plug->accept_transaction( msg); fc_dlog(logger, "chain accepted transaction" ); + return; } catch( const fc::exception &ex) { // received a block due to out of sequence elog( "accept txn threw ${m}",("m",ex.to_detail_string())); @@ -2225,9 +2163,89 @@ namespace eosio { elog( " caught something attempting to accept transaction"); } + big_msg_master->bcast_rejected_transaction(msg); + } + + void net_plugin_impl::handle_message( connection_ptr c, const signed_transaction &msg) { + } + + void net_plugin_impl::handle_message( connection_ptr c, const signed_block_summary &msg) { + chain_controller &cc = chain_plug->chain(); + block_id_type blk_id = msg.id(); + 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"); + } + + fc::microseconds age( fc::time_point::now() - msg.timestamp); + fc_dlog(logger, "got signed_block_summary #${n} from ${p} block age in secs = ${age}", + ("n",blk_num)("p",c->peer_name())("age",age.to_seconds())); + + signed_block sb(msg); + update_block_num ubn(blk_num); + for (const auto ®ion : sb.regions) { + for (const auto &cycle_sum : region.cycles_summary) { + for (const auto &shard : cycle_sum) { + for (const auto &recpt : shard.transactions) { + auto ltx = local_txns.get().find(recpt.id); + switch (recpt.status) { + case transaction_receipt::executed: { + if( ltx == local_txns.end()) { + fc_elog (logger,"summary references unknown transaction ${rid}",("rid",recpt.id)); + close (c); // close without go away allows reconnect + return; + } + sb.input_transactions.push_back(ltx->packed_txn); + local_txns.modify( ltx, ubn ); + break; + } + case transaction_receipt::soft_fail: + case transaction_receipt::hard_fail: { + if( ltx != local_txns.end()) { + sb.input_transactions.push_back(ltx->packed_txn); + local_txns.modify( ltx, ubn ); + auto ctx = c->trx_state.get().find(recpt.id); + if( ctx != c->trx_state.end()) { + c->trx_state.modify( ctx, ubn ); + } + } + break; + }} + } + } + } + } + + go_away_reason reason = fatal_other; + try { + chain_plug->accept_block(sb, 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())); + } + big_msg_master->recv_block (c, msg); + sync_master->recv_block (c, msg, reason == no_reason); } void net_plugin_impl::handle_message( connection_ptr c, const signed_block &msg) { + // should only be during synch or rolling upgrade chain_controller &cc = chain_plug->chain(); block_id_type blk_id = msg.id(); uint32_t blk_num = msg.block_num(); @@ -2264,8 +2282,25 @@ namespace eosio { elog( "handle sync block caught something else from ${p}",("num",blk_num)("p",c->peer_name())); } + update_block_num ubn(blk_num); if( reason == no_reason ) { - bm_master->recv_block (c, msg); + for (const auto ®ion : msg.regions) { + for (const auto &cycle_sum : region.cycles_summary) { + for (const auto &shard : cycle_sum) { + for (const auto &recpt : shard.transactions) { + auto ltx = local_txns.get().find(recpt.id); + if( ltx != local_txns.end()) { + local_txns.modify( ltx, ubn ); + } + auto ctx = c->trx_state.get().find(recpt.id); + if( ctx != c->trx_state.end()) { + c->trx_state.modify( ctx, ubn ); + } + } + } + } + } + big_msg_master->recv_block (c, msg); } sync_master->recv_block (c, msg, reason == no_reason); } @@ -2324,11 +2359,12 @@ namespace eosio { auto ex_up = old.upper_bound( time_point::now()); auto ex_lo = old.lower_bound( fc::time_point_sec( 0)); old.erase( ex_lo, ex_up); + auto &stale = local_txns.get(); chain_controller &cc = chain_plug->chain(); uint32_t bn = cc.last_irreversible_block_num(); auto bn_up = stale.upper_bound(bn); - auto bn_lo = stale.lower_bound(0); + auto bn_lo = stale.lower_bound(1); stale.erase( bn_lo, bn_up); } @@ -2368,12 +2404,16 @@ namespace eosio { /** * This one is necessary to hook into the boost notifier api **/ - void net_plugin_impl::transaction_ready( const packed_transaction& txn) { - my_impl->bm_master->bcast_transaction( txn ); + void net_plugin_impl::transaction_ready(const transaction_metadata& md, const packed_transaction& txn) { + time_point_sec expire; + if (md.decompressed_trx) { + expire = md.decompressed_trx->expiration; + } + my_impl->big_msg_master->bcast_transaction(md.id, expire, txn); } void net_plugin_impl::broadcast_block_impl( const chain::signed_block &sb) { - bm_master->bcast_block(sb); + big_msg_master->bcast_block(sb); } bool net_plugin_impl::authenticate_peer(const handshake_message& msg) const { @@ -2574,12 +2614,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->big_msg_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->bm_master->just_send_it_max = def_max_just_send; + my->big_msg_master->just_send_it_max = def_max_just_send; my->max_client_count = options.at("max-clients").as(); my->num_clients = 0; diff --git a/scripts/eosio-build_darwin.sh b/scripts/eosio-build_darwin.sh new file mode 100644 index 0000000000000000000000000000000000000000..04b034158481586a9c6711109338b37c90cbe613 --- /dev/null +++ b/scripts/eosio-build_darwin.sh @@ -0,0 +1,224 @@ + OS_VER=`sw_vers -productVersion` + OS_MAJ=`echo "${OS_VER}" | cut -d'.' -f1` + OS_MIN=`echo "${OS_VER}" | cut -d'.' -f2` + OS_PATCH=`echo "${OS_VER}" | cut -d'.' -f3` + + MEM_GIG=`bc <<< "($(sysctl -in hw.memsize) / 1024000000)"` + + CPU_SPEED=`bc <<< "scale=2; ($(sysctl -in hw.cpufrequency) / 100000000) / 10"` + CPU_CORE=$( sysctl -in machdep.cpu.core_count ) + + DISK_TOTAL=`df -H $PWD | grep /dev | tr -s ' ' | cut -d\ -f2 | sed 's/[^0-9]//'` + DISK_AVAIL=`df -H $PWD | grep /dev | tr -s ' ' | cut -d\ -f4 | sed 's/[^0-9]//'` + + printf "\n\tOS name: $ARCH\n" + printf "\tOS Version: ${OS_VER}\n" + printf "\tCPU speed: ${CPU_SPEED}Ghz\n" + printf "\tCPU cores: $CPU_CORE\n" + printf "\tPhysical Memory: $MEM_GIG Gbytes\n" + printf "\tDisk space total: ${DISK_TOTAL}G\n" + printf "\tDisk space available: ${DISK_AVAIL}G\n\n" + + if [ $MEM_GIG -lt 8 ]; then + printf "\tYour system must have 8 or more Gigabytes of physical memory installed.\n" + printf "\tExiting now.\n" + exit 1 + fi + + if [ $OS_MIN -lt 12 ]; then + printf "\tYou must be running Mac OS 10.12.x or higher to install EOSIO.\n" + printf "\tExiting now.\n" + exit 1 + fi + + if [ $DISK_AVAIL -lt 100 ]; then + printf "\tYou must have at least 100GB of available storage to install EOSIO.\n" + printf "\tExiting now.\n" + exit 1 + fi + + process_dep() + { + printf "\tChecking XCode installation\n" + XCODESELECT=$(which xcode-select) + if [ $? -ne 0 ]; then + printf "\n\tXCode must be installed in order to proceed.\n\n" + printf "\texiting now.\n" + exit 1 + fi + + printf "\tXCode installation found.\n\n" + + printf "\tChecking Ruby installation\n" + RUBY=$(which ruby) + if [ $? -ne 0 ]; then + printf "\nRuby must be installed in order to proceed.\n\n" + printf "\texiting now.\n" + exit 1 + fi + + printf "\tRuby installation found.\n\n" + + printf "\tChecking Home Brew installation\n" + BREW=$(which brew) + if [ $? -ne 0 ]; then + printf "\tHomebrew must be installed to compile EOS.IO\n\n" + printf "\tDo you wish to install Home Brew?\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + $XCODESELECT --install 2>/dev/null; + $RUBY -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + if [ $? -ne 0 ]; then + echo "User aborted homebrew installation. Exiting now." + exit 0; + fi + break;; + [Nn]* ) echo "User aborted homebrew installation. Exiting now."; + exit;; + * ) echo "Please enter 1 for yes or 2 for no.";; + esac + done + fi + + printf "\tHome Brew installation found.\n\n" + # DEPS="git automake libtool openssl cmake wget boost llvm@4 gmp gettext" + DCOUNT=0 + COUNT=1 + PERMISSION_GETTEXT=0 + DISPLAY="" + DEP="" + + printf "\tChecking dependencies.\n" + for line in `cat ${WORK_DIR}/scripts/eosio_build_dep`; do + pkg=$( echo "${line}" | cut -d',' -f1 ) + printf "\tChecking $pkg ... " + BIN=$(which $pkg) + if [ $? -eq 0 ]; then + printf "\t$pkg found\n" + continue + fi + + LIB=$( ls -l /usr/local/lib/lib${pkg}* 2>/dev/null | wc -l) + if [ ${LIB} -ne 0 ]; then + printf "\t$pkg found\n" + continue + else + let DCOUNT++ + + if [ $pkg = "LLVM" ]; then + pkg="llvm@4" + fi + + if [ $pkg = "gettext" ]; then + PERMISSION_GETTEXT=1 + fi + + DEP=$DEP" ${pkg} " + DISPLAY="${DISPLAY}${COUNT}. ${pkg}\n\t" + printf "\tPackage ${pkg} ${bldred}NOT${txtrst} found.\n" + let COUNT++ + fi + done + + if [ $DCOUNT -ne 0 ]; then + printf "\n\tThe following dependencies are required to install EOSIO.\n" + printf "\n\t$DISPLAY\n\n" + echo "Do you wish to install these packages?" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + if [ $PERMISSION_GETTEXT -eq 1 ]; then + sudo chown -R $(whoami) /usr/local/share + fi + + $XCODESELECT --install 2>/dev/null; + printf "\tUpdating Home Brew.\n" + brew update + printf "\tInstalling Dependencies.\n" + brew install --force $DEP + brew unlink $DEP && brew link --force $DEP + break;; + [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac + done + else + printf "\n\tNo required Home Brew dependencies to install.\n" + fi + + return 0 + } + + process_dep + + printf "\n\tChecking for secp256k1-zkp\n" + # install secp256k1-zkp (Cryptonomex branch) + if [ ! -e /usr/local/lib/libsecp256k1.a ]; then + cd ${TEMP_DIR} + git clone https://github.com/cryptonomex/secp256k1-zkp.git + cd secp256k1-zkp + ./autogen.sh + if [ $? -ne 0 ]; then + printf "\tError running autogen\n" + printf "\tExiting now.\n\n" + exit; + fi + ./configure + make + if [ $? -ne 0 ]; then + printf "\tError compiling secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + sudo make install + sudo rm -rf ${TEMP_DIR}/secp256k1-zkp + else + printf "\tsecp256k1 found at /usr/local/lib/\n" + fi + + printf "\n\tChecking for binaryen\n" + if [ ! -e /usr/local/binaryen/bin/binaryen.js ]; then + cd ${TEMP_DIR} + git clone https://github.com/WebAssembly/binaryen + cd binaryen + git checkout tags/1.37.14 + cmake . && make + if [ $? -ne 0 ]; then + printf "\tError compiling binaryen.\n" + printf "\tExiting now.\n\n" + exit; + fi + sudo mkdir /usr/local/binaryen + sudo mv ${TEMP_DIR}/binaryen/bin /usr/local/binaryen + sudo ln -s /usr/local/binaryen/bin/* /usr/local + sudo rm -rf ${TEMP_DIR}/binaryen + else + printf "\tBinaryen found at /usr/local/binaryen/bin/\n" + fi + + printf "\n\tChecking for WASM\n" + if [ ! -d /usr/local/wasm/bin ]; then + # Build LLVM and clang for WASM: + cd ${TEMP_DIR} + mkdir wasm-compiler + cd wasm-compiler + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + cd llvm/tools + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + cd .. + mkdir build + cd build + sudo cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr/local/wasm \ + -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly \ + -DCMAKE_BUILD_TYPE=Release ../ + if [ $? -ne 0 ]; then + printf "\tError compiling WASM.\n" + printf "\tExiting now.\n\n" + exit; + fi + sudo make -j4 install + sudo rm -rf ${TEMP_DIR}/wasm-compiler + else + printf "\tWASM found at /usr/local/wasm/bin/\n" + fi diff --git a/scripts/eosio-build_dep b/scripts/eosio-build_dep new file mode 100644 index 0000000000000000000000000000000000000000..7ecd9f0eadbdca7bc87ab2cffb984df60bfd3211 --- /dev/null +++ b/scripts/eosio-build_dep @@ -0,0 +1,9 @@ +automake,http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz +libtool,http://gnu.askapache.com/libtool/libtool-2.4.6.tar.gz +openssl,https://www.openssl.org/source/openssl-1.0.2n.tar.gz +LLVM,http://releases.llvm.org/5.0.1/llvm-5.0.1.src.tar.xz +wget,https://ftp.gnu.org/gnu/wget/wget-1.19.2.tar.gz +cmake,https://cmake.org/files/v3.10/cmake-3.10.1-Darwin-x86_64.tar.gz +boost,https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz +gmp,https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.bz2 +gettext,https://ftp.gnu.org/pub/gnu/gettext/gettext-latest.tar.gz diff --git a/scripts/eosio-build_fedora.sh b/scripts/eosio-build_fedora.sh new file mode 100644 index 0000000000000000000000000000000000000000..fdf3cc71c2fbf9b969aee4abaabde032b55c7842 --- /dev/null +++ b/scripts/eosio-build_fedora.sh @@ -0,0 +1,198 @@ + OS_VER=$( cat /etc/os-release | grep VERSION_ID | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' ) + + MEM_MEG=$( free -m | grep Mem | tr -s ' ' | cut -d\ -f2 ) + + CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) + CPU_CORE=$( lscpu | grep "^CPU(s)" | tr -s ' ' | cut -d\ -f2 ) + + DISK_TOTAL=`df -h / | grep /dev | tr -s ' ' | cut -d\ -f2 | sed 's/[^0-9]//'` + DISK_AVAIL=`df -h / | grep /dev | tr -s ' ' | cut -d\ -f4 | sed 's/[^0-9]//'` + + printf "\n\tOS name: $OS_NAME\n" + printf "\tOS Version: ${OS_VER}\n" + printf "\tCPU speed: ${CPU_SPEED}Mhz\n" + printf "\tCPU cores: $CPU_CORE\n" + printf "\tPhysical Memory: $MEM_MEG Mgb\n" + printf "\tDisk space total: ${DISK_TOTAL}G\n" + printf "\tDisk space available: ${DISK_AVAIL}G\n" + + if [ $MEM_MEG -lt 4000 ]; then + echo "Your system must have 8 or more Gigabytes of physical memory installed." + echo "exiting now." + exit 1 + fi + + if [ $OS_VER -lt 25 ]; then + echo "You must be running Fedora 25 or higher to install EOSIO." + echo "exiting now" + exit 1 + fi + + if [ $DISK_AVAIL -lt 100 ]; then + echo "You must have at least 100GB of available storage to install EOSIO." + echo "exiting now" + exit 1 + fi + + printf "\n\tChecking Yum installation\n" + + YUM=$( which yum 2>/dev/null ) + if [ $? -ne 0 ]; then + printf "\n\tYum must be installed to compile EOS.IO.\n" + printf "\n\tExiting now.\n" + exit 0 + fi + + printf "\tYum installation found at ${YUM}.\n" + printf "\tUpdating YUM.\n" + UPDATE=$( sudo yum update ) + + if [ $? -ne 0 ]; then + printf "\n\tYUM update failed.\n" + printf "\n\tExiting now.\n" + exit 1 + fi + + printf "\t${UPDATE}\n" + DEP_ARRAY=( git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make cmake.x86_64 bzip2 bzip2-devel.x86_64 openssl-devel.x86_64 gmp.x86_64 gmp-devel.x86_64 libstdc++-devel.x86_64 python3-devel.x86_64 libedit.x86_64 ncurses-devel.x86_64 swig.x86_64 ) + DCOUNT=0 + COUNT=1 + DISPLAY="" + DEP="" + + printf "\n\tChecking YUM for installed dependencies.\n\n" + + for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); + do + pkg=$( sudo $YUM info ${DEP_ARRAY[$i]} 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + + if [ "$pkg" != "@System" ]; then + DEP=$DEP" ${DEP_ARRAY[$i]} " + DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\n\t" + printf "\tPackage ${DEP_ARRAY[$i]} ${bldred} NOT ${txtrst} found.\n" + let COUNT++ + let DCOUNT++ + else + printf "\tPackage ${DEP_ARRAY[$i]} found.\n" + continue + fi + done + + if [ ${DCOUNT} -ne 0 ]; then + printf "\n\tThe following dependencies are required to install EOSIO.\n" + printf "\n\t$DISPLAY\n\n" + printf "\tDo you wish to install these dependencies?\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\n\n\tInstalling dependencies\n\n" + sudo yum -y install ${DEP} + if [ $? -ne 0 ]; then + printf "\n\tYUM dependency installation failed.\n" + printf "\n\tExiting now.\n" + exit 1 + else + printf "\n\tYUM dependencies installed successfully.\n" + fi + break;; + [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac + done + else + printf "\n\tNo required YUM dependencies to install.\n" + fi + + printf "\n\tChecking for boost libraries\n" + if [ ! -d ${HOME}/opt/boost_1_66_0 ]; then + # install boost + printf "\tInstalling boost libraries\n" + cd ${TEMP_DIR} + curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2 + tar xf boost_1.66.0.tar.bz2 + cd boost_1_66_0/ + ./bootstrap.sh "--prefix=$BOOST_ROOT" + ./b2 install + rm -rf ${TEMP_DIR}/boost_1_66_0/ + rm -f ${TEMP_DIR}/boost_1.66.0.tar.bz2 + else + printf "\tBoost 1.66 found at ${HOME}/opt/boost_1_66_0\n" + fi + + printf "\n\tChecking for secp256k1-zkp\n" + # install secp256k1-zkp (Cryptonomex branch) + if [ ! -e /usr/local/lib/libsecp256k1.a ]; then + printf "\tInstalling secp256k1-zkp (Cryptonomex branch)\n" + cd ${TEMP_DIR} + git clone https://github.com/cryptonomex/secp256k1-zkp.git + cd secp256k1-zkp + ./autogen.sh + if [ $? -ne 0 ]; then + printf "\tError running autogen for secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + ./configure + make + if [ $? -ne 0 ]; then + printf "\tError compiling secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + sudo make install + rm -rf cd ${TEMP_DIR}/secp256k1-zkp + else + printf "\tsecp256k1 found\n" + fi + + printf "\n\tChecking for binaryen\n" + if [ ! -d ${HOME}/opt/binaryen ]; then + # Install binaryen v1.37.14: + printf "\tInstalling binaryen v1.37.14:\n" + cd ${TEMP_DIR} + git clone https://github.com/WebAssembly/binaryen + cd binaryen + git checkout tags/1.37.14 + cmake . && make + if [ $? -ne 0 ]; then + printf "\tError compiling binaryen.\n" + printf "\tExiting now.\n\n" + exit; + fi + mkdir -p ${HOME}/opt/binaryen/ 2>/dev/null + mv ${TEMP_DIR}/binaryen/bin ${HOME}/opt/binaryen/ + rm -rf ${TEMP_DIR}/binaryen + else + printf "\tBinaryen found at ${HOME}/opt/binaryen\n" + fi + + printf "\n\tChecking for LLVM with WASM support.\n" + if [ ! -d ${HOME}/opt/wasm/bin ]; then + # Build LLVM and clang with EXPERIMENTAL WASM support: + printf "\tInstalling LLVM & WASM\n" + cd ${TEMP_DIR} + mkdir llvm-compiler 2>/dev/null + cd llvm-compiler + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + cd llvm/tools + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + cd .. + mkdir build + cd build + cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=${HOME}/opt/wasm -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ + if [ $? -ne 0 ]; then + printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" + printf "\tExiting now.\n\n" + exit; + fi + make -j$(nproc) + if [ $? -ne 0 ]; then + printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" + printf "\tExiting now.\n\n" + exit; + fi + make install + rm -rf ${TEMP_DIR}/llvm-compiler 2>/dev/null + else + printf "\tWASM found at ${HOME}/opt/wasm\n" + fi diff --git a/scripts/eosio-build_ubuntu.sh b/scripts/eosio-build_ubuntu.sh new file mode 100644 index 0000000000000000000000000000000000000000..e8eb8764e915b4109b14ee390a3ced9e00b12a47 --- /dev/null +++ b/scripts/eosio-build_ubuntu.sh @@ -0,0 +1,179 @@ + OS_VER=$( cat /etc/os-release | grep VERSION_ID | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' ) + OS_MAJ=`echo "${OS_VER}" | cut -d'.' -f1` + OS_MIN=`echo "${OS_VER}" | cut -d'.' -f2` + + MEM_MEG=$( free -m | grep Mem | tr -s ' ' | cut -d\ -f2 ) + + CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) + CPU_CORE=$( lscpu | grep "^CPU(s)" | tr -s ' ' | cut -d\ -f2 ) + + DISK_TOTAL=`df -h / | grep /dev | tr -s ' ' | cut -d\ -f2 | sed 's/[^0-9]//'` + DISK_AVAIL=`df -h / | grep /dev | tr -s ' ' | cut -d\ -f4 | sed 's/[^0-9]//'` + + printf "\n\tOS name: $OS_NAME\n" + printf "\tOS Version: ${OS_VER}\n" + printf "\tCPU speed: ${CPU_SPEED}Mhz\n" + printf "\tCPU cores: $CPU_CORE\n" + printf "\tPhysical Memory: $MEM_MEG Mgb\n" + printf "\tDisk space total: ${DISK_TOTAL}G\n" + printf "\tDisk space available: ${DISK_AVAIL}G\n" + + if [ $MEM_MEG -lt 4000 ]; then + echo "Your system must have 8 or more Gigabytes of physical memory installed." + echo "exiting now." + exit 1 + fi + + if [ $OS_MIN -lt 4 ]; then + echo "You must be running Ubuntu 16.04.x or higher to install EOSIO." + echo "exiting now" + exit 1 + fi + + if [ $DISK_AVAIL -lt 100 ]; then + echo "You must have at least 100GB of available storage to install EOSIO." + echo "exiting now" + exit 1 + fi + + DEP_ARRAY=(clang-4.0 lldb-4.0 libclang-4.0-dev cmake make libbz2-dev libssl-dev libgmp3-dev autotools-dev build-essential libbz2-dev libicu-dev python-dev autoconf libtool curl) + DCOUNT=0 + COUNT=1 + DISPLAY="" + DEP="" + + printf "\n\tChecking for installed dependencies.\n\n" + + for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); + do + pkg=$( dpkg -s ${DEP_ARRAY[$i]} 2>/dev/null | grep Status | tr -s ' ' | cut -d\ -f4 ) + if [ -z "$pkg" ]; then + DEP=$DEP" ${DEP_ARRAY[$i]} " + DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\n\t" + printf "\tPackage ${DEP_ARRAY[$i]} ${bldred} NOT ${txtrst} found.\n" + let COUNT++ + let DCOUNT++ + else + printf "\tPackage ${DEP_ARRAY[$i]} found.\n" + continue + fi + done + + if [ ${DCOUNT} -ne 0 ]; then + printf "\n\tThe following dependencies are required to install EOSIO.\n" + printf "\n\t$DISPLAY\n\n" + printf "\tDo you wish to install these packages?\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\n\n\tInstalling dependencies\n\n" + sudo apt-get update + sudo apt-get -y install ${DEP} + if [ $? -ne 0 ]; then + printf "\n\tDPKG dependency failed.\n" + printf "\n\tExiting now.\n" + exit 1 + else + printf "\n\tDPKG dependencies installed successfully.\n" + fi + break;; + [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac + done + else + printf "\n\tNo required dpkg dependencies to install.\n" + fi + + printf "\n\tChecking for boost libraries\n" + if [ ! -d ${HOME}/opt/boost_1_66_0 ]; then + # install boost + printf "\tInstalling boost libraries\n" + cd ${TEMP_DIR} + curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2 + tar xf boost_1.66.0.tar.bz2 + cd boost_1_66_0/ + ./bootstrap.sh "--prefix=$BOOST_ROOT" + ./b2 install + rm -rf ${TEMP_DIR}/boost_1_66_0/ + rm -f ${TEMP_DIR}/boost_1.66.0.tar.bz2 + else + printf "\tBoost 1.66 found at ${HOME}/opt/boost_1_66_0\n" + fi + + printf "\n\tChecking for secp256k1-zkp\n" + # install secp256k1-zkp (Cryptonomex branch) + if [ ! -e /usr/local/lib/libsecp256k1.a ]; then + printf "\tInstalling secp256k1-zkp (Cryptonomex branch)\n" + cd ${TEMP_DIR} + git clone https://github.com/cryptonomex/secp256k1-zkp.git + cd secp256k1-zkp + ./autogen.sh + if [ $? -ne 0 ]; then + printf "\tError running autogen for secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + ./configure + make + if [ $? -ne 0 ]; then + printf "\tError compiling secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + sudo make install + rm -rf cd ${TEMP_DIR}/secp256k1-zkp + else + printf "\tsecp256k1 found\n" + fi + + printf "\n\tChecking for binaryen\n" + if [ ! -d ${HOME}/opt/binaryen ]; then + # Install binaryen v1.37.14: + printf "\tInstalling binaryen v1.37.14:\n" + cd ${TEMP_DIR} + git clone https://github.com/WebAssembly/binaryen + cd binaryen + git checkout tags/1.37.14 + cmake . && make + if [ $? -ne 0 ]; then + printf "\tError compiling binaryen.\n" + printf "\tExiting now.\n\n" + exit; + fi + mkdir -p ${HOME}/opt/binaryen/ 2>/dev/null + mv ${TEMP_DIR}/binaryen/bin ${HOME}/opt/binaryen/ + rm -rf ${TEMP_DIR}/binaryen + else + printf "\tBinaryen found at ${HOME}/opt/binaryen\n" + fi + + printf "\n\tChecking for LLVM with WASM support.\n" + if [ ! -d ${HOME}/opt/wasm/bin ]; then + # Build LLVM and clang for WASM: + printf "\tInstalling LLVM & WASM\n" + cd ${TEMP_DIR} + mkdir llvm-compiler 2>/dev/null + cd llvm-compiler + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + cd llvm/tools + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + cd .. + mkdir build + cd build + cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=${HOME}/opt/wasm -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ + if [ $? -ne 0 ]; then + printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" + printf "\tExiting now.\n\n" + exit; + fi + make -j$(nproc) + if [ $? -ne 0 ]; then + printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" + printf "\tExiting now.\n\n" + exit; + fi + rm -rf ${TEMP_DIR}/llvm-compiler + else + printf "\tWASM found at ${HOME}/opt/wasm/bin\n" + fi diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh new file mode 100644 index 0000000000000000000000000000000000000000..b2e51cfba026e986340d935ecb71c48650bbf10a --- /dev/null +++ b/scripts/eosio_build_amazon.sh @@ -0,0 +1,227 @@ + OS_VER=$( cat /etc/os-release | grep VERSION_ID | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' | cut -d'.' -f1 ) + + MEM_MEG=$( free -m | grep Mem | tr -s ' ' | cut -d\ -f2 ) + + CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) + CPU_CORE=$( lscpu | grep "^CPU(s)" | tr -s ' ' | cut -d\ -f2 ) + + DISK_TOTAL=`df -h / | grep /dev | tr -s ' ' | cut -d\ -f2 | sed 's/[^0-9]//'` + DISK_AVAIL=`df -h / | grep /dev | tr -s ' ' | cut -d\ -f4 | sed 's/[^0-9]//'` + + printf "\n\tOS name: $OS_NAME\n" + printf "\tOS Version: ${OS_VER}\n" + printf "\tCPU speed: ${CPU_SPEED}Mhz\n" + printf "\tCPU cores: $CPU_CORE\n" + printf "\tPhysical Memory: $MEM_MEG Mgb\n" + printf "\tDisk space total: ${DISK_TOTAL}G\n" + printf "\tDisk space available: ${DISK_AVAIL}G\n" + + if [ $MEM_MEG -lt 4000 ]; then + printf "\tYour system must have 4 or more Gigabytes of physical memory installed.\n" + printf "\texiting now.\n" + exit 1 + fi + + if [ $OS_VER -lt 2017 ]; then + printf "\tYou must be running Amazon Linux 2017.09 or higher to install EOSIO.\n" + printf "\texiting now.\n" + exit 1 + fi + + if [ $DISK_AVAIL -lt 100 ]; then + printf "\tYou must have at least 100GB of available storage to install EOSIO.\n" + printf "\texiting now.\n" + exit 1 + fi + printf "\n\tChecking Yum installation\n" + + YUM=$( which yum 2>/dev/null ) + if [ $? -ne 0 ]; then + printf "\n\tYum must be installed to compile EOS.IO.\n" + printf "\n\tExiting now.\n" + exit 0 + fi + + printf "\tYum installation found at ${YUM}.\n" + printf "\tUpdating YUM.\n" + UPDATE=$( sudo yum -y update ) + + if [ $? -ne 0 ]; then + printf "\n\tYUM update failed.\n" + printf "\n\tExiting now.\n" + exit 1 + fi + + printf "\t${UPDATE}\n" +# DEP_ARRAY=(clang-4.0 lldb-4.0 libclang-4.0-dev cmake make libbz2-dev libssl-dev libgmp3-dev autotools-dev build-essential libicu-dev python-dev autoconf libtool) + DEP_ARRAY=( git gcc72.x86_64 gcc72-c++.x86_64 autoconf automake libtool make bzip2 bzip2-devel.x86_64 openssl-devel.x86_64 gmp.x86_64 gmp-devel.x86_64 libstdc++72.x86_64 python27-devel.x86_64 libedit-devel.x86_64 ncurses-devel.x86_64 swig.x86_64 ) + DCOUNT=0 + COUNT=1 + DISPLAY="" + DEP="" + + printf "\n\tChecking YUM for installed dependencies.\n\n" + + for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); + do + pkg=$( sudo $YUM info ${DEP_ARRAY[$i]} 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + + if [ "$pkg" != "installed" ]; then + DEP=$DEP" ${DEP_ARRAY[$i]} " + DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\n\t" + printf "\tPackage ${DEP_ARRAY[$i]} ${bldred} NOT ${txtrst} found.\n" + let COUNT++ + let DCOUNT++ + else + printf "\tPackage ${DEP_ARRAY[$i]} found.\n" + continue + fi + done + + if [ ${DCOUNT} -ne 0 ]; then + printf "\n\tThe following dependencies are required to install EOSIO.\n" + printf "\n\t$DISPLAY\n\n" + printf "\tDo you wish to install these dependencies?\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\n\n\tInstalling dependencies\n\n" + sudo yum -y install ${DEP} + if [ $? -ne 0 ]; then + printf "\n\tYUM dependency installation failed.\n" + printf "\n\tExiting now.\n" + exit 1 + else + printf "\n\tYUM dependencies installed successfully.\n" + fi + break;; + [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac + done + else + printf "\n\tNo required YUM dependencies to install.\n" + fi + + printf "\n\tChecking for CMAKE.\n" + # install CMAKE 3.10.2 + if [ ! -e ${CMAKE} ]; then + printf "\tInstalling CMAKE\n" + mkdir -p ${HOME}/opt/ 2>/dev/null + cd ${HOME}/opt + curl -L -O https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz + tar xf cmake-3.10.2.tar.gz + rm -f cmake-3.10.2.tar.gz + ln -s cmake-3.10.2/ cmake + cd cmake + ./bootstrap + if [ $? -ne 0 ]; then + printf "\tError running bootstrap for CMAKE.\n" + printf "\tExiting now.\n\n" + exit; + fi + make -j${CPU_CORE} + if [ $? -ne 0 ]; then + printf "\tError compiling CMAKE.\n" + printf "\tExiting now.\n\n" + exit; + fi + else + printf "\tCMAKE found\n" + fi + + printf "\n\tChecking for boost libraries\n" + if [ ! -d ${HOME}/opt/boost_1_66_0 ]; then + # install boost + printf "\tInstalling boost libraries\n" + cd ${TEMP_DIR} + curl -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2 > boost_1.66.0.tar.bz2 + tar xf boost_1.66.0.tar.bz2 + cd boost_1_66_0/ + ./bootstrap.sh "--prefix=$BOOST_ROOT" + ./b2 install + rm -rf ${TEMP_DIR}/boost_1_66_0/ + rm -f ${TEMP_DIR}/boost_1.66.0.tar.bz2 + else + printf "\tBoost 1.66 found at ${HOME}/opt/boost_1_66_0\n" + fi + + printf "\n\tChecking for secp256k1-zkp\n" + # install secp256k1-zkp (Cryptonomex branch) + if [ ! -e /usr/local/lib/libsecp256k1.a ]; then + printf "\tInstalling secp256k1-zkp (Cryptonomex branch)\n" + cd ${TEMP_DIR} + git clone https://github.com/cryptonomex/secp256k1-zkp.git + cd secp256k1-zkp + ./autogen.sh + if [ $? -ne 0 ]; then + printf "\tError running autogen for secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + ./configure + make -j${CPU_CORE} + if [ $? -ne 0 ]; then + printf "\tError compiling secp256k1-zkp.\n" + printf "\tExiting now.\n\n" + exit; + fi + sudo make install + rm -rf cd ${TEMP_DIR}/secp256k1-zkp + else + printf "\tsecp256k1 found\n" + fi + + printf "\n\tChecking for binaryen\n" + if [ ! -d ${HOME}/opt/binaryen ]; then + # Install binaryen v1.37.14: + printf "\tInstalling binaryen v1.37.14:\n" + cd ${TEMP_DIR} + git clone https://github.com/WebAssembly/binaryen + cd binaryen + git checkout tags/1.37.14 + $CMAKE . && make -j${CPU_CORE} + if [ $? -ne 0 ]; then + printf "\tError compiling binaryen.\n" + printf "\tExiting now.\n\n" + exit; + fi + mkdir -p ${HOME}/opt/binaryen/ 2>/dev/null + mv ${TEMP_DIR}/binaryen/bin ${HOME}/opt/binaryen/ + rm -rf ${TEMP_DIR}/binaryen + else + printf "\tBinaryen found at ${HOME}/opt/binaryen\n" + fi + + printf "\n\tChecking for LLVM with WASM support.\n" + if [ ! -d ${HOME}/opt/wasm/bin ]; then + # Build LLVM and clang with EXPERIMENTAL WASM support: + printf "\tInstalling LLVM & WASM\n" + cd ${TEMP_DIR} + mkdir llvm-compiler 2>/dev/null + cd llvm-compiler + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + cd llvm/tools + git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + cd .. + mkdir build 2>/dev/null + cd build + $CMAKE -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=${HOME}/opt/wasm \ + -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly \ + -DCMAKE_BUILD_TYPE=Release ../ + if [ $? -ne 0 ]; then + printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" + printf "\tExiting now.\n\n" + exit; + fi + make -j${CPU_CORE} + if [ $? -ne 0 ]; then + printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" + printf "\tExiting now.\n\n" + exit; + fi + make install + rm -rf ${TEMP_DIR}/llvm-compiler 2>/dev/null + else + printf "\tWASM found at ${HOME}/opt/wasm\n" + fi \ No newline at end of file diff --git a/scripts/eosio_build_darwin.sh b/scripts/eosio_build_darwin.sh index e4767f76b6533ff8c0a7d2ec3ec62ff133296ff6..03bb61c9c225107c0486f43041dbb66e02f7042d 100644 --- a/scripts/eosio_build_darwin.sh +++ b/scripts/eosio_build_darwin.sh @@ -20,20 +20,20 @@ printf "\tDisk space available: ${DISK_AVAIL}G\n\n" if [ $MEM_GIG -lt 8 ]; then - printf "\tYour system must have 8 or more Gigabytes of physical memory installed.\n" - printf "\tExiting now.\n" + echo "Your system must have 8 or more Gigabytes of physical memory installed." + echo "Exiting now." exit 1 fi if [ $OS_MIN -lt 12 ]; then - printf "\tYou must be running Mac OS 10.12.x or higher to install EOSIO.\n" - printf "\tExiting now.\n" + echo "You must be running Mac OS 10.12.x or higher to install EOSIO." + echo "Exiting now." exit 1 fi if [ $DISK_AVAIL -lt 100 ]; then - printf "\tYou must have at least 100GB of available storage to install EOSIO.\n" - printf "\tExiting now.\n" + echo "You must have at least 100GB of available storage to install EOSIO." + echo "Exiting now." exit 1 fi @@ -165,13 +165,13 @@ exit; fi ./configure - make + make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling secp256k1-zkp.\n" printf "\tExiting now.\n\n" exit; fi - sudo make install + sudo make -j${CPU_CORE} install sudo rm -rf ${TEMP_DIR}/secp256k1-zkp else printf "\tsecp256k1 found at /usr/local/lib/\n" @@ -183,7 +183,7 @@ git clone https://github.com/WebAssembly/binaryen cd binaryen git checkout tags/1.37.14 - cmake . && make + cmake . && make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling binaryen.\n" printf "\tExiting now.\n\n" @@ -217,7 +217,7 @@ printf "\tExiting now.\n\n" exit; fi - sudo make -j4 install + sudo make -j${CPU_CORE} install sudo rm -rf ${TEMP_DIR}/wasm-compiler else printf "\tWASM found at /usr/local/wasm/bin/\n" diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh index 6df27388355291fc424f7243c6f6e152d2dc9cf5..c7eb92bcd76d9ab541f3d6ae1f8657200584ad85 100644 --- a/scripts/eosio_build_fedora.sh +++ b/scripts/eosio_build_fedora.sh @@ -17,20 +17,20 @@ printf "\tDisk space available: ${DISK_AVAIL}G\n" if [ $MEM_MEG -lt 4000 ]; then - echo "Your system must have 8 or more Gigabytes of physical memory installed." - echo "exiting now." + printf "\tYour system must have 8 or more Gigabytes of physical memory installed.\n" + printf "\tExiting now.\n" exit 1 fi if [ $OS_VER -lt 25 ]; then - echo "You must be running Fedora 25 or higher to install EOSIO." - echo "exiting now" + printf "\tYou must be running Fedora 25 or higher to install EOSIO.\n" + printf "\tExiting now.\n" exit 1 fi if [ $DISK_AVAIL -lt 100 ]; then - echo "You must have at least 100GB of available storage to install EOSIO." - echo "exiting now" + printf "\tYou must have at least 100GB of available storage to install EOSIO.\n" + printf "\tExiting now.\n" exit 1 fi @@ -112,7 +112,7 @@ tar xf boost_1.66.0.tar.bz2 cd boost_1_66_0/ ./bootstrap.sh "--prefix=$BOOST_ROOT" - ./b2 install + ./b2 -j${CPU_CORE} install rm -rf ${TEMP_DIR}/boost_1_66_0/ rm -f ${TEMP_DIR}/boost_1.66.0.tar.bz2 else @@ -133,13 +133,13 @@ exit; fi ./configure - make + make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling secp256k1-zkp.\n" printf "\tExiting now.\n\n" exit; fi - sudo make install + sudo make -j${CPU_CORE} install rm -rf cd ${TEMP_DIR}/secp256k1-zkp else printf "\tsecp256k1 found\n" @@ -153,7 +153,7 @@ git clone https://github.com/WebAssembly/binaryen cd binaryen git checkout tags/1.37.14 - cmake . && make + cmake . && make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling binaryen.\n" printf "\tExiting now.\n\n" @@ -185,13 +185,13 @@ printf "\tExiting now.\n\n" exit; fi - make -j$(nproc) + make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" printf "\tExiting now.\n\n" exit; fi - make install + make -j${CPU_CORE} install rm -rf ${TEMP_DIR}/llvm-compiler 2>/dev/null else printf "\tWASM found at ${HOME}/opt/wasm\n" diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh index 73d6d6ffc33cd85f8b76c1953f4776b3fb7ab11a..03f770d82a2086acab9baf0f9af828012134dcb3 100644 --- a/scripts/eosio_build_ubuntu.sh +++ b/scripts/eosio_build_ubuntu.sh @@ -19,20 +19,20 @@ printf "\tDisk space available: ${DISK_AVAIL}G\n" if [ $MEM_MEG -lt 4000 ]; then - echo "Your system must have 8 or more Gigabytes of physical memory installed." - echo "exiting now." + printf "\tYour system must have 8 or more Gigabytes of physical memory installed.\n" + printf "\tExiting now.\n" exit 1 fi if [ $OS_MIN -lt 4 ]; then - echo "You must be running Ubuntu 16.04.x or higher to install EOSIO." - echo "exiting now" + printf "\tYou must be running Ubuntu 16.04.x or higher to install EOSIO.\n" + printf "\tExiting now.\n" exit 1 fi if [ $DISK_AVAIL -lt 100 ]; then - echo "You must have at least 100GB of available storage to install EOSIO." - echo "exiting now" + printf "\tYou must have at least 100GB of available storage to install EOSIO.\n" + printf "\tExiting now.\n" exit 1 fi @@ -94,7 +94,7 @@ tar xf boost_1.66.0.tar.bz2 cd boost_1_66_0/ ./bootstrap.sh "--prefix=$BOOST_ROOT" - ./b2 install + ./b2 -j${CPU_CORE} install rm -rf ${TEMP_DIR}/boost_1_66_0/ rm -f ${TEMP_DIR}/boost_1.66.0.tar.bz2 else @@ -115,13 +115,13 @@ exit; fi ./configure - make + make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling secp256k1-zkp.\n" printf "\tExiting now.\n\n" exit; fi - sudo make install + sudo make -j${CPU_CORE} install rm -rf cd ${TEMP_DIR}/secp256k1-zkp else printf "\tsecp256k1 found\n" @@ -135,7 +135,7 @@ git clone https://github.com/WebAssembly/binaryen cd binaryen git checkout tags/1.37.14 - cmake . && make + cmake . && make -j${CPU_CORE} if [ $? -ne 0 ]; then printf "\tError compiling binaryen.\n" printf "\tExiting now.\n\n" @@ -167,7 +167,7 @@ printf "\tExiting now.\n\n" exit; fi - make -j$(nproc) + make -j${CPU_CORE} install if [ $? -ne 0 ]; then printf "\tError compiling LLVM and clang with EXPERIMENTAL WASM support.\n" printf "\tExiting now.\n\n" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d0ccf9175c8ca569204250a1f13a122566bd41ae..98eafc9dd95eaac0832b0bfd5760af2a42a3db36 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,25 +12,15 @@ link_directories(${LLVM_LIBRARY_DIR}) set( CMAKE_CXX_STANDARD 14 ) -#file(GLOB UNIT_TESTS "tests/*.cpp") -#if(WASM_TOOLCHAIN) -# add_subdirectory(tests/contracts/rate_limit_auth) -# file(GLOB WASM_UNIT_TESTS "tests/wasm_tests/*.cpp") -# list(APPEND UNIT_TESTS ${WASM_UNIT_TESTS}) -#endif() -#add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) -#target_link_libraries( chain_test eos_native_contract eosio_chain chainbase eos_utilities eos_egenesis_none wallet_plugin chain_plugin producer_plugin fc ${PLATFORM_SPECIFIC_LIBS} ) -#if(WASM_TOOLCHAIN) -# target_include_directories( chain_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts ) -# add_dependencies(chain_test rate_limit_auth) -#endif() - +#include_directories("${CMAKE_BINARY_DIR}/tests/api_tests") +include_directories("${CMAKE_BINARY_DIR}/contracts") +include_directories("${CMAKE_SOURCE_DIR}/contracts") +file(GLOB UNIT_TESTS "chain_tests/*.cpp" "api_tests/*.cpp" "tests/abi_tests.cpp" "tests/database_tests.cpp") -file(GLOB UNIT_TESTS "chain_tests/*.cpp" "tests/abi_tests.cpp" "tests/database_tests.cpp") -if(WASM_TOOLCHAIN) - file(GLOB WASM_UNIT_TESTS "wasm_tests/*.cpp") -endif() +#if(WASM_TOOLCHAIN) +# file(GLOB WASM_UNIT_TESTS "wasm_tests/*.cpp") +#endif() add_executable( chain_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} common/main.cpp ) target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilities eos_egenesis_none chain_plugin abi_generator fc ${PLATFORM_SPECIFIC_LIBS} ) @@ -69,6 +59,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/restart-scenarios-test.py ${CMAKE_CUR configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testUtils.py ${CMAKE_CURRENT_BINARY_DIR}/testUtils.py COPYONLY) 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) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/consensusValidationMaliciousProducers.py ${CMAKE_CURRENT_BINARY_DIR}/consensusValidationMaliciousProducers.py COPYONLY) add_test(chain_test chain_test --report_level=detailed) add_test(NAME eosiod_run_test COMMAND tests/eosiod_run_test.py -v --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/tests/api_tests/api_tests.cpp b/tests/api_tests/api_tests.cpp index 02627762c04ecea7b8f42e0654b4b82884c4d4d9..6d4b49e8ad5d6e98bc4a56dccf227478cf7aaeed 100644 --- a/tests/api_tests/api_tests.cpp +++ b/tests/api_tests/api_tests.cpp @@ -1,5 +1,5 @@ /** - * @file + * @file api_tests.cpp * @copyright defined in eos/LICENSE.txt */ #include @@ -13,20 +13,20 @@ #include #include #include +#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include - -#include "../common/database_fixture.hpp" +#include #include #include @@ -36,135 +36,139 @@ #include #include +#include +#include #include -#include "memory_test/memory_test.wast.hpp" -#include "extended_memory_test/extended_memory_test.wast.hpp" -#include "table_abi_test/table_abi_test.wast.hpp" -#include "table_abi_test/table_abi_test.abi.hpp" - -#include -#include - -#include - -FC_REFLECT( dummy_message, (a)(b)(c) ); -FC_REFLECT( u128_msg, (values) ); +FC_REFLECT( dummy_action, (a)(b)(c) ); +FC_REFLECT( u128_action, (values) ); using namespace eosio; +using namespace eosio::testing; using namespace chain; +using namespace chain::contracts; +using namespace fc; namespace bio = boost::iostreams; -BOOST_AUTO_TEST_SUITE(api_tests) +template +struct test_api_action { + static account_name get_account() { + return N(testapi); + } -vector assemble_wast( const std::string& wast ) { - // std::cout << "\n" << wast << "\n"; - IR::Module module; - std::vector parseErrors; - WAST::parseModule(wast.c_str(),wast.size(),module,parseErrors); - if(parseErrors.size()) - { - // Print any parse errors; - std::cerr << "Error parsing WebAssembly text file:" << std::endl; - for(auto& error : parseErrors) - { - std::cerr << ":" << error.locus.describe() << ": " << error.message.c_str() << std::endl; - std::cerr << error.locus.sourceLine << std::endl; - std::cerr << std::setw(error.locus.column(8)) << "^" << std::endl; - } - FC_ASSERT( !"error parsing wast" ); - } + static action_name get_name() { + return action_name(NAME); + } +}; - try - { - // Serialize the WebAssembly module. - Serialization::ArrayOutputStream stream; - WASM::serialize(stream,module); - return stream.getBytes(); - } - catch(Serialization::FatalSerializationException exception) - { - std::cerr << "Error serializing WebAssembly binary file:" << std::endl; - std::cerr << exception.message << std::endl; - throw; - } +FC_REFLECT_TEMPLATE((uint64_t T), test_api_action, BOOST_PP_SEQ_NIL); + +template +struct test_chain_action { + static account_name get_account() { + return account_name(config::system_account_name); + } + + static action_name get_name() { + return action_name(NAME); + } +}; + +FC_REFLECT_TEMPLATE((uint64_t T), test_chain_action, BOOST_PP_SEQ_NIL); + + + +bool expect_assert_message(const fc::exception& ex, string expected) { + BOOST_TEST_MESSAGE("LOG : " << ex.get_log().at(0).get_message()); + return (ex.get_log().at(0).get_message().find(expected) != std::string::npos); } -uint32_t CallFunction( testing_blockchain& chain, const types::message& msg, const vector& data, const vector& scope = {N(testapi)}) { - static int expiration = 1; - eosio::chain::signed_transaction trx; - trx.scope = scope; - - //msg.data.clear(); - vector& dest = *(vector *)(&msg.data); - std::copy(data.begin(), data.end(), std::back_inserter(dest)); +struct assert_message_is { + bool operator()( const fc::exception& ex, string expected) { + auto act = ex.get_log().at(0).get_message(); + return boost::algorithm::ends_with(act, expected); + } - //std::cout << "MANDO: " << msg.code << " " << msg.type << std::endl; - transaction_emplace_message(trx, msg); - - trx.expiration = chain.head_block_time() + expiration++; - transaction_set_reference_block(trx, chain.head_block_id()); - //idump((trx)); - chain.push_transaction(trx); - - // - auto& wasm = wasm_interface::get(); - uint32_t *res = Runtime::memoryArrayPtr(wasm.current_memory, (1<<16) - 2*sizeof(uint32_t), 2); - - if(res[0] == WASM_TEST_FAIL) { - char *str_err = &Runtime::memoryRef(wasm.current_memory, res[1]); - wlog( "${err}", ("err",str_err)); - } + string expected; +}; - return res[0]; +constexpr uint64_t TEST_METHOD(const char* CLASS, const char *METHOD) { + return ( (uint64_t(DJBH(CLASS))<<32) | uint32_t(DJBH(METHOD)) ); } +string U64Str(uint64_t i) +{ + std::stringstream ss; + ss << i; + return ss.str(); +} -using namespace std; -string readFile2(const string &fileName) +string U128Str(unsigned __int128 i) { - ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate); + return fc::variant(fc::uint128_t(i)).get_string(); +} - ifstream::pos_type fileSize = ifs.tellg(); - ifs.seekg(0, ios::beg); - vector bytes(fileSize); - ifs.read(bytes.data(), fileSize); +template +void CallFunction(tester& test, T ac, const vector& data, const vector& scope = {N(testapi)}) { + { + signed_transaction trx; - return string(bytes.data(), fileSize); -} + auto pl = vector{{scope[0], config::active_name}}; + if (scope.size() > 1) + for (int i=1; i < scope.size(); i++) + pl.push_back({scope[i], config::active_name}); -uint64_t TEST_METHOD(const char* CLASS, const char *METHOD) { - //std::cerr << CLASS << "::" << METHOD << std::endl; - return ( (uint64_t(DJBH(CLASS))<<32) | uint32_t(DJBH(METHOD)) ); -} + action act(pl, ac); + act.data = data; + trx.actions.push_back(act); -#define CALL_TEST_FUNCTION(TYPE, AUTH, DATA) CallFunction(chain, message{"testapi", AUTH, TYPE}, DATA) -#define CALL_TEST_FUNCTION_SCOPE(TYPE, AUTH, DATA, SCOPE) CallFunction(chain, message{"testapi", AUTH, TYPE}, DATA, SCOPE) + test.set_tapos(trx); + auto sigs = trx.sign(test.get_private_key(scope[0], "active"), chain_id_type()); + trx.get_signature_keys(chain_id_type() ); + auto res = test.push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + test.produce_block(); + } +} + +#define CALL_TEST_FUNCTION(TESTER, CLS, MTH, DATA) CallFunction(TESTER, test_api_action{}, DATA) +#define CALL_TEST_FUNCTION_SYSTEM(TESTER, CLS, MTH, DATA) CallFunction(TESTER, test_chain_action{}, DATA, {N(eosio)} ) +#define CALL_TEST_FUNCTION_SCOPE(TESTER, CLS, MTH, DATA, ACCOUNT) CallFunction(TESTER, test_api_action{}, DATA, ACCOUNT) bool is_access_violation(fc::unhandled_exception const & e) { try { std::rethrow_exception(e.get_inner_exception()); } - catch (const Runtime::Exception& e) { - return e.cause == Runtime::Exception::Cause::accessViolation; + catch (const eosio::chain::wasm_execution_error& e) { + return true; } catch (...) { } return false; } - -bool is_tx_missing_recipient(tx_missing_recipient const & e) { return true;} +bool is_access_violation(const Runtime::Exception& e) { + return true; +} +bool is_assert_exception(fc::assert_exception const & e) { return true; } +bool is_page_memory_error(page_memory_error const &e) { return true; } bool is_tx_missing_auth(tx_missing_auth const & e) { return true; } -bool is_tx_missing_scope(tx_missing_scope const& e) { return true; } +bool is_tx_missing_recipient(tx_missing_recipient const & e) { return true;} +bool is_tx_missing_sigs(tx_missing_sigs const & e) { return true;} +bool is_wasm_execution_error(eosio::chain::wasm_execution_error const& e) {return true;} bool is_tx_resource_exhausted(const tx_resource_exhausted& e) { return true; } -bool is_tx_unknown_argument(const tx_unknown_argument& e) { return true; } -bool is_assert_exception(fc::assert_exception const & e) { return true; } -bool is_tx_resource_exhausted_or_checktime(const transaction_exception& e) { - return (e.code() == tx_resource_exhausted::code_value) || (e.code() == checktime_exceeded::code_value); -} +bool is_checktime_exceeded(const checktime_exceeded& e) { return true; } + +/* + * register test suite `api_tests` + */ +BOOST_AUTO_TEST_SUITE(api_tests) + +/* + * Print capturing stuff + */ std::vector capture; struct MySink : public bio::sink @@ -180,580 +184,873 @@ struct MySink : public bio::sink } }; uint32_t last_fnc_err = 0; + #define CAPTURE(STREAM, EXEC) \ {\ capture.clear(); \ bio::stream_buffer sb; sb.open(MySink()); \ std::streambuf *oldbuf = std::STREAM.rdbuf(&sb); \ - last_fnc_err = EXEC; \ + EXEC; \ std::STREAM.rdbuf(oldbuf); \ } -void send_set_code_message(testing_blockchain& chain, types::setcode& handler, account_name account) -{ - eosio::chain::signed_transaction trx; - handler.account = account; - trx.scope = { account }; - trx.messages.resize(1); - trx.messages[0].authorization = {{account,"active"}}; - trx.messages[0].code = config::eos_contract_name; - transaction_set_message(trx, 0, "setcode", handler); - trx.expiration = chain.head_block_time() + 100; - transaction_set_reference_block(trx, chain.head_block_id()); - chain.push_transaction(trx); - chain.produce_blocks(1); -} +#define CAPTURE_AND_PRE_TEST_PRINT(METHOD) \ + { \ + BOOST_TEST_MESSAGE( "Running test_print::" << METHOD ); \ + CAPTURE( cerr, CALL_TEST_FUNCTION( *this, "test_print", METHOD, {} ) ); \ + BOOST_CHECK_EQUAL( capture.size(), 7 ); \ + captured = capture[3]; \ + } + + +/************************************************************************************* + * action_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(action_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + create_account( N(acc1) ); + create_account( N(acc2) ); + create_account( N(acc3) ); + create_account( N(acc4) ); + produce_blocks(1000); + set_code( N(testapi), test_api_wast ); + produce_blocks(1); + + // test assert_true + CALL_TEST_FUNCTION( *this, "test_action", "assert_true", {}); + + //test assert_false + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "assert_false", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "test_action::assert_false"); + } + ); + + // test read_action_normal + dummy_action dummy13{DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C}; + CALL_TEST_FUNCTION( *this, "test_action", "read_action_normal", fc::raw::pack(dummy13)); + + // test read_action_to_0 + std::vector raw_bytes((1<<16)); + CALL_TEST_FUNCTION( *this, "test_action", "read_action_to_0", raw_bytes ); + + // test read_action_to_0 + raw_bytes.resize((1<<16)+1); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "read_action_to_0", raw_bytes), eosio::chain::wasm_execution_error, + [](const eosio::chain::wasm_execution_error& e) { + return expect_assert_message(e, "access violation"); + } + ); + + // test read_action_to_64k + raw_bytes.resize(1); + CALL_TEST_FUNCTION( *this, "test_action", "read_action_to_64k", raw_bytes ); + + // test read_action_to_64k + raw_bytes.resize(3); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "read_action_to_64k", raw_bytes ), eosio::chain::wasm_execution_error, + [](const eosio::chain::wasm_execution_error& e) { + return expect_assert_message(e, "access violation"); + } + ); + + // test require_notice + auto scope = std::vector{N(testapi)}; + auto test_require_notice = [](auto& test, std::vector& data, std::vector& scope){ + signed_transaction trx; + auto tm = test_api_action{}; + + action act(std::vector{{N(testapi), config::active_name}}, tm); + vector& dest = *(vector *)(&act.data); + std::copy(data.begin(), data.end(), std::back_inserter(dest)); + trx.actions.push_back(act); + + test.set_tapos(trx); + trx.sign(test.get_private_key(N(inita), "active"), chain_id_type()); + auto res = test.push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + }; + BOOST_CHECK_EXCEPTION(test_require_notice(*this, raw_bytes, scope), tx_missing_sigs, + [](const tx_missing_sigs& e) { + return expect_assert_message(e, "transaction declares authority"); + } + ); + + // test require_auth + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "require_auth", {}), tx_missing_auth, + [](const tx_missing_auth& e) { + return expect_assert_message(e, "missing authority of"); + } + ); + + // test require_auth + auto a3only = std::vector{{N(acc3), config::active_name}}; + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "require_auth", fc::raw::pack(a3only)), tx_missing_auth, + [](const tx_missing_auth& e) { + return expect_assert_message(e, "missing authority of"); + } + ); + + // test require_auth + auto a4only = std::vector{{N(acc4), config::active_name}}; + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "require_auth", fc::raw::pack(a4only)), tx_missing_auth, + [](const tx_missing_auth& e) { + return expect_assert_message(e, "missing authority of"); + } + ); + + // test require_auth + auto a3a4 = std::vector{{N(acc3), config::active_name}, {N(acc4), config::active_name}}; + auto a3a4_scope = std::vector{N(acc3), N(acc4)}; + { + signed_transaction trx; + auto tm = test_api_action{}; + auto pl = a3a4; + if (a3a4_scope.size() > 1) + for (int i=1; i < a3a4_scope.size(); i++) + pl.push_back({a3a4_scope[i], config::active_name}); + + action act(pl, tm); + auto dat = fc::raw::pack(a3a4); + vector& dest = *(vector *)(&act.data); + std::copy(dat.begin(), dat.end(), std::back_inserter(dest)); + trx.actions.push_back(act); + + set_tapos(trx); + trx.sign(get_private_key(N(acc3), "active"), chain_id_type()); + trx.sign(get_private_key(N(acc4), "active"), chain_id_type()); + auto res = push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + } + + uint32_t now = control->head_block_time().sec_since_epoch(); + CALL_TEST_FUNCTION( *this, "test_action", "now", fc::raw::pack(now)); + + // test now + produce_block(); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "now", fc::raw::pack(now)), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "assertion failed: tmp == now"); + } + ); + + // test test_current_receiver + CALL_TEST_FUNCTION( *this, "test_action", "test_current_receiver", fc::raw::pack(N(testapi))); + + // test send_action_sender + CALL_TEST_FUNCTION( *this, "test_transaction", "send_action_sender", fc::raw::pack(N(testapi))); + control->push_deferred_transactions( true ); + + // test_publication_time + uint32_t pub_time = control->head_block_time().sec_since_epoch(); + CALL_TEST_FUNCTION( *this, "test_action", "test_publication_time", fc::raw::pack(pub_time) ); + + // test test_abort + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "test_abort", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "abort() called"); + } + ); + -BOOST_FIXTURE_TEST_CASE(test_all, testing_fixture) -{ try { - //auto wasm = assemble_wast( readFile2("/home/matu/Documents/Dev/eos/build/contracts/test_api/test_api.wast").c_str() ); - auto wasm = assemble_wast( test_api_wast ); - - Make_Blockchain(chain); - chain.produce_blocks(2); - Make_Account(chain, testapi); - Make_Account(chain, another); - Make_Account(chain, acc1); - Make_Account(chain, acc2); - Make_Account(chain, acc3); - Make_Account(chain, acc4); - chain.produce_blocks(1); - - //Set test code - types::setcode handler; - handler.code.resize(wasm.size()); - memcpy( handler.code.data(), wasm.data(), wasm.size() ); - - send_set_code_message(chain, handler, "testapi"); - send_set_code_message(chain, handler, "acc1"); - send_set_code_message(chain, handler, "acc2"); - - //Test types - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_types", "types_size"), {}, {} ) == WASM_TEST_PASS, "test_types::types_size()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_types", "char_to_symbol"), {}, {} ) == WASM_TEST_PASS, "test_types::char_to_symbol()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_types", "string_to_name"), {}, {} ) == WASM_TEST_PASS, "test_types::string_to_name()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_types", "name_class"), {}, {} ) == WASM_TEST_PASS, "test_types::name_class()" ); - - //Test message - dummy_message dummy13{DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "read_message_normal"), {}, fc::raw::pack(dummy13) ) == WASM_TEST_PASS, "test_message::read_message_normal()" ); - - std::vector raw_bytes((1<<16)); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "read_message_to_0"), {}, raw_bytes) == WASM_TEST_PASS, "test_message::read_message_to_0()" ); - - raw_bytes.resize((1<<16)+1); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "read_message_to_0"), {}, raw_bytes), - fc::unhandled_exception, is_access_violation ); - - raw_bytes.resize(1); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "read_message_to_64k"), {}, raw_bytes) == WASM_TEST_PASS, "test_message::read_message_to_64k()" ); - - raw_bytes.resize(2); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "read_message_to_64k"), {}, raw_bytes), - fc::unhandled_exception, is_access_violation ); - - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "require_notice"), {}, raw_bytes) == WASM_TEST_PASS, "test_message::require_notice()" ); +} FC_LOG_AND_RETHROW() } + +/************************************************************************************* + * checktime_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(checktime_pass_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + produce_blocks(1000); + set_code( N(testapi), test_api_wast ); + produce_blocks(1); + + // test checktime_pass + CALL_TEST_FUNCTION( *this, "test_checktime", "checktime_pass", {}); + +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(checktime_fail_tests) { + try { + tester t( {fc::milliseconds(1), fc::milliseconds(1)} ); + t.produce_blocks(2); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "require_auth"), {}, {}), - tx_missing_auth, is_tx_missing_auth ); + t.create_account( N(testapi) ); + t.set_code( N(testapi), test_api_wast ); - auto a3only = vector{{"acc3","active"}}; - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "require_auth"), a3only, {}), - tx_missing_auth, is_tx_missing_auth ); + auto call_test = [](tester& test, auto ac) { + signed_transaction trx; - auto a4only = vector{{"acc4","active"}}; - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "require_auth"), a4only, {}), - tx_missing_auth, is_tx_missing_auth ); + auto pl = vector{{N(testapi), config::active_name}}; + action act(pl, ac); - auto a3a4 = vector{{"acc3","active"}, {"acc4","active"}}; - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "require_auth"), a3a4, {}) == WASM_TEST_PASS, "test_message::require_auth()"); + trx.actions.push_back(act); + test.set_tapos(trx); + auto sigs = trx.sign(test.get_private_key(N(testapi), "active"), chain_id_type()); + trx.get_signature_keys(chain_id_type() ); + auto res = test.push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + test.produce_block(); + }; - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "assert_false"), {}, {}), - fc::assert_exception, is_assert_exception ); + BOOST_CHECK_EXCEPTION(call_test( t, test_api_action{}), checktime_exceeded, is_checktime_exceeded); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "assert_true"), {}, {}) == WASM_TEST_PASS, "test_message::assert_true()"); + } FC_LOG_AND_RETHROW(); +} +/************************************************************************************* + * compiler_builtins_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(compiler_builtins_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + produce_blocks(1000); + set_code( N(testapi), test_api_wast ); + produce_blocks(1); + + // test test_multi3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_multi3", {}); + + // test test_divti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_divti3", {}); + + // test test_divti3_by_0 + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_divti3_by_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); + + // test test_udivti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_udivti3", {}); + + // test test_udivti3_by_0 + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_udivti3_by_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); + + // test test_modti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_modti3", {}); + + // test test_modti3_by_0 + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_modti3_by_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); + + // test test_lshlti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_lshlti3", {}); + + // test test_lshrti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_lshrti3", {}); + + // test test_ashlti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_ashlti3", {}); + + // test test_ashrti3 + CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_ashrti3", {}); +} FC_LOG_AND_RETHROW() } - chain.produce_blocks(1); - - uint32_t now = chain.head_block_time().sec_since_epoch(); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "now"), {}, fc::raw::pack(now)) == WASM_TEST_PASS, "test_message::now()"); - chain.produce_blocks(1); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_message", "now"), {}, fc::raw::pack(now)) == WASM_TEST_FAIL, "test_message::now()"); +/************************************************************************************* + * transaction_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(transaction_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + produce_blocks(100); + set_code( N(testapi), test_api_wast ); + produce_blocks(1); + + // test send_action + CALL_TEST_FUNCTION(*this, "test_transaction", "send_action", {}); + + // test send_action_empty + CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_empty", {}); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "false: abort() called"); + } + ); + + // test send_action_inline_fail + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_inline_fail", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "test_action::assert_false"); + } + ); + control->push_deferred_transactions( true ); + + // test send_transaction + CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction", {}); + control->push_deferred_transactions( true ); + + // test send_transaction_empty + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_empty", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "transaction must have at least one action"); + } + ); + control->push_deferred_transactions( true ); + + // test test_transaction_size + CALL_TEST_FUNCTION(*this, "test_transaction", "test_transaction_size", fc::raw::pack(56) ); + control->push_deferred_transactions( true ); + + // test test_read_transaction + // this is a bit rough, but I couldn't figure out a better way to compare the hashes + CAPTURE( cerr, CALL_TEST_FUNCTION( *this, "test_transaction", "test_read_transaction", {} ) ); + BOOST_CHECK_EQUAL( capture.size(), 7 ); + string sha_expect = "bdeb5b58dda272e4b23ee7d2a5f0ff034820c156364893b758892e06fa39e7fe"; + BOOST_CHECK_EQUAL(capture[3] == sha_expect, true); + // test test_tapos_block_num + CALL_TEST_FUNCTION(*this, "test_transaction", "test_tapos_block_num", fc::raw::pack(control->head_block_num()) ); + + // test test_tapos_block_prefix + CALL_TEST_FUNCTION(*this, "test_transaction", "test_tapos_block_prefix", fc::raw::pack(control->head_block_id()._hash[1]) ); + + // test send_action_recurse + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_recurse", {}), eosio::chain::transaction_exception, + [](const eosio::chain::transaction_exception& e) { + return expect_assert_message(e, "inline action recursion depth reached"); + } + ); - //Test print - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_print", "test_prints"), {}, {}) ); - - BOOST_CHECK_EQUAL( last_fnc_err , WASM_TEST_PASS); - BOOST_CHECK_EQUAL( capture.size() , 3); - BOOST_CHECK_EQUAL( (capture[0] == "ab" && capture[1] == "c" && capture[2] == "efg") , true); - - auto U64Str = [](uint64_t v) -> std::string { - std::stringstream s; - s << v; - return s.str(); - }; - - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_print", "test_printi"), {}, {}) ); - BOOST_CHECK_EQUAL( capture.size() , 3); - BOOST_CHECK_EQUAL( capture[0], U64Str(0) ); - BOOST_CHECK_EQUAL( capture[1], U64Str(556644) ); - BOOST_CHECK_EQUAL( capture[2], U64Str(-1) ); - - auto U128Str = [](uint128_t value) -> std::string { - fc::uint128_t v(value>>64, uint64_t(value) ); - return fc::variant(v).get_string(); - }; - - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_print", "test_printi128"), {}, {}) ); - BOOST_CHECK_EQUAL( capture.size() , 3); - BOOST_CHECK_EQUAL( capture[0], U128Str(-1)); - BOOST_CHECK_EQUAL( capture[1], U128Str(0)); - BOOST_CHECK_EQUAL( capture[2], U128Str(87654323456)); - - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_print", "test_printn"), {}, {}) ); - BOOST_CHECK_EQUAL( capture.size() , 8); - - std::cout << capture[0] << std::endl - << capture[1] << std::endl - << capture[2] << std::endl - << capture[3] << std::endl - << capture[4] << std::endl - << capture[5] << std::endl - << capture[6] << std::endl - << capture[7] << std::endl; - - BOOST_CHECK_EQUAL( ( - capture[0] == "abcde" && - capture[1] == "ab.de" && - capture[2] == "1q1q1q" && - capture[3] == "abcdefghijk" && - capture[4] == "abcdefghijkl" && - capture[5] == "abcdefghijkl1" && - capture[6] == "abcdefghijkl1" && - capture[7] == "abcdefghijkl1" - ), true); - - //Test math - std::random_device rd; - std::mt19937_64 gen(rd()); - std::uniform_int_distribution dis; - - for(int i=0; i<10; i++) { - u128_msg msg; - msg.values[0] = dis(gen); msg.values[0] <<= 64; msg.values[0] |= dis(gen); - msg.values[1] = dis(gen); msg.values[1] <<= 64; msg.values[1] |= dis(gen); - msg.values[2] = msg.values[0] * msg.values[1]; - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_math", "test_multeq_i128"), {}, fc::raw::pack(msg) ) == WASM_TEST_PASS, "test_math::test_multeq_i128()" ); - } - - for(int i=0; i<10; i++) { - u128_msg msg; - msg.values[0] = dis(gen); msg.values[0] <<= 64; msg.values[0] |= dis(gen); - msg.values[1] = dis(gen); msg.values[1] <<= 64; msg.values[1] |= dis(gen); - msg.values[2] = msg.values[0] / msg.values[1]; - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_math", "test_diveq_i128"), {}, fc::raw::pack(msg) ) == WASM_TEST_PASS, "test_math::test_diveq_i128()" ); - } - - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_math", "test_diveq_i128_by_0"), {}, {} ), - fc::assert_exception, is_assert_exception ); - - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_math", "test_double_api"), {}, {} ) == WASM_TEST_PASS, "test_math::test_double_api()" ); - - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_math", "test_double_api_div_0"), {}, {} ), - fc::assert_exception, is_assert_exception ); - - //Test db (i64) - const auto& idx = chain_db.get_index(); +} FC_LOG_AND_RETHROW() } - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64_general"), {}, {} ) == WASM_TEST_PASS, "test_db::key_i64_general()" ); - BOOST_CHECK_EQUAL( std::distance(idx.begin(), idx.end()) , 4); +template +struct setprod_act { + static account_name get_account() { + return N(config::system_account_name); + } + + static action_name get_name() { + return action_name(NAME); + } +}; + +/************************************************************************************* + * chain_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(chain_tests, tester) { try { + produce_blocks(2); + create_account( N(inita) ); + create_account( N(initb) ); + create_account( N(initc) ); + create_account( N(initd) ); + create_account( N(inite) ); + create_account( N(initf) ); + create_account( N(initg) ); + create_account( N(inith) ); + create_account( N(initi) ); + create_account( N(initj) ); + create_account( N(initk) ); + create_account( N(initl) ); + create_account( N(initm) ); + create_account( N(initn) ); + create_account( N(inito) ); + create_account( N(initp) ); + create_account( N(initq) ); + create_account( N(initr) ); + create_account( N(inits) ); + create_account( N(initt) ); + create_account( N(initu) ); + create_account( N(initv) ); + + create_account( N(testapi) ); + + // set active producers + { + signed_transaction trx; + + auto pl = vector{{config::system_account_name, config::active_name}}; + action act(pl, test_chain_action()); + vector prod_keys = { + { N(inita), get_public_key( N(inita), "active" ) }, + { N(initb), get_public_key( N(initb), "active" ) }, + { N(initc), get_public_key( N(initc), "active" ) }, + { N(initd), get_public_key( N(initd), "active" ) }, + { N(inite), get_public_key( N(inite), "active" ) }, + { N(initf), get_public_key( N(initf), "active" ) }, + { N(initg), get_public_key( N(initg), "active" ) }, + { N(inith), get_public_key( N(inith), "active" ) }, + { N(initi), get_public_key( N(initi), "active" ) }, + { N(initj), get_public_key( N(initj), "active" ) }, + { N(initk), get_public_key( N(initk), "active" ) }, + { N(initl), get_public_key( N(initl), "active" ) }, + { N(initm), get_public_key( N(initm), "active" ) }, + { N(initn), get_public_key( N(initn), "active" ) }, + { N(inito), get_public_key( N(inito), "active" ) }, + { N(initp), get_public_key( N(initp), "active" ) }, + { N(initq), get_public_key( N(initq), "active" ) }, + { N(initr), get_public_key( N(initr), "active" ) }, + { N(inits), get_public_key( N(inits), "active" ) }, + { N(initt), get_public_key( N(initt), "active" ) }, + { N(initu), get_public_key( N(initu), "active" ) } + }; + vector data = fc::raw::pack(uint32_t(0)); + vector keys = fc::raw::pack(prod_keys); + data.insert( data.end(), keys.begin(), keys.end() ); + act.data = data; + trx.actions.push_back(act); + + set_tapos(trx); - auto itr = idx.lower_bound( boost::make_tuple( N(testapi), N(testapi), N(test_table)) ); - - BOOST_CHECK_EQUAL((uint64_t)itr->primary_key, N(alice)); ++itr; - BOOST_CHECK_EQUAL((uint64_t)itr->primary_key, N(bob)); ++itr; - BOOST_CHECK_EQUAL((uint64_t)itr->primary_key, N(carol)); ++itr; - BOOST_CHECK_EQUAL((uint64_t)itr->primary_key, N(dave)); - - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64_remove_all"), {}, {} ) == WASM_TEST_PASS, "test_db::key_i64_remove_all()" ); - BOOST_CHECK_EQUAL( std::distance(idx.begin(), idx.end()) , 0); - - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64_small_load"), {}, {} ), - fc::assert_exception, is_assert_exception ); - - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64_small_store"), {}, {} ), - fc::assert_exception, is_assert_exception ); - - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_i64_store_scope"), {}, {}, {N(another)} ), - tx_missing_scope, is_tx_missing_scope ); - - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_i64_remove_scope"), {}, {}, {N(another)} ), - tx_missing_scope, is_tx_missing_scope ); - - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64_not_found"), {}, {} ) == WASM_TEST_PASS, "test_db::key_i64_not_found()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64_front_back"), {}, {} ) == WASM_TEST_PASS, "test_db::key_i64_front_back()" ); - - //Test db (i128i128) - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i128i128_general"), {}, {} ) == WASM_TEST_PASS, "test_db::key_i128i128_general()" ); - - //Test db (i64i64i64) - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_i64i64i64_general"), {}, {} ) == WASM_TEST_PASS, "test_db::key_i64i64i64_general()" ); - - //Test db (str) - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_db", "key_str_general"), {}, {} ) == WASM_TEST_PASS, "test_db::key_str_general()" ); - - //Test crypto - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_crypto", "test_sha256"), {}, {} ) == WASM_TEST_PASS, "test_crypto::test_sha256()" ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_crypto", "sha256_no_data"), {}, {} ), - fc::assert_exception, is_assert_exception ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_crypto", "asert_sha256_false"), {}, {} ), - fc::assert_exception, is_assert_exception ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_crypto", "asert_sha256_true"), {}, {} ) == WASM_TEST_PASS, "test_crypto::asert_sha256_true()" ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_crypto", "asert_no_data"), {}, {} ), - fc::assert_exception, is_assert_exception ); - - //Test transaction - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message"), {}, {}) == WASM_TEST_PASS, "test_transaction::send_message()"); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_empty"), {}, {}) == WASM_TEST_PASS, "test_transaction::send_message_empty()"); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_large"), {}, {} ), - tx_resource_exhausted, is_tx_resource_exhausted ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_max"), {}, {} ), - tx_resource_exhausted, is_tx_resource_exhausted ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_recurse"), {}, fc::raw::pack(dummy13) ), - transaction_exception, is_tx_resource_exhausted_or_checktime ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_inline_fail"), {}, {} ), - fc::assert_exception, is_assert_exception ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction"), {}, {}) == WASM_TEST_PASS, "test_transaction::send_message()"); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction_empty"), {}, {} ), - tx_unknown_argument, is_tx_unknown_argument ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction_large"), {}, {} ), - tx_resource_exhausted, is_tx_resource_exhausted ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction_max"), {}, {} ), - tx_resource_exhausted, is_tx_resource_exhausted ); - - auto& gpo = chain_db.get(); - std::vector prods(gpo.active_producers.size()); - std::copy(gpo.active_producers.begin(), gpo.active_producers.end(), prods.begin()); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_chain", "test_activeprods"), {}, fc::raw::pack(prods) ) == WASM_TEST_PASS, "test_chain::test_activeprods()" ); - - // Test string - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_size"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_size()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_data"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_data()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_data_copied"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_data_copied()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_data_partially"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_data_partially()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "copy_constructor"), {}, {} ) == WASM_TEST_PASS, "test_string::copy_constructor()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "assignment_operator"), {}, {} ) == WASM_TEST_PASS, "test_string::assignment_operator()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "index_operator"), {}, {} ) == WASM_TEST_PASS, "test_string::index_operator()" ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "index_out_of_bound"), {}, {} ), fc::assert_exception, is_assert_exception ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "substring"), {}, {} ) == WASM_TEST_PASS, "test_string::substring()" ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "substring_out_of_bound"), {}, {} ), fc::assert_exception, is_assert_exception ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "concatenation_null_terminated"), {}, {} ) == WASM_TEST_PASS, "test_string::concatenation_null_terminated()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "concatenation_non_null_terminated"), {}, {} ) == WASM_TEST_PASS, "test_string::concatenation_non_null_terminated()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "assign"), {}, {} ) == WASM_TEST_PASS, "test_string::assign()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "comparison_operator"), {}, {} ) == WASM_TEST_PASS, "test_string::comparison_operator()" ); - - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_fixedpoint", "create_instances"), {}, {} ) == WASM_TEST_PASS, "test_fixedpoint::create_instances()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_fixedpoint", "test_addition"), {}, {} ) == WASM_TEST_PASS, "test_fixedpoint::test_addition()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_fixedpoint", "test_subtraction"), {}, {} ) == WASM_TEST_PASS, "test_fixedpoint::test_subtraction()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_fixedpoint", "test_multiplication"), {}, {} ) == WASM_TEST_PASS, "test_fixedpoint::test_multiplication()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_fixedpoint", "test_division"), {}, {} ) == WASM_TEST_PASS, "test_fixedpoint::test_division()" ); - - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_real", "create_instances"), {}, {} ) == WASM_TEST_PASS, "test_real::create_instances()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_real", "test_addition"), {}, {} ) == WASM_TEST_PASS, "test_real::test_addition()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_real", "test_multiplication"), {}, {} ) == WASM_TEST_PASS, "test_real::test_multiplication()" ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_real", "test_division"), {}, {} ) == WASM_TEST_PASS, "test_real::test_division()" ); - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_real", "create_instances"), {}, {}) ); - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_string", "print_null_terminated"), {}, {}) ); - - BOOST_CHECK_EQUAL( capture.size() , 1); - BOOST_CHECK_EQUAL( capture[0], "Hello World!"); - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_string", "print_non_null_terminated"), {}, {}) ); - BOOST_CHECK_EQUAL( capture.size() , 1); - BOOST_CHECK_EQUAL( capture[0], "Hello World!"); - CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_string", "print_unicode"), {}, {}) ); - BOOST_CHECK_EQUAL( capture.size() , 1); - BOOST_CHECK_EQUAL( capture[0], "你好,世界!"); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "valid_utf8"), {}, {} ) == WASM_TEST_PASS, "test_string::valid_utf8()" ); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "invalid_utf8"), {}, {} ), fc::assert_exception, is_assert_exception ); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "string_literal"), {}, {} ) == WASM_TEST_PASS, "test_string::string_literal()" ); + auto sigs = trx.sign(get_private_key(config::system_account_name, "active"), chain_id_type()); + trx.get_signature_keys(chain_id_type() ); + auto res = push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + } + + set_code( N(testapi), test_api_wast ); + produce_blocks(100); + auto& gpo = control->get_global_properties(); + std::vector prods(gpo.active_producers.producers.size()); + for ( int i=0; i < gpo.active_producers.producers.size(); i++ ) { + prods[i] = gpo.active_producers.producers[i].producer_name; + } + CALL_TEST_FUNCTION( *this, "test_chain", "test_activeprods", fc::raw::pack(prods)); } FC_LOG_AND_RETHROW() } -#define RUN_CODE_HANDLER_WITH_TRANSFER(account_name, test_wast) \ - Make_Blockchain(chain); \ - chain.produce_blocks(1); \ - Make_Account(chain, account_name); \ - chain.produce_blocks(1); \ - \ - \ - handler.account = #account_name; \ - \ - auto wasm = assemble_wast( test_wast ); \ - handler.code.resize(wasm.size()); \ - memcpy( handler.code.data(), wasm.data(), wasm.size() ); \ - \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = {#account_name}; \ - trx.messages.resize(1); \ - trx.messages[0].code = config::eos_contract_name; \ - trx.messages[0].authorization.emplace_back(types::account_permission{#account_name,"active"}); \ - transaction_set_message(trx, 0, "setcode", handler); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - chain.produce_blocks(1); \ - } \ - \ - \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names({#account_name,"inita"}); \ - transaction_emplace_message(trx, #account_name, \ - vector{}, \ - "transfer", types::transfer{#account_name, "inita", 1,""}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - chain.produce_blocks(1); \ - } - -#define RUN_CODE_WITH_TRANSFER(account_name, test_wast) \ - types::setcode handler; \ - RUN_CODE_HANDLER_WITH_TRANSFER(account_name, test_wast) - -#define TEST_CASE_RUN_CODE_W_XFER(test_case_name, account_name, test_wast) \ -BOOST_FIXTURE_TEST_CASE(test_case_name, testing_fixture) \ -{ try{ \ - RUN_CODE_WITH_TRANSFER(account_name, test_wast); \ +/************************************************************************************* + * db_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(db_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + produce_blocks(1000); + set_code( N(testapi), test_api_db_wast ); + produce_blocks(1); + + CALL_TEST_FUNCTION( *this, "test_db", "key_str_general", {}); + CALL_TEST_FUNCTION( *this, "test_db", "primary_i64_general", {}); + CALL_TEST_FUNCTION( *this, "test_db", "primary_i64_lowerbound", {}); + CALL_TEST_FUNCTION( *this, "test_db", "primary_i64_upperbound", {}); + CALL_TEST_FUNCTION( *this, "test_db", "idx64_general", {}); + CALL_TEST_FUNCTION( *this, "test_db", "idx64_lowerbound", {}); + CALL_TEST_FUNCTION( *this, "test_db", "idx64_upperbound", {}); + /* + CALL_TEST_FUNCTION( *this, "test_db", "key_i64_general", {}); + CALL_TEST_FUNCTION( *this, "test_db", "key_i64_remove_all", {}); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_db", "key_i64_small_load", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "Data is not long enough to contain keys"); + } + ); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_db", "key_i64_small_store", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "Data is not long enough to contain keys"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_db", "key_i64_store_scope", {}); + CALL_TEST_FUNCTION( *this, "test_db", "key_i64_remove_scope", {}); + CALL_TEST_FUNCTION( *this, "test_db", "key_i64_not_found", {}); + CALL_TEST_FUNCTION( *this, "test_db", "key_i64_front_back", {}); + //CALL_TEST_FUNCTION( *this, "test_db", "key_i64i64i64_general", {}); + CALL_TEST_FUNCTION( *this, "test_db", "key_i128i128_general", {}); + */ } FC_LOG_AND_RETHROW() } -#define RUN_CODE_ABI_WITH_TRANSFER(account_name, test_wast, test_abi) \ - types::setcode handler; \ - handler.code_abi = fc::json::from_string(test_abi).as(); \ - RUN_CODE_HANDLER_WITH_TRANSFER(account_name, test_wast) +/************************************************************************************* + * fixedpoint_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(fixedpoint_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + produce_blocks(1000); + set_code( N(testapi), test_api_wast ); + produce_blocks(1000); + + CALL_TEST_FUNCTION( *this, "test_fixedpoint", "create_instances", {}); + CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_addition", {}); + CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_subtraction", {}); + CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_multiplication", {}); + CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_division", {}); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_division_by_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); -#define TEST_CASE_RUN_CODE_ABI_W_XFER(test_case_name, account_name, test_wast, test_abi) \ -BOOST_FIXTURE_TEST_CASE(test_case_name, testing_fixture) \ -{ try{ \ - RUN_CODE_ABI_WITH_TRANSFER(account_name, test_wast, test_abi); \ } FC_LOG_AND_RETHROW() } -//Test wasm memory allocation -TEST_CASE_RUN_CODE_W_XFER(test_memory, testmemory, memory_test_wast) -//Test memcmp -TEST_CASE_RUN_CODE_W_XFER(test_memcmp, testmemcmp, memory_test_wast) +/************************************************************************************* + * real_tests test cases + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(real_tests, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_wast); + produce_blocks(1000); -//Test wasm memory allocation of one large hunk -TEST_CASE_RUN_CODE_W_XFER(test_memory_hunk, testmemhunk, memory_test_wast) + CALL_TEST_FUNCTION( *this, "test_real", "create_instances", {} ); + CALL_TEST_FUNCTION( *this, "test_real", "test_addition", {} ); + CALL_TEST_FUNCTION( *this, "test_real", "test_multiplication", {} ); + CALL_TEST_FUNCTION( *this, "test_real", "test_division", {} ); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_real", "test_division_by_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); -//Test wasm memory allocation of many medium hunks in contiguous 2nd heap -TEST_CASE_RUN_CODE_W_XFER(test_memory_hunks, testmemhunks, memory_test_wast) -//Test wasm memory allocation of many medium hunks with disjoint heaps -TEST_CASE_RUN_CODE_W_XFER(test_memory_hunks_disjoint, testdisjoint, memory_test_wast) +} FC_LOG_AND_RETHROW() } -//Test intrinsic provided memset and memcpy -TEST_CASE_RUN_CODE_W_XFER(test_memset_memcpy, testmemset, memory_test_wast) -//Test memcpy overlap at start of destination -BOOST_FIXTURE_TEST_CASE(test_memcpy_overlap_start, testing_fixture) -{ - try { - RUN_CODE_WITH_TRANSFER(testolstart, memory_test_wast); - BOOST_FAIL("memcpy should have thrown assert exception"); - } - catch(fc::assert_exception& ex) - { - BOOST_REQUIRE(ex.to_detail_string().find("overlap of memory range is undefined") != std::string::npos); - } -} -//Test memcpy overlap at end of destination -BOOST_FIXTURE_TEST_CASE(test_memcpy_overlap_end, testing_fixture) -{ - try { - RUN_CODE_WITH_TRANSFER(testolend, memory_test_wast); - BOOST_FAIL("memcpy should have thrown assert exception"); - } - catch(fc::assert_exception& ex) - { - BOOST_REQUIRE(ex.to_detail_string().find("overlap of memory range is undefined") != std::string::npos); - } -} +/************************************************************************************* + * crypto_tests test cases + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(crypto_tests, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_wast); + produce_blocks(1000); + { + signed_transaction trx; + + auto pl = vector{{N(testapi), config::active_name}}; + + action act(pl, test_api_action{}); + auto signatures = trx.sign(get_private_key(N(testapi), "active"), chain_id_type()); + + produce_block(); + + auto payload = fc::raw::pack( trx.sig_digest( chain_id_type() ) ); + auto pk = fc::raw::pack( get_public_key( N(testapi), "active" ) ); + auto sigs = fc::raw::pack( signatures ); + payload.insert( payload.end(), pk.begin(), pk.end() ); + payload.insert( payload.end(), sigs.begin(), sigs.end() ); + + CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key", payload ); + CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_true", payload ); + payload[payload.size()-1] = 0; + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_false", payload ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message( e, "check == p: Error expected key different than recovered key" ); + } + ); + } + + CALL_TEST_FUNCTION( *this, "test_crypto", "test_sha1", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "test_sha256", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "test_sha512", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "test_ripemd160", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "sha1_no_data", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "sha256_no_data", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "sha512_no_data", {} ); + CALL_TEST_FUNCTION( *this, "test_crypto", "ripemd160_no_data", {} ); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha256_false", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "hash miss match"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha256_true", {} ); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_false", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "hash miss match"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_true", {} ); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_false", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "hash miss match"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_true", {} ); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha512_false", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "hash miss match"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha512_true", {} ); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_ripemd160_false", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "hash miss match"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_crypto", "assert_ripemd160_true", {} ); -//Test logic for memory.hpp adding extra pages of memory -TEST_CASE_RUN_CODE_W_XFER(test_extended_memory, testextmem, extended_memory_test_wast) +} FC_LOG_AND_RETHROW() } -//Test logic for extra pages of memory -TEST_CASE_RUN_CODE_W_XFER(test_page_memory, testpagemem, extended_memory_test_wast) -//Test logic for exceeding extra pages of memory -BOOST_FIXTURE_TEST_CASE(test_page_memory_exceeded, testing_fixture) -{ - try { - RUN_CODE_WITH_TRANSFER(testmemexc, extended_memory_test_wast); - BOOST_FAIL("sbrk should have thrown exception"); - } - catch (eosio::chain::page_memory_error& ) - { - // expected behavior - } -} +/************************************************************************************* + * memory_tests test cases + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(memory_tests, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_mem_wast); + produce_blocks(1000); + + CALL_TEST_FUNCTION( *this, "test_memory", "test_memory_allocs", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memory_hunk", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memory_hunks", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memory_hunks_disjoint", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memset_memcpy", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memcpy_overlap_start", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memcpy_overlap_end", {} ); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_memory", "test_memcmp", {} ); +} FC_LOG_AND_RETHROW() } -//Test logic for preventing reducing page memory -BOOST_FIXTURE_TEST_CASE(test_page_memory_negative_bytes, testing_fixture) -{ - try { - RUN_CODE_WITH_TRANSFER(testnegbytes, extended_memory_test_wast); - BOOST_FAIL("sbrk should have thrown exception"); + +/************************************************************************************* + * extended_memory_tests test cases + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(extended_memory_test_initial_memory, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_mem_wast); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_initial_buffer", {} ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(extended_memory_test_page_memory, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_mem_wast); + produce_blocks(1000); + CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_page_memory", {} ); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(extended_memory_test_page_memory_exceeded, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_mem_wast); + produce_blocks(1000); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_page_memory_exceeded", {} ), + page_memory_error, is_page_memory_error); + +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(extended_memory_test_page_memory_negative_bytes, tester) { try { + produce_blocks(1000); + create_account(N(testapi) ); + produce_blocks(1000); + set_code(N(testapi), test_api_mem_wast); + produce_blocks(1000); + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_page_memory_negative_bytes", {} ), + page_memory_error, is_page_memory_error); + +} FC_LOG_AND_RETHROW() } + +/************************************************************************************* + * print_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(print_tests, tester) { try { + produce_blocks(2); + create_account(N(testapi) ); + produce_blocks(1000); + + set_code(N(testapi), test_api_wast); + produce_blocks(1000); + string captured = ""; + + // test prints + CAPTURE_AND_PRE_TEST_PRINT("test_prints"); + BOOST_CHECK_EQUAL(captured == "abcefg", true); + + // test prints_l + CAPTURE_AND_PRE_TEST_PRINT("test_prints_l"); + BOOST_CHECK_EQUAL(captured == "abatest", true); + + // test printi + CAPTURE_AND_PRE_TEST_PRINT("test_printi"); + BOOST_CHECK_EQUAL( captured.substr(0,1), U64Str(0) ); + BOOST_CHECK_EQUAL( captured.substr(1,6), U64Str(556644) ); + BOOST_CHECK_EQUAL( captured.substr(7, capture[3].size()), U64Str(-1) ); // "18446744073709551615" + + // test printn + CAPTURE_AND_PRE_TEST_PRINT("test_printn"); + BOOST_CHECK_EQUAL( captured.substr(0,5), "abcde" ); + BOOST_CHECK_EQUAL( captured.substr(5, 5), "ab.de" ); + BOOST_CHECK_EQUAL( captured.substr(10, 6), "1q1q1q"); + BOOST_CHECK_EQUAL( captured.substr(16, 11), "abcdefghijk"); + BOOST_CHECK_EQUAL( captured.substr(27, 12), "abcdefghijkl"); + BOOST_CHECK_EQUAL( captured.substr(39, 13), "abcdefghijkl1"); + BOOST_CHECK_EQUAL( captured.substr(52, 13), "abcdefghijkl1"); + BOOST_CHECK_EQUAL( captured.substr(65, 13), "abcdefghijkl1"); + + // test printi128 + CAPTURE_AND_PRE_TEST_PRINT("test_printi128"); + BOOST_CHECK_EQUAL( captured.substr(0, 39), U128Str(-1) ); + BOOST_CHECK_EQUAL( captured.substr(39, 1), U128Str(0) ); + BOOST_CHECK_EQUAL( captured.substr(40, 11), U128Str(87654323456) ); + +} FC_LOG_AND_RETHROW() } + + +/************************************************************************************* + * math_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(math_tests, tester) { try { + produce_blocks(1000); + create_account( N(testapi) ); + produce_blocks(1000); + + produce_blocks(1000); + set_code( N(testapi), test_api_wast ); + produce_blocks(1000); + + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution dis; + + // test mult_eq with 10 random pairs of 128 bit numbers + for (int i=0; i < 10; i++) { + u128_action act; + act.values[0] = dis(gen); act.values[0] <<= 64; act.values[0] |= dis(gen); + act.values[1] = dis(gen); act.values[1] <<= 64; act.values[1] |= dis(gen); + act.values[2] = act.values[0] * act.values[1]; + CALL_TEST_FUNCTION( *this, "test_math", "test_multeq", fc::raw::pack(act)); } - catch (fc::assert_exception& ex) - { - BOOST_REQUIRE(ex.to_detail_string().find("not reduce") != std::string::npos); + // test div_eq with 10 random pairs of 128 bit numbers + for (int i=0; i < 10; i++) { + u128_action act; + act.values[0] = dis(gen); act.values[0] <<= 64; act.values[0] |= dis(gen); + act.values[1] = dis(gen); act.values[1] <<= 64; act.values[1] |= dis(gen); + act.values[2] = act.values[0] / act.values[1]; + CALL_TEST_FUNCTION( *this, "test_math", "test_diveq", fc::raw::pack(act)); } -} + // test diveq for divide by zero + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_math", "test_diveq_by_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); + + CALL_TEST_FUNCTION( *this, "test_math", "test_double_api", {}); + + union { + char whole[32]; + double _[4] = {2, -2, 100000, -100000}; + } d_vals; + + std::vector ds(sizeof(d_vals)); + std::copy(d_vals.whole, d_vals.whole+sizeof(d_vals), ds.begin()); + CALL_TEST_FUNCTION( *this, "test_math", "test_i64_to_double", ds); + + std::copy(d_vals.whole, d_vals.whole+sizeof(d_vals), ds.begin()); + CALL_TEST_FUNCTION( *this, "test_math", "test_double_to_i64", ds); + + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_math", "test_double_api_div_0", {}), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "divide by zero"); + } + ); + +} FC_LOG_AND_RETHROW() } -TEST_CASE_RUN_CODE_ABI_W_XFER(test_table_store_i64, storei, table_abi_test_wast, table_abi_test_abi) -TEST_CASE_RUN_CODE_ABI_W_XFER(test_table_store_i128i128, storeii, table_abi_test_wast, table_abi_test_abi) +/************************************************************************************* + * types_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(types_tests, tester) { try { + produce_blocks(1000); + create_account( N(testapi) ); -TEST_CASE_RUN_CODE_ABI_W_XFER(test_table_store_i64i64i64, storeiii, table_abi_test_wast, table_abi_test_abi) + produce_blocks(1000); + set_code( N(testapi), test_api_wast ); + produce_blocks(1000); -TEST_CASE_RUN_CODE_ABI_W_XFER(test_table_store_str, storestr, table_abi_test_wast, table_abi_test_abi) + CALL_TEST_FUNCTION( *this, "test_types", "types_size", {}); + CALL_TEST_FUNCTION( *this, "test_types", "char_to_symbol", {}); + CALL_TEST_FUNCTION( *this, "test_types", "string_to_name", {}); + CALL_TEST_FUNCTION( *this, "test_types", "name_class", {}); +} FC_LOG_AND_RETHROW() } -#define TEST_CASE_TABLE_TYPE_FAILURE(test_case_name, account_name, test_wast, test_abi) \ -BOOST_FIXTURE_TEST_CASE(test_case_name, testing_fixture) \ -{ \ - try { \ - RUN_CODE_ABI_WITH_TRANSFER(account_name, test_wast, test_abi); \ - BOOST_FAIL("should have thrown assert exception"); \ - } \ - catch(fc::assert_exception& ex) \ - { \ - const auto first = ex.to_detail_string().find("abi definition for"); \ - BOOST_REQUIRE(first != std::string::npos); \ - BOOST_REQUIRE(ex.to_detail_string().substr(first).find(" expects ") != std::string::npos); \ - } \ -} +#if 0 +/************************************************************************************* + * privileged_tests test case + *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(privileged_tests, tester) { try { + produce_blocks(2); + create_account( N(testapi) ); + create_account( N(acc1) ); + produce_blocks(100); + set_code( N(testapi), test_api_wast ); + produce_blocks(1); -TEST_CASE_TABLE_TYPE_FAILURE(test_table_store_fail_str_with_i64, strnoti, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_store_fail_i64_with_i128i128, inotii, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_store_fail_i128i128_with_i64i64i64, iinotiii, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_store_fail_i64i64i64_with_str, iiinotstr, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_load_fail_str_with_i64, ldstrnoti, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_load_fail_i64_with_i128i128, ldinotii, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_load_fail_i128i128_with_i64i64i64, ldiinotiii, table_abi_test_wast, table_abi_test_abi) - -TEST_CASE_TABLE_TYPE_FAILURE(test_table_load_fail_i64i64i64_with_str, ldiiinotstr, table_abi_test_wast, table_abi_test_abi) - -#define VERIFY_DB_KEY_TYPES(KEY_TYPE) \ -{ try { \ - auto wasm = assemble_wast( test_api_wast ); \ - \ - Make_Blockchain(chain, 5000, \ - ::eosio::chain_plugin::default_received_block_transaction_execution_time, \ - ::eosio::chain_plugin::default_create_block_transaction_execution_time, chain_controller::txn_msg_limits {}); \ - chain.produce_blocks(2); \ - Make_Account(chain, testapi); \ - Make_Account(chain, dblimits); \ - Make_Account(chain, another); \ - chain.produce_blocks(1); \ - \ - types::setcode handler; \ - handler.code.resize(wasm.size()); \ - memcpy( handler.code.data(), wasm.data(), wasm.size() ); \ - \ - send_set_code_message(chain, handler, "testapi"); \ - send_set_code_message(chain, handler, "another"); \ - \ - /* setup the limit */ \ - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_" KEY_TYPE "_setup_limit"), {}, {}, {N(dblimits)} ) == WASM_TEST_PASS, "test_db::key_" KEY_TYPE "_setup_limit()" ); \ - /* verify exception for exceeding limit */ \ - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_" KEY_TYPE "_min_exceed_limit"), {}, {}, {N(dblimits)} ), \ - tx_code_db_limit_exceeded, [](const tx_code_db_limit_exceeded& e) -> bool { return e.to_detail_string().find("Database limit exceeded") != std::string::npos; } ); \ - /* verify we can update and be under limit */ \ - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_" KEY_TYPE "_under_limit"), {}, {}, {N(dblimits)} ) == WASM_TEST_PASS, "test_db::key_" KEY_TYPE "_under_limit()" ); \ - /* verify exception for allocating more than remainder */ \ - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_" KEY_TYPE "_available_space_exceed_limit"), {}, {}, {N(dblimits)} ), \ - tx_code_db_limit_exceeded, [](const tx_code_db_limit_exceeded& e) -> bool { return e.to_detail_string().find("Database limit exceeded") != std::string::npos; } ); \ - /* verify removing and updating under limit is allowed */ \ - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_" KEY_TYPE "_another_under_limit"), {}, {}, {N(dblimits)} ) == WASM_TEST_PASS, "test_db::key_" KEY_TYPE "_another_under_limit()" ); \ - /* verify exception for exceeding limit */ \ - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_db", "key_" KEY_TYPE "_min_exceed_limit"), {}, {}, {N(dblimits)} ), \ - tx_code_db_limit_exceeded, [](const tx_code_db_limit_exceeded& e) -> bool { return e.to_detail_string().find("Database limit exceeded") != std::string::npos; } ); \ -} FC_LOG_AND_RETHROW() } + { + signed_transaction trx; + + auto pl = vector{{config::system_account_name, config::active_name}}; + action act(pl, test_chain_action()); + vector prod_keys = { + { N(inita), get_public_key( N(inita), "active" ) }, + { N(initb), get_public_key( N(initb), "active" ) }, + { N(initc), get_public_key( N(initc), "active" ) }, + { N(initd), get_public_key( N(initd), "active" ) }, + { N(inite), get_public_key( N(inite), "active" ) }, + { N(initf), get_public_key( N(initf), "active" ) }, + { N(initg), get_public_key( N(initg), "active" ) }, + { N(inith), get_public_key( N(inith), "active" ) }, + { N(initi), get_public_key( N(initi), "active" ) }, + { N(initj), get_public_key( N(initj), "active" ) }, + { N(initk), get_public_key( N(initk), "active" ) }, + { N(initl), get_public_key( N(initl), "active" ) }, + { N(initm), get_public_key( N(initm), "active" ) }, + { N(initn), get_public_key( N(initn), "active" ) }, + { N(inito), get_public_key( N(inito), "active" ) }, + { N(initp), get_public_key( N(initp), "active" ) }, + { N(initq), get_public_key( N(initq), "active" ) }, + { N(initr), get_public_key( N(initr), "active" ) }, + { N(inits), get_public_key( N(inits), "active" ) }, + { N(initt), get_public_key( N(initt), "active" ) }, + { N(initu), get_public_key( N(initu), "active" ) } + }; + vector data = fc::raw::pack(uint32_t(0)); + vector keys = fc::raw::pack(prod_keys); + data.insert( data.end(), keys.begin(), keys.end() ); + act.data = data; + trx.actions.push_back(act); + + set_tapos(trx); + + auto sigs = trx.sign(get_private_key(config::system_account_name, "active"), chain_id_type()); + trx.get_signature_keys(chain_id_type() ); + auto res = push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + } + + CALL_TEST_FUNCTION( *this, "test_privileged", "test_is_privileged", {} ); + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_privileged", "test_is_privileged", {} ), fc::assert_exception, + [](const fc::assert_exception& e) { + return expect_assert_message(e, "context.privileged: testapi does not have permission to call this API"); + } + ); -//Test logic for database storage limiting -BOOST_FIXTURE_TEST_CASE(test_database_limiting_for_str, testing_fixture) - VERIFY_DB_KEY_TYPES("str") - -//Test logic for database storage limiting -BOOST_FIXTURE_TEST_CASE(test_database_limiting_for_i64, testing_fixture) - VERIFY_DB_KEY_TYPES("i64") - -//Test logic for database storage limiting -BOOST_FIXTURE_TEST_CASE(test_database_limiting_for_i128i128, testing_fixture) - VERIFY_DB_KEY_TYPES("i128i128") - -//Test logic for database storage limiting -BOOST_FIXTURE_TEST_CASE(test_database_limiting_for_i64i64i64, testing_fixture) - VERIFY_DB_KEY_TYPES("i64i64i64") - -//Test logic for preventing reducing page memory -BOOST_FIXTURE_TEST_CASE(test_account_api_balance, testing_fixture) -{ try { - //auto wasm = assemble_wast( readFile2("/home/matu/Documents/Dev/eos/build/contracts/test_api/test_api.wast").c_str() ); - auto wasm = assemble_wast( test_api_wast ); - - Make_Blockchain(chain); - chain.produce_blocks(2); - Make_Account(chain, testapi); - Make_Account(chain, acc1); - chain.produce_blocks(1); - - //Set test code - types::setcode handler; - handler.code.resize(wasm.size()); - memcpy( handler.code.data(), wasm.data(), wasm.size() ); - - send_set_code_message(chain, handler, "testapi"); - - eosio::chain::signed_transaction trx; - trx.scope = sort_names({"acc1","inita"}); - transaction_emplace_message(trx, "eos", - vector{ {"inita","active"} }, - "transfer", types::transfer{"inita", "acc1", 1000,""}); - trx.expiration = chain.head_block_time() + 100; - transaction_set_reference_block(trx, chain.head_block_id()); - chain.push_transaction(trx); - chain.produce_blocks(1); - - const auto& balance = chain_db.get( "acc1" ); - const auto& staked_balance = chain_db.get( "acc1" ); - - // manually set balance so it can be verified in test_account - chain_db.modify(balance, [](eosio::chain::balance_object& bo) { - bo.balance = 24; - }); - chain_db.modify(staked_balance, [](eosio::chain::staked_balance_object& sbo) { - sbo.staked_balance = 23; - sbo.unstaking_balance = 14; - sbo.last_unstaking_time = types::time(55); - }); - - // Test account - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_account", "test_balance_acc1"), {}, {} ),tx_missing_scope, is_tx_missing_scope ); - vector scope = sort_names({"testapi", "acc1"}); - BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION_SCOPE( TEST_METHOD("test_account", "test_balance_acc1"), {}, {}, scope ) == WASM_TEST_PASS, "test_account::test_balance_acc1()" ); } FC_LOG_AND_RETHROW() } +#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/api_tests/extended_memory_test/CMakeLists.txt b/tests/api_tests/extended_memory_test/CMakeLists.txt deleted file mode 100644 index 32903770b4ee079cd17ab994bae04e638289d8c7..0000000000000000000000000000000000000000 --- a/tests/api_tests/extended_memory_test/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_wast_target(extended_memory_test "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/api_tests/extended_memory_test/extended_memory_test.cpp b/tests/api_tests/extended_memory_test/extended_memory_test.cpp deleted file mode 100644 index 84bf88de361385a97f645068957f46aa1fb120ab..0000000000000000000000000000000000000000 --- a/tests/api_tests/extended_memory_test/extended_memory_test.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -//#include -#include - -extern "C" { - - const uint32_t _64K = 65536; - - void init() - { - } - - void verify(const void* const ptr, const uint32_t val, const uint32_t size) - { - const char* char_ptr = (const char*)ptr; - for (uint32_t i = 0; i < size; ++i) - { - assert(static_cast(static_cast(char_ptr[i])) == val, "buf slot doesn't match"); - } - } - - /******************************************************************************************************* - * - * Current test is written assuming there is one intial "heap"(block of contiguous memory) and that up - * to 4 "heap"s will be created. The first heap is assumed to be 8192 chars and that the second through - * fourth "heap"s are 1024 chars (till adding pages are actually written). - * - *******************************************************************************************************/ - void test_extended_memory() - { - // initial buffer will be exhausted at 8192 - - // 8176 left (12 + ptr header) - char* ptr1 = (char*)eosio::malloc(12); - assert(ptr1 != nullptr, "should have allocated 12 char buf"); - // leave a little space at end of 1st buffer - char* ptr2 = (char*)eosio::malloc(8159); - assert(ptr2 != nullptr, "should have allocated 8159 char buf"); - - // allocated in 2nd memory heap - char* ptr3 = (char*)eosio::malloc(20); - assert(ptr3 != nullptr, "should have allocated a 20 char buf"); - verify(ptr3, 0, 20); - // re-sized in 1st memory heap - char* ptr2_realloc = (char*)eosio::realloc(ptr2, 8172); - assert(ptr2_realloc != nullptr, "should have returned a 8172 char buf"); - assert(ptr2_realloc == ptr2, "should have enlarged the 8159 char buf"); - - // re-sized in 1st memory heap - char* ptr1_realloc = (char*)eosio::realloc(ptr1, 5); - assert(ptr1_realloc != nullptr, "should have returned a 5 char buf"); - assert(ptr1_realloc == ptr1, "should have shrunk the 10 char buf"); - - // allocated in 2nd memory heap - char* ptr4 = (char*)eosio::malloc(20); - assert(ptr4 != nullptr, "should have allocated another 20 char buf"); - assert(ptr3 + 20 < ptr4, "20 char buf should have been created after ptr3"); // test specific to implementation (can remove for refactor) - - // re-size back to original - ptr1_realloc = (char*)eosio::realloc(ptr1, 10); - assert(ptr1_realloc != nullptr, "should have returned a 10 char buf"); - assert(ptr1_realloc == ptr1, "should have enlarged the 5 char buf"); - - // re-size into 2nd memory heap - ptr1_realloc = (char*)eosio::realloc(ptr1, 13); - assert(ptr1_realloc != nullptr, "should have returned a 13 char buf"); - assert(ptr1_realloc != ptr1, "should have reallocated the 12 char buf"); - assert(ptr4 + 20 < ptr1_realloc, "11 char buf should have been created after ptr4"); // test specific to implementation (can remove for refactor) - - // allocate rest of 2nd memory heap (1024 chars total) - ptr1 = ptr1_realloc; - ptr1_realloc = (char*)eosio::realloc(ptr1, 972); - assert(ptr1_realloc != nullptr, "should have returned a 972 char buf"); - assert(ptr1_realloc == ptr1, "should have resized the 11 char buf"); - - // allocated in 3rd memory heap (all of 1024 chars) - char* ptr5 = (char*)eosio::malloc(1020); - assert(ptr5 != nullptr, "should have allocated a 1020 char buf"); - assert(ptr1_realloc + 972 < ptr5, "972 char buf should have been created after ptr1_realloc"); // test specific to implementation (can remove for refactor) - - // allocated in 4th memory heap - char* ptr6 = (char*)eosio::malloc(996); - assert(ptr6 != nullptr, "should have allocated a 996 char buf"); - assert(ptr5 + 1020 < ptr6, "1020 char buf should have been created after ptr5"); // test specific to implementation (can remove for refactor) - } - - void test_page_memory() - { - auto prev = sbrk(0); - - assert(reinterpret_cast(prev) == _64K, "Should initially have 1 64K page allocated"); - - prev = sbrk(1); - - assert(reinterpret_cast(prev) == _64K, "Should still point to the end of 1st 64K page"); - - prev = sbrk(2); - - assert(reinterpret_cast(prev) == _64K + 8, "Should point to 8 past the end of 1st 64K page"); - - prev = sbrk(_64K - 17); - - assert(reinterpret_cast(prev) == _64K + 16, "Should point to 16 past the end of 1st 64K page"); - - prev = sbrk(1); - - assert(reinterpret_cast(prev) == 2*_64K, "Should point to the end of 2nd 64K page"); - - prev = sbrk(_64K); - - assert(reinterpret_cast(prev) == 2*_64K + 8, "Should point to 8 past the end of the 2nd 64K page"); - - prev = sbrk(_64K - 15); - - assert(reinterpret_cast(prev) == 3*_64K + 8, "Should point to 8 past the end of the 3rd 64K page"); - - prev = sbrk(2*_64K - 1); - - assert(reinterpret_cast(prev) == 4*_64K, "Should point to the end of 4th 64K page"); - - prev = sbrk(2*_64K); - - assert(reinterpret_cast(prev) == 6*_64K, "Should point to the end of 6th 64K page"); - - prev = sbrk(2*_64K + 1); - - assert(reinterpret_cast(prev) == 8*_64K, "Should point to the end of 8th 64K page"); - - prev = sbrk(6*_64K - 15); - - assert(reinterpret_cast(prev) == 10*_64K + 8, "Should point to 8 past the end of 13th 64K page"); - - prev = sbrk(0); - - assert(reinterpret_cast(prev) == 16*_64K, "Should point to the end of 16th 64K page"); - } - - void test_page_memory_exceeded() - { - auto prev = sbrk(15*_64K); - assert(reinterpret_cast(prev) == _64K, "Should have allocated up to the 1M of memory limit"); - sbrk(1); - assert(0, "Should have thrown exception for trying to allocate more than 1M of memory"); - } - - void test_page_memory_negative_bytes() - { - sbrk(-1); - assert(0, "Should have thrown exception for trying to remove memory"); - } - - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t code, uint64_t action ) - { - if( code == N(testextmem) ) - { - if( action == N(transfer) ) - { - test_extended_memory(); - } - } - else if( code == N(testpagemem) ) - { - if( action == N(transfer) ) - { - test_page_memory(); - } - } - else if( code == N(testmemexc) ) - { - if( action == N(transfer) ) - { - test_page_memory_exceeded(); - } - } - else if( code == N(testnegbytes) ) - { - if( action == N(transfer) ) - { - test_page_memory_negative_bytes(); - } - } - } -} diff --git a/tests/api_tests/memory_test/CMakeLists.txt b/tests/api_tests/memory_test/CMakeLists.txt deleted file mode 100644 index f21ef0989649c2a50d29c00d12f17c7d6fb7175d..0000000000000000000000000000000000000000 --- a/tests/api_tests/memory_test/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_wast_target(memory_test "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/api_tests/memory_test/memory_test.cpp b/tests/api_tests/memory_test/memory_test.cpp deleted file mode 100644 index 305cc86d3c60bcaaf4da40aea233dd192bc896ba..0000000000000000000000000000000000000000 --- a/tests/api_tests/memory_test/memory_test.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -//#include -#include - -extern "C" { - void init() - { - } - - void verify(const void* const ptr, const uint32_t val, const uint32_t size) - { - const char* char_ptr = (const char*)ptr; - for (uint32_t i = 0; i < size; ++i) - { - assert(static_cast(static_cast(char_ptr[i])) == val, "buf slot doesn't match"); - } - } - - void print(const void* const ptr, const uint32_t size) - { - const char* char_ptr = (const char*)ptr; - eosio::print("\n{ "); - for (uint32_t i = 0; i < size; ++i) - { - const char* delim = (i % 8 == 7) ? ", " : " "; - eosio::print("", static_cast(static_cast(char_ptr[i])), delim); - } - eosio::print("}\n"); - } - - /* - * malloc and realloc always allocate on 8 byte boundaries based off of total allocation, so - * if the requested size + the 2 byte header is not divisible by 8, then the allocated space - * will be larger than the requested size - */ - void test_memory() - { - char* ptr1 = (char*)eosio::malloc(0); - assert(ptr1 == nullptr, "should not have allocated a 0 char buf"); - - // 20 chars - 20 + 4(header) which is divisible by 8 - ptr1 = (char*)eosio::malloc(20); - assert(ptr1 != nullptr, "should have allocated a 20 char buf"); - verify(ptr1, 0, 20); - // existing memory layout -> |24| - - // 36 chars allocated - 30 + 4 plus an extra 6 to be divisible by 8 - char* ptr1_realloc = (char*)eosio::realloc(ptr1, 30); - assert(ptr1_realloc != nullptr, "should have returned a 30 char buf"); - assert(ptr1_realloc == ptr1, "should have enlarged the 20 char buf"); - // existing memory layout -> |40| - - // 20 chars allocated - char* ptr2 = (char*)eosio::malloc(20); - assert(ptr2 != nullptr, "should have allocated another 20 char buf"); - assert(ptr1 + 36 < ptr2, "20 char buf should have been created after ptr1"); // test specific to implementation (can remove for refactor) - verify(ptr1, 0, 36); - assert(ptr1[36] != 0, "should not have empty bytes following since block allocated"); // test specific to implementation (can remove for refactor) - // existing memory layout -> |40|24| - - //shrink the buffer - ptr1[14] = 0x7e; - // 20 chars allocated (still) - ptr1_realloc = (char*)eosio::realloc(ptr1, 15); - assert(ptr1_realloc != nullptr, "should have returned a 15 char buf"); - assert(ptr1_realloc == ptr1, "should have shrunk the reallocated 30 char buf"); - verify(ptr1, 0, 14); // test specific to implementation (can remove for refactor) - assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched"); - // existing memory layout -> |24(shrunk)|16(freed)|24| - - //same size the buffer (verify corner case) - // 20 chars allocated (still) - ptr1_realloc = (char*)eosio::realloc(ptr1, 15); - assert(ptr1_realloc != nullptr, "should have returned a reallocated 15 char buf"); - assert(ptr1_realloc == ptr1, "should have reallocated 15 char buf as the same buf"); - assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for unchanged buf"); - - //same size as max allocated buffer -- test specific to implementation (can remove for refactor) - ptr1_realloc = (char*)eosio::realloc(ptr1, 30); - assert(ptr1_realloc != nullptr, "should have returned a 30 char buf"); - assert(ptr1_realloc == ptr1, "should have increased the buf back to orig max"); //test specific to implementation (can remove for refactor) - assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for expanded buf"); - - //increase buffer beyond (indicated) allocated space - // 36 chars allocated (still) - ptr1_realloc = (char*)eosio::realloc(ptr1, 36); - assert(ptr1_realloc != nullptr, "should have returned a 36 char buf"); - assert(ptr1_realloc == ptr1, "should have increased char buf to actual size"); // test specific to implementation (can remove for refactor) - - //increase buffer beyond allocated space - ptr1[35] = 0x7f; - // 44 chars allocated - 37 + 4 plus an extra 7 to be divisible by 8 - ptr1_realloc = (char*)eosio::realloc(ptr1, 37); - assert(ptr1_realloc != nullptr, "should have returned a 37 char buf"); - assert(ptr1_realloc != ptr1, "should have had to create new 37 char buf from 36 char buf"); - assert(ptr2 < ptr1_realloc, "should have been created after ptr2"); // test specific to implementation (can remove for refactor) - assert(ptr1_realloc[14] == 0x7e, "orig 36 char buf's content should be copied"); - assert(ptr1_realloc[35] == 0x7f, "orig 36 char buf's content should be copied"); - - //realloc with nullptr - char* nullptr_realloc = (char*)eosio::realloc(nullptr, 50); - assert(nullptr_realloc != nullptr, "should have returned a 50 char buf and ignored nullptr"); - assert(ptr1_realloc < nullptr_realloc, "should have created after ptr1_realloc"); // test specific to implementation (can remove for refactor) - - //realloc with invalid ptr - char* invalid_ptr_realloc = (char*)eosio::realloc(nullptr_realloc + 4, 10); - assert(invalid_ptr_realloc != nullptr, "should have returned a 10 char buf and ignored invalid ptr"); - assert(nullptr_realloc < invalid_ptr_realloc, "should have created invalid_ptr_realloc after nullptr_realloc"); // test specific to implementation (can remove for refactor) - } - - // this test verifies that malloc can allocate 15 64K pages and treat them as one big heap space (if sbrk is not called in the mean time) - void test_memory_hunk() - { - // try to allocate the largest buffer we can, which is 15 contiguous 64K pages (with the 4 char space for the ptr header) - char* ptr1 = (char*)eosio::malloc(15 * 64 * 1024 - 4); - assert(ptr1 != nullptr, "should have allocated a ~983K char buf"); - } - - void test_memory_hunks() - { - // leave 784 bytes of initial buffer to allocate later (rounds up to nearest 8 byte boundary, - // 16 bytes bigger than remainder left below in 15 64K page heap)) - char* ptr1 = (char*)eosio::malloc(7404); - assert(ptr1 != nullptr, "should have allocated a 7404 char buf"); - - char* last_ptr = nullptr; - // 96 * (10 * 1024 - 15) => 15 ~64K pages with 768 byte buffer left to allocate - for (int i = 0; i < 96; ++i) - { - char* ptr2 = (char*)eosio::malloc(10 * 1024 - 15); - assert(ptr2 != nullptr, "should have allocated a ~10K char buf"); - if (last_ptr != nullptr) - { - // - 15 rounds to -8 - assert(last_ptr + 10 * 1024 - 8 == ptr2, "should allocate the very next ptr"); // test specific to implementation (can remove for refactor) - } - - last_ptr = ptr2; - } - - // try to allocate a buffer slightly larger than the remaining buffer| 765 + 4 rounds to 776 - char* ptr3 = (char*)eosio::malloc(765); - assert(ptr3 != nullptr, "should have allocated a 772 char buf"); - assert(ptr1 + 7408 == ptr3, "should allocate the very next ptr after ptr1 in initial heap"); // test specific to implementation (can remove for refactor) - - // use all but 8 chars - char* ptr4 = (char*)eosio::malloc(764); - assert(ptr4 != nullptr, "should have allocated a 764 char buf"); - assert(last_ptr + 10 * 1024 - 8 == ptr4, "should allocate the very next ptr after last_ptr at end of contiguous heap"); // test specific to implementation (can remove for refactor) - - // use up remaining 8 chars - char* ptr5 = (char*)eosio::malloc(4); - assert(ptr5 != nullptr, "should have allocated a 4 char buf"); - assert(ptr3 + 776 == ptr5, "should allocate the very next ptr after ptr3 in initial heap"); // test specific to implementation (can remove for refactor) - - // nothing left to allocate - char* ptr6 = (char*)eosio::malloc(4); - assert(ptr6 == nullptr, "should not have allocated a char buf"); - } - - void test_memory_hunks_disjoint() - { - // leave 8 bytes of initial buffer to allocate later - char* ptr1 = (char*)eosio::malloc(8 * 1024 - 12); - assert(ptr1 != nullptr, "should have allocated a 8184 char buf"); - - // can only make 14 extra (64K) heaps for malloc, since calls to sbrk will eat up part - char* loop_ptr1[14]; - // 14 * (64 * 1024 - 28) => 14 ~64K pages with each page having 24 bytes left to allocate - for (int i = 0; i < 14; ++i) - { - // allocates a new heap for each request, since sbrk call doesn't allow contiguous heaps to grow - loop_ptr1[i] = (char*)eosio::malloc(64 * 1024 - 28); - assert(loop_ptr1[i] != nullptr, "should have allocated a 64K char buf"); - - assert(sbrk(4) != nullptr, "should be able to allocate 8 bytes"); - } - - // the 15th extra heap is reduced in size because of the 14 * 8 bytes allocated by sbrk calls - // will leave 8 bytes to allocate later (verifying that we circle back in the list - char* ptr2 = (char*)eosio::malloc(65412); - assert(ptr2 != nullptr, "should have allocated a 65412 char buf"); - - char* loop_ptr2[14]; - for (int i = 0; i < 14; ++i) - { - // 12 char buffer to leave 8 bytes for another pass - loop_ptr2[i] = (char*)eosio::malloc(12); - assert(loop_ptr2[i] != nullptr, "should have allocated a 12 char buf"); - assert(loop_ptr1[i] + 64 * 1024 - 24 == loop_ptr2[i], "loop_ptr2[i] should be very next pointer after loop_ptr1[i]"); - } - - // this shows that searching for free ptrs starts at the last loop to find free memory, not at the begining - char* ptr3 = (char*)eosio::malloc(4); - assert(ptr3 != nullptr, "should have allocated a 4 char buf"); - assert(loop_ptr2[13] + 16 == ptr3, "should allocate the very next ptr after loop_ptr2[13]"); // test specific to implementation (can remove for refactor) - - char* ptr4 = (char*)eosio::malloc(4); - assert(ptr4 != nullptr, "should have allocated a 4 char buf"); - assert(ptr2 + 65416 == ptr4, "should allocate the very next ptr after ptr2 in last heap"); // test specific to implementation (can remove for refactor) - - char* ptr5 = (char*)eosio::malloc(4); - assert(ptr5 != nullptr, "should have allocated a 4 char buf"); - assert(ptr1 + 8184 == ptr5, "should allocate the very next ptr after ptr1 in last heap"); // test specific to implementation (can remove for refactor) - - // will eat up remaining memory (14th heap already used up) - char* loop_ptr3[13]; - for (int i = 0; i < 13; ++i) - { - // 4 char buffer to use up buffer - loop_ptr3[i] = (char*)eosio::malloc(4); - assert(loop_ptr3[i] != nullptr, "should have allocated a 4 char buf"); - assert(loop_ptr2[i] + 16 == loop_ptr3[i], "loop_ptr3[i] should be very next pointer after loop_ptr2[i]"); - } - - char* ptr6 = (char*)eosio::malloc(4); - assert(ptr6 == nullptr, "should not have allocated a char buf"); - - eosio::free(loop_ptr1[3]); - eosio::free(loop_ptr2[3]); - eosio::free(loop_ptr3[3]); - - char* slot3_ptr[64]; - for (int i = 0; i < 64; ++i) - { - slot3_ptr[i] = (char*)eosio::malloc(1020); - assert(slot3_ptr[i] != nullptr, "should have allocated a 1020 char buf"); - if (i == 0) - assert(loop_ptr1[3] == slot3_ptr[0], "loop_ptr1[3] should be very next pointer after slot3_ptr[0]"); - else - assert(slot3_ptr[i - 1] + 1024 == slot3_ptr[i], "slot3_ptr[i] should be very next pointer after slot3_ptr[i-1]"); - } - - char* ptr7 = (char*)eosio::malloc(4); - assert(ptr7 == nullptr, "should not have allocated a char buf"); - } - - void test_memset_memcpy() - { - char buf1[40] = {}; - char buf2[40] = {}; - - verify(buf1, 0, 40); - verify(buf2, 0, 40); - - memset(buf1, 0x22, 20); - verify(buf1, 0x22, 20); - verify(&buf1[20], 0, 20); - - memset(&buf2[20], 0xff, 20); - verify(buf2, 0, 20); - verify(&buf2[20], 0xff, 20); - - memcpy(&buf1[10], &buf2[10], 20); - verify(buf1, 0x22, 10); - verify(&buf1[10], 0, 10); - verify(&buf1[20], 0xff, 10); - verify(&buf1[30], 0, 10); - - memset(&buf1[1], 1, 1); - verify(buf1, 0x22, 1); - verify(&buf1[1], 1, 1); - verify(&buf1[2], 0x22, 8); - - // verify adjacent non-overlapping buffers - char buf3[50] = {}; - memset(&buf3[25], 0xee, 25); - verify(buf3, 0, 25); - memcpy(buf3, &buf3[25], 25); - verify(buf3, 0xee, 50); - - memset(buf3, 0, 25); - verify(&buf3[25], 0xee, 25); - memcpy(&buf3[25], buf3, 25); - verify(buf3, 0, 50); - } - - void test_memcpy_overlap_start() - { - char buf3[99] = {}; - memset(buf3, 0xee, 50); - memset(&buf3[50], 0xff, 49); - memcpy(&buf3[49], buf3, 50); - } - - - void test_memcpy_overlap_end() - { - char buf3[99] = {}; - memset(buf3, 0xee, 50); - memset(&buf3[50], 0xff, 49); - memcpy(buf3, &buf3[49], 50); - } - - void test_memcmp() - { - char buf1[] = "abcde"; - char buf2[] = "abcde"; - int32_t res1 = memcmp(buf1, buf2, 6); - assert(res1 == 0, "first data should be equal to second data"); - - char buf3[] = "abcde"; - char buf4[] = "fghij"; - int32_t res2 = memcmp(buf3, buf4, 6); - assert(res2 < 0, "first data should be smaller than second data"); - - char buf5[] = "fghij"; - char buf6[] = "abcde"; - int32_t res3 = memcmp(buf5, buf6, 6); - assert(res3 > 0, "first data should be larger than second data"); - } - - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t code, uint64_t action ) - { - if( code == N(testmemory) ) - { - if( action == N(transfer) ) - { - test_memory(); - } - } - else if( code == N(testmemhunk) ) - { - if( action == N(transfer) ) - { - test_memory_hunk(); - } - } - else if( code == N(testmemhunks) ) - { - if( action == N(transfer) ) - { - test_memory_hunks(); - } - } - else if( code == N(testdisjoint) ) - { - if( action == N(transfer) ) - { - test_memory_hunks_disjoint(); - } - } - else if( code == N(testmemset) ) - { - if( action == N(transfer) ) - { - test_memset_memcpy(); - } - } - else if( code == N(testolstart) ) - { - if( action == N(transfer) ) - { - test_memcpy_overlap_start(); - } - } - else if( code == N(testolend) ) - { - if( action == N(transfer) ) - { - test_memcpy_overlap_end(); - } - } - else if( code == N(testmemcmp) ) - { - if( action == N(transfer) ) - { - test_memcmp(); - } - } - } -} diff --git a/tests/api_tests/memory_test/memory_test.hpp b/tests/api_tests/memory_test/memory_test.hpp deleted file mode 100644 index d748cc62a2b87bd884d0b19e52ab7edc327380d8..0000000000000000000000000000000000000000 --- a/tests/api_tests/memory_test/memory_test.hpp +++ /dev/null @@ -1,9 +0,0 @@ - -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -namespace memory_test { - -} /// namespace memory_test - diff --git a/tests/chain_tests/block_tests.cpp b/tests/chain_tests/block_tests.cpp index e7d3040c1c7078bb5c48441773c677da7fa3f9f1..962485e2e3b258ea8695041f55028a3b53c1971b 100644 --- a/tests/chain_tests/block_tests.cpp +++ b/tests/chain_tests/block_tests.cpp @@ -36,7 +36,8 @@ BOOST_AUTO_TEST_CASE( schedule_test ) { try { } FC_LOG_AND_RETHROW() }/// schedule_test BOOST_AUTO_TEST_CASE( push_block ) { try { - tester test1, test2(chain_controller::runtime_limits(), false); + tester test1; + base_tester test2; for (uint32 i = 0; i < 1000; ++i) { test2.control->push_block(test1.produce_block()); diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp deleted file mode 100644 index 2ce79a4b504991ff8eef589512c5263c5c9cec6f..0000000000000000000000000000000000000000 --- a/tests/common/database_fixture.hpp +++ /dev/null @@ -1,257 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#include -#include -#include - -#include - -using namespace eosio::chain; - -extern uint32_t EOS_TESTING_GENESIS_TIMESTAMP; - -#define HAVE_DATABASE_FIXTURE -#include "testing_macros.hpp" - -#define TEST_DB_SIZE (1024*1024*1000) - -#define EOS_REQUIRE_THROW( expr, exc_type ) \ -{ \ - std::string req_throw_info = fc::json::to_string( \ - fc::mutable_variant_object() \ - ("source_file", __FILE__) \ - ("source_lineno", __LINE__) \ - ("expr", #expr) \ - ("exc_type", #exc_type) \ - ); \ - if( fc::enable_record_assert_trip ) \ - std::cout << "EOS_REQUIRE_THROW begin " \ - << req_throw_info << std::endl; \ - BOOST_REQUIRE_THROW( expr, exc_type ); \ - if( fc::enable_record_assert_trip ) \ - std::cout << "EOS_REQUIRE_THROW end " \ - << req_throw_info << std::endl; \ -} - -#define EOS_CHECK_THROW( expr, exc_type ) \ -{ \ - std::string req_throw_info = fc::json::to_string( \ - fc::mutable_variant_object() \ - ("source_file", __FILE__) \ - ("source_lineno", __LINE__) \ - ("expr", #expr) \ - ("exc_type", #exc_type) \ - ); \ - if( fc::enable_record_assert_trip ) \ - std::cout << "EOS_CHECK_THROW begin " \ - << req_throw_info << std::endl; \ - BOOST_CHECK_THROW( expr, exc_type ); \ - if( fc::enable_record_assert_trip ) \ - std::cout << "EOS_CHECK_THROW end " \ - << req_throw_info << std::endl; \ -} - -namespace eosio { namespace chain { -FC_DECLARE_EXCEPTION(testing_exception, 6000000, "test framework exception") -FC_DECLARE_DERIVED_EXCEPTION(missing_key_exception, eosio::chain::testing_exception, 6010000, "key could not be found") - -/** - * @brief The testing_fixture class provides various services relevant to testing the blockchain. - */ -class testing_fixture { -public: - testing_fixture(); - - /** - * @brief Get a temporary directory to store data in during this test - * - * @param id Identifier for the temporary directory. All requests for directories with the same ID will receive the - * same path. If id is empty, a unique directory will be returned. - * - * @return Path to the temporary directory - * - * This method makes it easy to get temporary directories for the duration of a test. All returned directories will - * be automatically deleted when the testing_fixture is destroyed. - * - * If multiple calls to this function are made with the same id, the same path will be returned. Multiple calls with - * distinct ids will not return the same path. If called with an empty id, a unique path will be returned which will - * not be returned from any subsequent call. - */ - fc::path get_temp_dir(std::string id = std::string()); - - const native_contract::genesis_state_type& genesis_state() const; - native_contract::genesis_state_type& genesis_state(); - - void store_private_key(const private_key_type& key); - private_key_type get_private_key(const public_key_type& public_key) const; - flat_set available_keys() const; - -protected: - std::vector anonymous_temp_dirs; - std::map named_temp_dirs; - std::map key_ring; - native_contract::genesis_state_type default_genesis_state; -}; - -/** - * @brief The testing_blockchain class wraps chain_controller and eliminates some of the boilerplate for common - * operations on the blockchain during testing. - * - * testing_blockchains have an optional ID, which is passed to the constructor. If two testing_blockchains are created - * with the same ID, they will have the same data directory. If no ID, or an empty ID, is provided, the database will - * have a unique data directory which no subsequent testing_blockchain will be assigned. - * - * testing_blockchain helps with producing blocks, or missing blocks, via the @ref produce_blocks and @ref miss_blocks - * methods. To produce N blocks, simply call produce_blocks(N); to miss N blocks, call miss_blocks(N). Note that missing - * blocks has no effect on the blockchain until the next block, following the missed blocks, is produced. - */ -class testing_blockchain : public chain_controller { -public: - testing_blockchain(chainbase::database& db, fork_database& fork_db, block_log& blocklog, - chain_initializer_interface& initializer, testing_fixture& fixture); - - testing_blockchain(chainbase::database& db, fork_database& fork_db, block_log& blocklog, - chain_initializer_interface& initializer, testing_fixture& fixture, - uint32_t transaction_execution_time_msec, - uint32_t received_block_execution_time_msec, - uint32_t create_block_execution_time_msec, - const chain_controller::txn_msg_limits& rate_limits = chain_controller::txn_msg_limits()); - - /** - * @brief Publish the provided contract to the blockchain, owned by owner - * @param owner The account to publish the contract under - * @param contract_wast The WAST of the contract - */ - void set_contract(account_name owner, const char* contract_wast); - - /** - * @brief Produce new blocks, adding them to the blockchain, optionally following a gap of missed blocks - * @param count Number of blocks to produce - * @param blocks_to_miss Number of block intervals to miss a production before producing the next block - * - * Creates and adds @ref count new blocks to the blockchain, after going @ref blocks_to_miss intervals without - * producing a block. - */ - void produce_blocks(uint32_t count = 1, uint32_t blocks_to_miss = 0); - - /** - * @brief Sync this blockchain with other - * @param other Blockchain to sync with - * - * To sync the blockchains, all blocks from one blockchain which are unknown to the other are pushed to the other, - * then the same thing in reverse. Whichever blockchain has more blocks will have its blocks sent to the other - * first. - * - * Blocks not on the main fork are ignored. - */ - void sync_with(testing_blockchain& other); - - /// @brief Get the liquid balance belonging to the named account - asset get_liquid_balance(const types::account_name& account); - /// @brief Get the staked balance belonging to the named account - asset get_staked_balance(const types::account_name& account); - /// @brief Get the unstaking balance belonging to the named account - asset get_unstaking_balance(const types::account_name& account); - - /// @brief Get the set of producers approved by the named account - std::set get_approved_producers(const account_name& account); - /// @brief Get the specified block producer's signing key - public_key get_block_signing_key(const account_name& producerName); - - /// @brief Attempt to sign the provided transaction using the keys available to the testing_fixture - void sign_transaction(signed_transaction& trx) const; - - /// @brief Override push_transaction to apply testing policies - /// If transactions are being held for review, transaction will be held after testing policies are applied - fc::optional push_transaction(signed_transaction trx, uint32_t skip_flags = 0); - /// @brief Review and optionally push last held transaction - /// @tparam F A callable with signature `bool f(SignedTransaction&, uint32_t&)` - /// @param reviewer Callable which inspects and potentially alters the held transaction and skip flags, and returns - /// whether it should be pushed or not - template - fc::optional review_transaction(F&& reviewer) { - if (reviewer(review_storage.first, review_storage.second)) - return chain_controller::push_transaction(review_storage.first, review_storage.second); - return {}; - } - - /// @brief Set whether testing_blockchain::push_transaction checks signatures by default - /// @param skip_sigs If true, push_transaction will skip signature checks; otherwise, no changes will be made - void set_skip_transaction_signature_checking(bool skip_sigs) { - skip_trx_sigs = skip_sigs; - } - /// @brief Set whether testing_blockchain::push_transaction attempts to sign transactions or not - void set_auto_sign_transactions(bool auto_sign) { - auto_sign_trxs = auto_sign; - } - /// @brief Set whether testing_blockchain::push_transaction holds transactions for review or not - void set_hold_transactions_for_review(bool hold_trxs) { - hold_for_review = hold_trxs; - } - - static std::vector assemble_wast(const std::string& wast); - -protected: - chainbase::database& db; - testing_fixture& fixture; - std::pair review_storage; - bool skip_trx_sigs = true; - bool auto_sign_trxs = false; - bool hold_for_review = false; -}; - -using boost::signals2::scoped_connection; - -/** - * @brief The testing_network class provides a simplistic virtual P2P network connecting testing_blockchains together. - * - * A testing_blockchain may be connected to zero or more testing_networks at any given time. When a new - * testing_blockchain joins the network, it will be synced with all other blockchains already in the network (blocks - * known only to the new chain will be pushed to the prior network members and vice versa, ignoring blocks not on the - * main fork). After this, whenever any blockchain in the network gets a new block, that block will be pushed to all - * other blockchains in the network as well. - */ -class testing_network { -public: - /** - * @brief Add a new database to the network - * @param new_blockchain The blockchain to add - */ - void connect_blockchain(testing_blockchain& new_database); - /** - * @brief Remove a database from the network - * @param leaving_blockchain The database to remove - */ - void disconnect_database(testing_blockchain& leaving_blockchain); - /** - * @brief Disconnect all blockchains from the network - */ - void disconnect_all(); - - /** - * @brief Send a block to all blockchains in this network - * @param block The block to send - */ - void propagate_block(const signed_block& block, const testing_blockchain& skip_db); - -protected: - std::map blockchains; -}; - -} } diff --git a/tests/common/macro_support.hpp b/tests/common/macro_support.hpp deleted file mode 100644 index 178d627e095a18ef6963e3e5823e3a39b1bd67bf..0000000000000000000000000000000000000000 --- a/tests/common/macro_support.hpp +++ /dev/null @@ -1,249 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include - -/** - * @file Contains support macros for the testcase helper macros. These macros are implementation details, and thus - * should not be used directly. Use their frontends instead. - */ - -#define MKCHAIN1(name) \ - chainbase::database name ## _db(get_temp_dir(), chainbase::database::read_write, TEST_DB_SIZE); \ - block_log name ## _log(get_temp_dir() / "blocklog"); \ - fork_database name ## _fdb; \ - native_contract::native_contract_chain_initializer name ## _initializer(genesis_state()); \ - testing_blockchain name(name ## _db, name ## _fdb, name ## _log, name ## _initializer, *this); \ - BOOST_TEST_CHECKPOINT("Created blockchain " << #name); -#define MKCHAIN2(name, id) \ - chainbase::database name ## _db(get_temp_dir(#id), chainbase::database::read_write, TEST_DB_SIZE); \ - block_log name ## _log(get_temp_dir(#id) / "blocklog"); \ - fork_database name ## _fdb; \ - native_contract::native_contract_chain_initializer name ## _initializer(genesis_state()); \ - testing_blockchain name(name ## _db, name ## _fdb, name ## _log, name ## _initializer, *this); \ - BOOST_TEST_CHECKPOINT("Created blockchain " << #name); -#define MKCHAIN5(name, transaction_execution_time_sec, receive_block_execution_time_sec, create_block_execution_time_sec, rate_limits) \ - chainbase::database name ## _db(get_temp_dir(), chainbase::database::read_write, TEST_DB_SIZE); \ - block_log name ## _log(get_temp_dir() / "blocklog"); \ - fork_database name ## _fdb; \ - native_contract::native_contract_chain_initializer name ## _initializer(genesis_state()); \ - testing_blockchain name(name ## _db, name ## _fdb, name ## _log, name ## _initializer, *this, transaction_execution_time_sec, receive_block_execution_time_sec, create_block_execution_time_sec, rate_limits); \ - BOOST_TEST_CHECKPOINT("Created blockchain " << #name); -#define MKCHAINS_MACRO(x, y, name) Make_Blockchain(name) - -#define MKNET1(name) testing_network name; BOOST_TEST_CHECKPOINT("Created testnet " << #name); -#define MKNET2_MACRO(x, name, chain) name.connect_blockchain(chain); -#define MKNET2(name, ...) MKNET1(name) BOOST_PP_SEQ_FOR_EACH(MKNET2_MACRO, name, __VA_ARGS__) - -inline std::vector sort_names( std::vector&& names ) { - std::sort( names.begin(), names.end() ); - auto itr = std::unique( names.begin(), names.end() ); - names.erase( itr, names.end() ); - return names; -} - -#define Complex_Authority_macro_Key(r, data, key_bubble) \ - data.keys.emplace_back(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, key_bubble), _public_key), \ - BOOST_PP_TUPLE_ELEM(2, 1, key_bubble)); -#define Complex_Authority_macro_Account(r, data, account_bubble) \ - data.accounts.emplace_back(types::account_permission{BOOST_PP_TUPLE_ELEM(3, 0, account_bubble), \ - BOOST_PP_TUPLE_ELEM(3, 1, account_bubble)}, \ - BOOST_PP_TUPLE_ELEM(3, 2, account_bubble)); - -#define MKACCT_IMPL(chain, name, creator, active, owner, recovery, deposit) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names({ #creator, config::eos_contract_name }); \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#creator, "active"}}, \ - "newaccount", types::newaccount{#creator, #name, owner, active, recovery, deposit}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Created account " << #name); \ - } -#define MKACCT2(chain, name) \ - Make_Key(name) \ - MKACCT_IMPL(chain, name, inita, Key_Authority(name ## _public_key), Key_Authority(name ## _public_key), \ - Account_Authority(inita), asset(100)) -#define MKACCT3(chain, name, creator) \ - Make_Key(name) \ - MKACCT_IMPL(chain, name, creator, Key_Authority(name ## _public_key), Key_Authority(name ## _public_key), \ - Account_Authority(creator), asset(100)) -#define MKACCT4(chain, name, creator, deposit) \ - Make_Key(name) \ - MKACCT_IMPL(chain, name, creator, Key_Authority(name ## _public_key), Key_Authority(name ## _public_key), \ - Account_Authority(creator), deposit) -#define MKACCT5(chain, name, creator, deposit, owner) \ - Make_Key(name) \ - MKACCT_IMPL(chain, name, creator, owner, Key_Authority(name ## _public_key), Account_Authority(creator), deposit) -#define MKACCT6(chain, name, creator, deposit, owner, active) \ - MKACCT_IMPL(chain, name, creator, owner, active, Account_Authority(creator), deposit) -#define MKACCT7(chain, name, creator, deposit, owner, active, recovery) \ - MKACCT_IMPL(chain, name, creator, owner, active, recovery, deposit) - -#define SETCODE3(chain, acct, wast) \ - { \ - auto wasm = eosio::chain::wast_to_wasm(wast); \ - types::setcode handler; \ - handler.account = #acct; \ - handler.code.assign(wasm.begin(), wasm.end()); \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names({config::eos_contract_name, #acct}); \ - transaction_emplace_message(trx, config::eos_contract_name, vector{{#acct,"active"}}, \ - "setcode", handler); \ - } - -#define SETAUTH5(chain, account, authname, parentname, auth) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = {#account}; \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#account,"active"}}, \ - "updateauth", types::updateauth{#account, authname, parentname, auth}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Set " << #account << "'s " << authname << " authority."); \ - } - -#define DELAUTH3(chain, account, authname) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = {#account}; \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#account,"active"}}, \ - "deleteauth", types::deleteauth{#account, authname}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Deleted " << #account << "'s " << authname << " authority."); \ - } - -#define LINKAUTH5(chain, account, authname, codeacct, messagetype) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = {#account}; \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#account,"active"}}, \ - "linkauth", types::linkauth{#account, #codeacct, messagetype, authname}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Link " << #codeacct << "::" << messagetype << " to " << #account \ - << "'s " << authname << " authority."); \ - } -#define LINKAUTH4(chain, account, authname, codeacct) LINKAUTH5(chain, account, authname, codeacct, "") - -#define UNLINKAUTH4(chain, account, codeacct, messagetype) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = {#account}; \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#account,"active"}}, \ - "unlinkauth", types::unlinkauth{#account, #codeacct, messagetype}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Unlink " << #codeacct << "::" << messagetype << " from " << #account); \ - } -#define LINKAUTH3(chain, account, codeacct) LINKAUTH5(chain, account, codeacct, "") - -#define XFER5(chain, sender, recipient, Amount, memo) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names({#sender,#recipient}); \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{ {#sender,"active"} }, \ - "transfer", types::transfer{#sender, #recipient, Amount.amount, memo}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Transferred " << Amount << " from " << #sender << " to " << #recipient); \ - } -#define XFER4(chain, sender, recipient, amount) XFER5(chain, sender, recipient, amount, "") - -#define STAKE4(chain, sender, recipient, amount) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names( { #sender, #recipient, config::eos_contract_name } ); \ - transaction_emplace_message(trx, config::eos_contract_name, vector{{#sender, "active"}}, \ - "lock", types::lock{#sender, #recipient, amount}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Staked " << amount << " to " << #recipient); \ - } -#define STAKE3(chain, account, amount) STAKE4(chain, account, account, amount) - -#define BEGIN_UNSTAKE3(chain, account, amount) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names( { config::eos_contract_name } ); \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#account, "active"}}, \ - "unlock", types::unlock{#account, amount}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Begin unstake " << amount << " to " << #account); \ - } - -#define FINISH_UNSTAKE3(chain, account, amount) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names( { config::eos_contract_name, #account } ); \ - transaction_emplace_message(trx, config::eos_contract_name, vector{{#account, "active"}}, \ - "claim", types::claim{#account, amount}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Finish unstake " << amount << " to " << #account); \ - } - -#define MKPDCR4(chain, owner, key, cfg) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names( {#owner, config::eos_contract_name} ); \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#owner, "active"}}, \ - "setproducer", types::setproducer{#owner, key, cfg}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Create producer " << #owner); \ - } -#define MKPDCR3(chain, owner, key) MKPDCR4(chain, owner, key, blockchain_configuration{}); -#define MKPDCR2(chain, owner) \ - Make_Key(owner ## _producer); \ - MKPDCR4(chain, owner, owner ## _producer_public_key, blockchain_configuration{}); - -#define APPDCR4(chain, voter, producer, approved) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names( {#voter, config::eos_contract_name} ); \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{#voter, "active"}}, \ - "okproducer", types::okproducer{#voter, #producer, approved? 1 : 0}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Set producer approval from " << #voter << " for " << #producer << " to " << approved); \ - } - -#define UPPDCR4(chain, owner, key, cfg) \ - { \ - eosio::chain::signed_transaction trx; \ - trx.scope = sort_names( {owner, config::eos_contract_name} ); \ - transaction_emplace_message(trx, config::eos_contract_name, \ - vector{{owner, "active"}}, \ - "setproducer", types::setproducer{owner, key, cfg}); \ - trx.expiration = chain.head_block_time() + 100; \ - transaction_set_reference_block(trx, chain.head_block_id()); \ - chain.push_transaction(trx); \ - BOOST_TEST_CHECKPOINT("Update producer " << owner); \ - } -#define UPPDCR3(chain, owner, key) UPPDCR4(chain, owner, key, chain.get_producer(owner).configuration) diff --git a/tests/common/testing_macros.hpp b/tests/common/testing_macros.hpp index b3c19844338eb919ea4121baf2d52db21d7d082c..649eb0b755cf2bcddae7f8f7f182d21945ec9296 100644 --- a/tests/common/testing_macros.hpp +++ b/tests/common/testing_macros.hpp @@ -4,7 +4,7 @@ */ #pragma once -#include +#include #include "macro_support.hpp" diff --git a/tests/consensusValidationMaliciousProducers.py b/tests/consensusValidationMaliciousProducers.py new file mode 100755 index 0000000000000000000000000000000000000000..751cc49100b037f29ecd0e68e49e7cf4e9108e90 --- /dev/null +++ b/tests/consensusValidationMaliciousProducers.py @@ -0,0 +1,414 @@ +#!/usr/bin/python3 + +import testUtils + +import argparse +import signal +from collections import namedtuple +import os +import shutil + +############################################################### +# Test for validating consensus based block production. We introduce malicious producers which +# reject all transactions. +# We have three test scenarios: +# - No malicious producers. Transactions should be incorporated into the chain. +# - Minority malicious producers (less than a third producer count). Transactions will get incorporated +# into the chain as majority appoves the transactions. +# - Majority malicious producer count (greater than a third producer count). Transactions won't get +# incorporated into the chain as majority rejects the transactions. +############################################################### + + +Print=testUtils.Utils.Print + +StagedNodeInfo=namedtuple("StagedNodeInfo", "config logging") + + +logging00="""{ + "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 + },{ + "name": "net", + "type": "gelf", + "args": { + "endpoint": "10.160.11.21:12201", + "host": "testnet_00" + }, + "enabled": true + } + ], + "loggers": [{ + "name": "default", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr", + "net" + ] + } + ] +}""" + +config00="""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:8888 +p2p-listen-endpoint = 0.0.0.0:9876 +p2p-server-address = localhost:9876 +allowed-connection = any +p2p-peer-address = localhost:9877 +required-participation = true +private-key = ["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"] +producer-name = initu +plugin = eosio::producer_plugin +plugin = eosio::chain_api_plugin +plugin = eosio::account_history_plugin +plugin = eosio::account_history_api_plugin""" + + +config01="""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 +required-participation = true +private-key = ["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"] +producer-name = initb +plugin = eosio::producer_plugin +plugin = eosio::chain_api_plugin +plugin = eosio::account_history_plugin +plugin = eosio::account_history_api_plugin""" + + +producers="""producer-name = initd +producer-name = initf +producer-name = inith +producer-name = initj +producer-name = initl +producer-name = initn +producer-name = initp +producer-name = initr +producer-name = initt +producer-name = inita +producer-name = initc +producer-name = inite +producer-name = initg +producer-name = initi +producer-name = initk +producer-name = initm +producer-name = inito +producer-name = initq +producer-name = inits""" + +zeroExecTime="trans-execution-time = 0" + +def getNoMaliciousStagedNodesInfo(): + stagedNodesInfo=[] + myConfig00=config00 + stagedNodesInfo.append(StagedNodeInfo(myConfig00, logging00)) + myConfig01=config01+"\n"+producers + stagedNodesInfo.append(StagedNodeInfo(myConfig01, logging00)) + return stagedNodesInfo + +def getMinorityMaliciousProducerStagedNodesInfo(): + stagedNodesInfo=[] + myConfig00=config00+"\n"+producers + stagedNodesInfo.append(StagedNodeInfo(myConfig00, logging00)) + myConfig01=config01+"\n"+zeroExecTime + stagedNodesInfo.append(StagedNodeInfo(myConfig01, logging00)) + return stagedNodesInfo + +def getMajorityMaliciousProducerStagedNodesInfo(): + stagedNodesInfo=[] + myConfig00=config00 + stagedNodesInfo.append(StagedNodeInfo(myConfig00, logging00)) + myConfig01=config01+"\n"+producers+"\n"+zeroExecTime + stagedNodesInfo.append(StagedNodeInfo(myConfig01, logging00)) + return stagedNodesInfo + +stagingDir="staging" +def stageScenario(stagedNodeInfos): + assert(stagedNodeInfos != None) + assert(len(stagedNodeInfos) > 1) + + os.makedirs(stagingDir) + count=0 + for stagedNodeInfo in stagedNodeInfos: + dataPath=os.path.join(stagingDir, "tn_data_%02d" % (count)) + os.makedirs(dataPath) + with open(os.path.join(dataPath, "config.ini"), "w") as textFile: + print(stagedNodeInfo.config,file=textFile) + with open(os.path.join(dataPath, "logging.json"), "w") as textFile: + print(stagedNodeInfo.logging,file=textFile) + count += 1 + return + +def cleanStaging(): + os.path.exists(stagingDir) and shutil.rmtree(stagingDir) + + +def errorExit(msg="", errorCode=1): + Print("ERROR:", msg) + exit(errorCode) + +def error(msg="", errorCode=1): + Print("ERROR:", msg) + +parser = argparse.ArgumentParser() +tests=[1,2,3] + +parser.add_argument("-t", "--tests", type=str, help="1|2|3 1=run no malicious producers test, 2=minority malicious, 3=majority malicious.", default=None) +parser.add_argument("-w", type=int, help="system wait time", default=testUtils.Utils.systemWaitTimeout) +parser.add_argument("-v", help="verbose logging", action='store_true') +parser.add_argument("--dumpErrorDetails", + help="Upon error print tn_data_*/config.ini and tn_data_*/stderr.log to stdout", + action='store_true') +parser.add_argument("--keepLogs", help="Don't delete tn_data_* folders upon test completion", + action='store_true') +parser.add_argument("--not-noon", help="This is not the Noon branch.", action='store_true') +parser.add_argument("--dontKill", help="Leave cluster running after test finishes", action='store_true') + +args = parser.parse_args() +testsArg=args.tests +debug=args.v +waitTimeout=args.w +dumpErrorDetails=args.dumpErrorDetails +keepLogs=args.keepLogs +amINoon=not args.not_noon +killEosInstances= not args.dontKill +killWallet= not args.dontKill + +testUtils.Utils.Debug=debug + +assert (testsArg is None or testsArg == "1" or testsArg == "2" or testsArg == "3") +if testsArg is not None: + tests=[int(testsArg)] + +testUtils.Utils.setSystemWaitTimeout(waitTimeout) +testUtils.Utils.iAmNotNoon() + +def myTest(transWillEnterBlock): + testSuccessful=False + + cluster=testUtils.Cluster(walletd=True, staging=True) + walletMgr=testUtils.WalletMgr(True) + + try: + cluster.killall() + cluster.cleanup() + walletMgr.killall() + walletMgr.cleanup() + + pnodes=2 + total_nodes=pnodes + topo="mesh" + delay=0 + Print("Stand up cluster") + if cluster.launch(pnodes, total_nodes, topo, delay) is False: + error("Failed to stand up eos cluster.") + return False + + accounts=testUtils.Cluster.createAccountKeys(1) + if accounts is None: + error("FAILURE - create keys") + return False + currencyAccount=accounts[0] + currencyAccount.name="currency" + + Print("Stand up walletd") + if walletMgr.launch() is False: + error("Failed to stand up eos walletd.") + return False + + testWalletName="test" + Print("Creating wallet \"%s\"." % (testWalletName)) + testWallet=walletMgr.create(testWalletName) + if testWallet is None: + error("Failed to create wallet %s." % (testWalletName)) + return False + + for account in accounts: + Print("Importing keys for account %s into wallet %s." % (account.name, testWallet.name)) + if not walletMgr.importKey(account, testWallet): + error("Failed to import key for account %s" % (account.name)) + return False + + node=cluster.getNode(0) + node2=cluster.getNode(1) + if node is None or node2 is None: + error("Cluster in bad state, received None node") + return False + + initaAccount=testUtils.Cluster.initaAccount + + Print("Importing keys for account %s into wallet %s." % (initaAccount.name, testWallet.name)) + if not walletMgr.importKey(initaAccount, testWallet): + error("Failed to import key for account %s" % (initaAccount.name)) + return False + + Print("Create new account %s via %s" % (currencyAccount.name, initaAccount.name)) + transId=node.createAccount(currencyAccount, initaAccount, stakedDeposit=5000, waitForTransBlock=True) + if transId is None: + error("Failed to create account %s" % (currencyAccount.name)) + return False + + wastFile="contracts/currency/currency.wast" + abiFile="contracts/currency/currency.abi" + Print("Publish contract") + trans=node.publishContract(currencyAccount.name, wastFile, abiFile, waitForTransBlock=True) + if trans is None: + error("Failed to publish contract.") + return False + + Print("push transfer action to currency contract") + contract="currency" + action="transfer" + data="{\"from\":\"currency\",\"to\":\"inita\",\"quantity\":" + if amINoon: + data +="\"00.0050 CUR\",\"memo\":\"test\"}" + else: + data +="50}" + opts="--permission currency@active" + if not amINoon: + opts += " --scope currency,inita" + + trans=node.pushMessage(contract, action, data, opts, silentErrors=True) + transInBlock=False + if not trans[0]: + # On slower systems e.g Travis the transaction rejection can happen immediately + # We want to handle fast and slow failures. + if "allocated processing time was exceeded" in trans[1]: + Print("Push message transaction immediately failed.") + else: + error("Exception in push message. %s" % (trans[1])) + return False + + else: + transId=testUtils.Node.getTransId(trans[1]) + + Print("verify transaction exists") + if not node2.waitForTransIdOnNode(transId): + error("Transaction never made it to node2") + return False + + Print("Get details for transaction %s" % (transId)) + transaction=node2.getTransaction(transId) + signature=transaction["transaction"]["signatures"][0] + + blockNum=int(transaction["transaction"]["ref_block_num"]) + blockNum += 1 + Print("Our transaction is in block %d" % (blockNum)) + + block=node2.getBlock(blockNum) + cycles=block["cycles"] + if len(cycles) > 0: + blockTransSignature=cycles[0][0]["user_input"][0]["signatures"][0] + # Print("Transaction signature: %s\nBlock transaction signature: %s" % + # (signature, blockTransSignature)) + transInBlock=(signature == blockTransSignature) + + if transWillEnterBlock: + if not transInBlock: + error("Transaction did not enter the chain.") + return False + else: + Print("SUCCESS: Transaction1 entered in the chain.") + elif not transWillEnterBlock: + if transInBlock: + error("Transaction entered the chain.") + return False + else: + Print("SUCCESS: Transaction2 did not enter the chain.") + + testSuccessful=True + finally: + if not testSuccessful and dumpErrorDetails: + cluster.dumpErrorDetails() + walletMgr.dumpErrorDetails() + Print("== Errors see above ==") + + if killEosInstances: + Print("Shut down the cluster%s" % (" and cleanup." if (testSuccessful and not keepLogs) else ".")) + cluster.killall() + walletMgr.killall() + if testSuccessful and not keepLogs: + Print("Cleanup cluster and wallet data.") + cluster.cleanup() + walletMgr.cleanup() + + return True + + +try: + if 1 in tests: + Print("Cluster with no malicious producers. All producers expected to approve transaction. Hence transaction is expected to enter the chain.") + cleanStaging() + stageScenario(getNoMaliciousStagedNodesInfo()) + if not myTest(True): + exit(1) + + if 2 in tests: + Print("\nCluster with minority(1) malicious nodes. Majority producers expected to approve transaction. Hence transaction is expected to enter the chain.") + cleanStaging() + stageScenario(getMinorityMaliciousProducerStagedNodesInfo()) + if not myTest(True): + exit(1) + + if 3 in tests: + Print("\nCluster with majority(20) malicious nodes. Majority producers expected to block transaction. Hence transaction is not expected to enter the chain.") + cleanStaging() + stageScenario(getMajorityMaliciousProducerStagedNodesInfo()) + if not myTest(False): + exit(1) + +finally: + cleanStaging() + +exit(0) + diff --git a/tests/distributed-transactions-remote-test.py b/tests/distributed-transactions-remote-test.py index c960234a5395df619ff5fbeb07aa5e2581b40234..bb7451f1dcef609c7df04cb0a8b9398254ce9d92 100755 --- a/tests/distributed-transactions-remote-test.py +++ b/tests/distributed-transactions-remote-test.py @@ -17,6 +17,7 @@ parser = argparse.ArgumentParser() parser.add_argument("-p", type=int, help="producing nodes count", default=pnodes) parser.add_argument("-v", help="verbose", action='store_true') parser.add_argument("--nodes-file", type=str, help="File containing nodes info in JSON format.", default=nodesFile) +parser.add_argument("--not-noon", help="This is not the Noon branch.", action='store_true') parser.add_argument("--dump-error-details", help="Upon error print tn_data_*/config.ini and tn_data_*/stderr.log to stdout", action='store_true') @@ -25,6 +26,7 @@ args = parser.parse_args() pnodes=args.p nodesFile=args.nodes_file debug=args.v +amINoon=not args.not_noon dumpErrorDetails=args.dump_error_details testUtils.Utils.Debug=debug @@ -36,6 +38,8 @@ total_nodes=pnodes actualTest="tests/distributed-transactions-test.py" testSuccessful=False +if not amINoon: + testUtils.Utils.iAmNotNoon() cluster=testUtils.Cluster() try: @@ -54,7 +58,7 @@ try: if not cluster.waitOnClusterBlockNumSync(3): errorExit("Cluster never stabilized") - cmd="%s --nodes-file %s %s" % (actualTest, nodesFile, "-v" if debug else "") + cmd="%s --nodes-file %s %s %s" % (actualTest, nodesFile, "-v" if debug else "", "" if amINoon else "--not-noon") Print("Starting up distributed transactions test: %s" % (actualTest)) Print("cmd: %s\n" % (cmd)) if 0 != subprocess.call(cmd, shell=True): diff --git a/tests/distributed-transactions-test.py b/tests/distributed-transactions-test.py index 938fa25aa9178f0d662ec0f5db68b466726356f9..e2edb7d31c37e110eb828463a6ec64d2ab0bde4d 100755 --- a/tests/distributed-transactions-test.py +++ b/tests/distributed-transactions-test.py @@ -21,6 +21,7 @@ parser.add_argument("-s", type=str, help="topology", default="mesh") parser.add_argument("-v", help="verbose", action='store_true') parser.add_argument("--nodes-file", type=str, help="File containing nodes info in JSON format.") parser.add_argument("--seed", type=int, help="random seed", default=seed) +parser.add_argument("--not-noon", help="This is not the Noon branch.", action='store_true') parser.add_argument("--dump-error-details", help="Upon error print tn_data_*/config.ini and tn_data_*/stderr.log to stdout", action='store_true') @@ -33,6 +34,7 @@ total_nodes = pnodes if args.n == 0 else args.n debug=args.v nodesFile=args.nodes_file seed=args.seed +amINoon=not args.not_noon dumpErrorDetails=args.dump_error_details killWallet=True @@ -43,6 +45,9 @@ if nodesFile is not None: testUtils.Utils.Debug=debug testSuccessful=False +if not amINoon: + testUtils.Utils.iAmNotNoon() + random.seed(seed) # Use a fixed seed for repeatability. cluster=testUtils.Cluster(walletd=True) walletMgr=testUtils.WalletMgr(True) @@ -52,7 +57,6 @@ try: Print("Stand up walletd") if walletMgr.launch() is False: - cmdError("%s" % (WalletdName)) errorExit("Failed to stand up eos walletd.") if nodesFile is not None: diff --git a/tests/eosiod_run_remote_test.py b/tests/eosiod_run_remote_test.py index c1b6bd2afa8576573558b8b57aeb7efc5c5eacdb..5d88b139a99e3c1dc8e0931c492a4563d16b9b94 100755 --- a/tests/eosiod_run_remote_test.py +++ b/tests/eosiod_run_remote_test.py @@ -13,12 +13,14 @@ def errorExit(msg="", errorCode=1): parser = argparse.ArgumentParser() parser.add_argument("-v", help="verbose", action='store_true') +parser.add_argument("--not-noon", help="This is not the Noon branch.", action='store_true') parser.add_argument("--dump-error-details", help="Upon error print tn_data_*/config.ini and tn_data_*/stderr.log to stdout", action='store_true') args = parser.parse_args() debug=args.v +amINoon=not args.not_noon dumpErrorDetails=args.dump_error_details testUtils.Utils.Debug=debug @@ -29,8 +31,13 @@ delay=1 pnodes=1 total_nodes=pnodes actualTest="tests/eosiod_run_test.py" +if not amINoon: + actualTest="tests/eosd_run_test.py" testSuccessful=False +if not amINoon: + testUtils.Utils.iAmNotNoon() + cluster=testUtils.Cluster() try: Print("BEGIN") @@ -48,8 +55,8 @@ try: if not cluster.waitOnClusterBlockNumSync(3): errorExit("Cluster never stabilized") - cmd="%s --dont-launch --exit-early %s" % (actualTest, "-v" if debug else "") - Print("Starting up eosiod test: %s" % (actualTest)) + cmd="%s --dont-launch %s %s" % (actualTest, "-v" if debug else "", "" if amINoon else "--not-noon") + Print("Starting up %s test: %s" % ("eosiod" if amINoon else "eosd", actualTest)) Print("cmd: %s\n" % (cmd)) if 0 != subprocess.call(cmd, shell=True): errorExit("failed to run cmd.") diff --git a/tests/eosiod_run_test.py b/tests/eosiod_run_test.py index 9b92159876515f9f6359ec01c796441d5b19371c..1cc2f0ee0af263aed26426da7be2fc361ca54e04 100755 --- a/tests/eosiod_run_test.py +++ b/tests/eosiod_run_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import testUtils @@ -458,13 +458,19 @@ try: Print("push transfer action to currency contract") contract="currency" action="transfer" - data="{\"from\":\"currency\",\"to\":\"inita\",\"quantity\":\"00.0050 CUR\",\"memo\":\"test\"}" + data="{\"from\":\"currency\",\"to\":\"inita\",\"quantity\":" + if amINoon: + data +="\"00.0050 CUR\",\"memo\":\"test\"}" + else: + data +="50}" opts="--permission currency@active" + if not amINoon: + opts += " --scope currency,inita" trans=node.pushMessage(contract, action, data, opts) - if trans is None: + if not trans[0]: cmdError("%s push message currency transfer" % (ClientName)) errorExit("Failed to push message to currency contract") - transId=testUtils.Node.getTransId(trans) + transId=testUtils.Node.getTransId(trans[1]) Print("verify transaction exists") if not node.waitForTransIdOnNode(transId): diff --git a/tests/restart-scenarios-test.py b/tests/restart-scenarios-test.py index 79e08a94b24301d969e7ddcdc15c64997621cb56..f982b08ca8b3672244e5e3621df51017a617d3ec 100755 --- a/tests/restart-scenarios-test.py +++ b/tests/restart-scenarios-test.py @@ -22,7 +22,7 @@ import signal ############################################################### -DefaultKillPercent=50 +DefaultKillPercent=25 Print=testUtils.Utils.Print def errorExit(msg="", errorCode=1): @@ -41,6 +41,7 @@ parser.add_argument("--killSig", type=str, help="kill signal[%s|%s]" % parser.add_argument("--killCount", type=int, help="eosiod instances to kill", default=-1) parser.add_argument("-v", help="verbose logging", action='store_true') parser.add_argument("--dontKill", help="Leave cluster running after test finishes", action='store_true') +parser.add_argument("--not-noon", help="This is not the Noon branch.", action='store_true') parser.add_argument("--dumpErrorDetails", help="Upon error print tn_data_*/config.ini and tn_data_*/stderr.log to stdout", action='store_true') @@ -54,14 +55,18 @@ delay=args.d chainSyncStrategyStr=args.c debug=args.v total_nodes = pnodes -killCount=args.killCount if args.killCount > 0 else int((DefaultKillPercent/100.0)*total_nodes) +killCount=args.killCount if args.killCount > 0 else int(round((DefaultKillPercent/100.0)*total_nodes)) killSignal=args.killSig killEosInstances= not args.dontKill dumpErrorDetails=args.dumpErrorDetails keepLogs=args.keepLogs +amINoon=not args.not_noon testUtils.Utils.Debug=debug +if not amINoon: + testUtils.Utils.iAmNotNoon() + Print ("producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d, chain sync strategy: %s" % ( pnodes, topo, delay, chainSyncStrategyStr)) @@ -148,7 +153,7 @@ finally: if not testSuccessful and dumpErrorDetails: cluster.dumpErrorDetails() walletMgr.dumpErrorDetails() - Utils.Print("== Errors see above ==") + Print("== Errors see above ==") if killEosInstances: Print("Shut down the cluster%s" % (" and cleanup." if (testSuccessful and not keepLogs) else ".")) diff --git a/tests/slow_tests/slow_tests.cpp b/tests/slow_tests/slow_tests.cpp index fc56d869f2f9f8470158f9bbaacb53f8bf1bb3f6..32487929b5ad6e46d61af72acb36b87f4f1c04a5 100644 --- a/tests/slow_tests/slow_tests.cpp +++ b/tests/slow_tests/slow_tests.cpp @@ -14,8 +14,6 @@ #include -#include - #include #include "../common/database_fixture.hpp" diff --git a/tests/testUtils.py b/tests/testUtils.py index 4e0eb7c962f77f2e6cf4293d736db5200fb6a64d..45917fa2c3b482ea99d6cc950e6c0f9f4ed00a3b 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -23,11 +23,13 @@ class Utils: Debug=False FNull = open(os.devnull, 'w') - EosServerName="eosiod" EosClientPath="programs/eosioc/eosioc" - EosWalletPath="programs/eosiowd/eosiowd" + + EosWalletName="eosiowd" + EosWalletPath="programs/eosiowd/"+ EosWalletName + EosServerName="eosiod" - EosServerPath="programs/eosiod/%s" % (EosServerName) + EosServerPath="programs/eosiod/"+ EosServerName EosLauncherPath="programs/eosio-launcher/eosio-launcher" MongoPath="mongo" @@ -48,6 +50,8 @@ class Utils: SigKillTag="kill" SigTermTag="term" + systemWaitTimeout=60 + # mongoSyncTime: eosiod mongodb plugin seems to sync with a 10-15 seconds delay. This will inject # a wait period before the 2nd DB check (if first check fails) mongoSyncTime=25 @@ -57,15 +61,23 @@ class Utils: @staticmethod def iAmNotNoon(): Utils.amINoon=False - Utils.EosServerName="eosd" + Utils.EosClientPath="programs/eosc/eosc" - Utils.EosWalletPath="programs/eos-walletd/eos-walletd" - Utils.EosServerPath="programs/eosd/%s" % (Utils.EosServerName) + + Utils.EosWalletName="eos-walletd" + Utils.EosWalletPath="programs/eos-walletd/"+ Utils.EosWalletName + + Utils.EosServerName="eosd" + Utils.EosServerPath="programs/eosd/"+ Utils.EosServerName @staticmethod def setMongoSyncTime(syncTime): Utils.mongoSyncTime=syncTime - + + @staticmethod + def setSystemWaitTimeout(timeout): + Utils.systemWaitTimeout=timeout + @staticmethod def getChainStrategies(): chainSyncStrategies={} @@ -81,6 +93,12 @@ class Utils: return chainSyncStrategies + @staticmethod + def checkOutput(cmd): + assert(isinstance(cmd, list)) + retStr=subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode("utf-8") + return retStr + @staticmethod def errorExit(msg="", raw=False, errorCode=1): Utils.Print("ERROR:" if not raw else "", msg) @@ -140,7 +158,7 @@ class Node(object): @staticmethod def runCmdReturnJson(cmd, trace=False): - retStr=Node.__checkOutput(cmd.split()) + retStr=Utils.checkOutput(cmd.split()) jStr=Node.filterJsonObject(retStr) trace and Utils.Print ("RAW > %s"% retStr) trace and Utils.Print ("JSON> %s"% jStr) @@ -149,7 +167,7 @@ class Node(object): @staticmethod def __runCmdArrReturnJson(cmdArr, trace=False): - retStr=Node.__checkOutput(cmdArr) + retStr=Utils.checkOutput(cmdArr) jStr=Node.filterJsonObject(retStr) trace and Utils.Print ("RAW > %s"% retStr) trace and Utils.Print ("JSON> %s"% jStr) @@ -220,6 +238,7 @@ class Node(object): @staticmethod def getTransId(trans): + #Utils.Print("%s" % trans) transId=trans["transaction_id"] return transId @@ -259,6 +278,7 @@ class Node(object): if not retry: break if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None @@ -280,17 +300,18 @@ class Node(object): if not retry: break if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None def doesNodeHaveBlockNum(self, blockNum): - if self.alive is False: - return False + assert isinstance(blockNum, int) - block=self.getBlock(blockNum, silentErrors=True) - if block is None: + info=self.getInfo(silentErrors=True) + last_irreversible_block_num=int(info["last_irreversible_block_num"]) + if blockNum > last_irreversible_block_num: return False else: return True @@ -323,6 +344,7 @@ class Node(object): if not retry: break if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None @@ -344,6 +366,7 @@ class Node(object): if not retry: break if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None @@ -367,6 +390,7 @@ class Node(object): if not retry: break if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None @@ -388,18 +412,25 @@ class Node(object): if not retry: break if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None - def doesNodeHaveTransId(self, transId): trans=self.getTransaction(transId, silentErrors=True) - if trans is not None: - return True - else: + if trans is None: return False + blockNum=None + if not self.enableMongo: + blockNum=int(trans["transaction"]["data"]["ref_block_num"]) + else: + blockNum=int(trans["ref_block_num"]) + + blockNum += 1 + return self.doesNodeHaveBlockNum(blockNum) + def createInitAccounts(self): eosio = copy.copy(Cluster.initaAccount) eosio.name = "eosio" @@ -418,7 +449,7 @@ class Node(object): data="{\"to\":\"eosio\",\"quantity\":\"1000000000.0000 EOS\"}" opts="--permission eosio@active" trans=self.pushMessage(contract, action, data, opts) - transId=Node.getTransId(trans) + transId=Node.getTransId(trans[1]) self.waitForTransIdOnNode(transId) initx = copy.copy(Cluster.initaAccount) @@ -445,7 +476,7 @@ class Node(object): cmd="%s %s create account %s %s %s %s" % (Utils.EosClientPath, self.endpointArgs, creatorAccount.name, account.name, account.ownerPublicKey, account.activePublicKey) - + Utils.Debug and Utils.Print("cmd: %s" % (cmd)) trans=None try: @@ -522,48 +553,61 @@ class Node(object): return None return ret if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) return None - def waitForBlockNumOnNode(self, blockNum, timeout=60): + def waitForBlockNumOnNode(self, blockNum, timeout=None): + if timeout is None: + timeout=Utils.systemWaitTimeout startTime=time.time() remainingTime=timeout + Utils.Debug and Utils.Print("cmd: remaining time %d seconds" % (remainingTime)) while time.time()-startTime < timeout: if self.doesNodeHaveBlockNum(blockNum): return True sleepTime=3 if remainingTime > 3 else (3 - remainingTime) remainingTime -= sleepTime + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (sleepTime)) time.sleep(sleepTime) return False - def waitForTransIdOnNode(self, transId, timeout=60): + def waitForTransIdOnNode(self, transId, timeout=None): + if timeout is None: + timeout=Utils.systemWaitTimeout startTime=time.time() remainingTime=timeout + Utils.Debug and Utils.Print("cmd: remaining time %d seconds" % (remainingTime)) while time.time()-startTime < timeout: if self.doesNodeHaveTransId(transId): return True sleepTime=3 if remainingTime > 3 else (3 - remainingTime) remainingTime -= sleepTime + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (sleepTime)) time.sleep(sleepTime) return False - def waitForNextBlock(self, timeout=60): + def waitForNextBlock(self, timeout=None): + if timeout is None: + timeout=Utils.systemWaitTimeout startTime=time.time() remainingTime=timeout - num=self.getHeadBlockNum() + Utils.Debug and Utils.Print("cmd: remaining time %d seconds" % (remainingTime)) + num=self.getIrreversibleBlockNum() Utils.Debug and Utils.Print("Current block number: %s" % (num)) while time.time()-startTime < timeout: - nextNum=self.getHeadBlockNum() + nextNum=self.getIrreversibleBlockNum() if nextNum > num: Utils.Debug and Utils.Print("Next block number: %s" % (nextNum)) return True sleepTime=.5 if remainingTime > .5 else (.5 - remainingTime) remainingTime -= sleepTime + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (sleepTime)) time.sleep(sleepTime) return False @@ -652,6 +696,7 @@ class Node(object): return balance else: if self.mongoSyncTime is not None: + Utils.Debug and Utils.Print("cmd: sleep %d seconds" % (self.mongoSyncTime)) time.sleep(self.mongoSyncTime) account=self.getEosAccountFromDb(name) @@ -689,7 +734,7 @@ class Node(object): cmd="%s %s get code %s" % (Utils.EosClientPath, self.endpointArgs, account) Utils.Debug and Utils.Print("cmd: %s" % (cmd)) try: - retStr=Node.__checkOutput(cmd.split()) + retStr=Utils.checkOutput(cmd.split()) #Utils.Print ("get code> %s"% retStr) p=re.compile('code\shash: (\w+)\n', re.MULTILINE) m=p.search(retStr) @@ -788,7 +833,8 @@ class Node(object): keys=list(row.keys()) return keys - def pushMessage(self, contract, action, data, opts): + # returns tuple with transaction and + def pushMessage(self, contract, action, data, opts, silentErrors=False): cmd=None if Utils.amINoon: cmd="%s %s push action %s %s" % (Utils.EosClientPath, self.endpointArgs, contract, action) @@ -802,11 +848,12 @@ class Node(object): Utils.Debug and Utils.Print("cmd: %s" % (cmdArr)) try: trans=Node.__runCmdArrReturnJson(cmdArr) - return trans + return (True, trans) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during push message. %s" % (msg)) - return None + if not silentErrors: + Utils.Print("ERROR: Exception during push message. %s" % (msg)) + return (False, msg) def setPermission(self, account, code, pType, requirement, waitForTransBlock=False): cmd="%s %s set action permission %s %s %s %s" % ( @@ -870,7 +917,19 @@ class Node(object): blockNum=block["block_num"] return blockNum return None - + + def getIrreversibleBlockNum(self): + if not self.enableMongo: + info=self.getInfo() + if info is not None: + return info["last_irreversible_block_num"] + else: + block=self.getBlockFromDb(-1) + if block is not None: + blockNum=block["block_num"] + return blockNum + return None + ########################################################################################### Wallet=namedtuple("Wallet", "name password host port") @@ -972,7 +1031,7 @@ class WalletMgr(object): def unlockWallet(self, wallet): cmd="%s %s wallet unlock --name %s" % (Utils.EosClientPath, self.endpointArgs, wallet.name) - #Utils.Debug and Utils.Print("cmd: %s" % (cmd)) + Utils.Debug and Utils.Print("cmd: %s" % (cmd)) popen=subprocess.Popen(cmd.split(), stdout=Utils.FNull, stdin=subprocess.PIPE) outs, errs = popen.communicate(input=wallet.password.encode("utf-8")) if 0 != popen.wait(): @@ -1032,8 +1091,9 @@ class WalletMgr(object): shutil.copyfileobj(f, sys.stdout) def killall(self): - if self.__walletPid is not None: - os.kill(self.__walletPid, signal.SIGKILL) + cmd="pkill %s" % (Utils.EosWalletName) + Utils.Debug and Utils.Print("cmd: %s" % (cmd)) + subprocess.call(cmd.split()) def cleanup(self): dataDir=WalletMgr.__walletDataDir @@ -1062,7 +1122,7 @@ class Cluster(object): initbAccount.activePublicKey="EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"; # walletd [True|False] Is walletd running. If not load the wallet plugin - def __init__(self, walletd=False, localCluster=True, host="localhost", port=8888, walletHost="localhost", walletPort=8899, enableMongo=False, mongoHost="localhost", mongoPort=27017, mongoDb="EOStest", initaPrvtKey=initaAccount.ownerPrivateKey, initbPrvtKey=initbAccount.ownerPrivateKey): + def __init__(self, walletd=False, localCluster=True, host="localhost", port=8888, walletHost="localhost", walletPort=8899, enableMongo=False, mongoHost="localhost", mongoPort=27017, mongoDb="EOStest", initaPrvtKey=initaAccount.ownerPrivateKey, initbPrvtKey=initbAccount.ownerPrivateKey, staging=False): self.accounts={} self.nodes={} self.localCluster=localCluster @@ -1087,6 +1147,7 @@ class Cluster(object): self.mongoEndpointArgs += "--host %s --port %d %s" % (mongoHost, mongoPort, mongoDb) Cluster.initaAccount.ownerPrivateKey=initaPrvtKey Cluster.initbAccount.ownerPrivateKey=initbPrvtKey + self.staging=staging def setChainStrategy(self, chainSyncStrategy=Utils.SyncReplayTag): self.__chainSyncStrategy=self.__chainSyncStrategies.get(chainSyncStrategy) @@ -1108,6 +1169,8 @@ class Cluster(object): cmd="%s -p %s -n %s -s %s -d %s" % ( Utils.EosLauncherPath, pnodes, total_nodes, topo, delay) cmdArr=cmd.split() + if self.staging: + cmdArr.append("--nogen") if not self.walletd or self.enableMongo: if Utils.amINoon: cmdArr.append("--eosiod") @@ -1185,8 +1248,11 @@ class Cluster(object): # If a last transaction exists wait for it on root node, then collect its head block number. # Wait on this block number on each cluster node - def waitOnClusterSync(self, timeout=60): + def waitOnClusterSync(self, timeout=None): + if timeout is None: + timeout=Utils.systemWaitTimeout startTime=time.time() + Utils.Debug and Utils.Print("cmd: remaining time %d seconds" % (timeout)) if self.nodes[0].alive is False: Utils.Print("ERROR: Root node is down.") return False; @@ -1205,9 +1271,12 @@ class Cluster(object): currentTimeout=timeout-(time.time()-startTime) return self.waitOnClusterBlockNumSync(targetHeadBlockNum, currentTimeout) - def waitOnClusterBlockNumSync(self, targetHeadBlockNum, timeout=60): + def waitOnClusterBlockNumSync(self, targetHeadBlockNum, timeout=None): + if timeout is None: + timeout=Utils.systemWaitTimeout startTime=time.time() remainingTime=timeout + Utils.Debug and Utils.Print("cmd: remaining time %d seconds" % (remainingTime)) while time.time()-startTime < timeout: synced=True for node in self.nodes: @@ -1221,6 +1290,7 @@ class Cluster(object): #Utils.Debug and Utils.Print("Brief pause to allow nodes to catch up.") sleepTime=3 if remainingTime > 3 else (3 - remainingTime) remainingTime -= sleepTime + Utils.Debug and Utils.Print("cmd: remaining time %d seconds" % (remainingTime)) time.sleep(sleepTime) return False @@ -1299,14 +1369,14 @@ class Cluster(object): for account in accounts: Utils.Print("Importing keys for account %s into wallet %s." % (account.name, wallet.name)) if not self.walletMgr.importKey(account, wallet): - Utils.errorExit("Failed to import key for account %s" % (account.name)) + Utils.Print("ERROR: Failed to import key for account %s" % (account.name)) return False self.accounts=accounts return True def getNode(self, id=0): - return self.nodes[0] + return self.nodes[id] def getNodes(self): return self.nodes @@ -1429,7 +1499,11 @@ class Cluster(object): nodes=[] try: - cmd="pgrep -a %s" % (Utils.EosServerName) + pgrepOpts="-a" + if sys.platform == "darwin": + pgrepOpts="-fl" + + cmd="pgrep %s %s" % (pgrepOpts, Utils.EosServerName) Utils.Debug and Utils.Print("cmd: %s" % (cmd)) psOut=subprocess.check_output(cmd.split()).decode("utf-8") #Utils.Print("psOut: <%s>" % psOut) @@ -1525,9 +1599,11 @@ class Cluster(object): except: pass - def waitForNextBlock(self, timeout=60): + def waitForNextBlock(self, timeout=None): + if timeout is None: + timeout=Utils.systemWaitTimeout node=self.nodes[0] - return node.waitForNextBlock() + return node.waitForNextBlock(timeout) def cleanup(self): for f in glob.glob("tn_data_*"): diff --git a/tests/tests/abi_tests.cpp b/tests/tests/abi_tests.cpp index cb16b7178124b0fa1d24b3886f7d0916e76a20eb..647a11938ea29f78911cee2384c1f8a3af13603d 100644 --- a/tests/tests/abi_tests.cpp +++ b/tests/tests/abi_tests.cpp @@ -89,11 +89,11 @@ const char* my_abi = R"=====( "name": "signature_arr", "type": "signature[]" },{ - "name": "checksum", - "type": "checksum" + "name": "checksum256", + "type": "checksum256" },{ - "name": "checksum_arr", - "type": "checksum[]" + "name": "checksum256_arr", + "type": "checksum256[]" },{ "name": "fieldname", "type": "field_name" @@ -434,7 +434,7 @@ BOOST_AUTO_TEST_CASE(generator) std::string field1; time field2; signature field3; - checksum field4; + checksum256 field4; field_name field5; fixed_string32 field6; fixed_string16 field7; @@ -491,7 +491,7 @@ BOOST_AUTO_TEST_CASE(generator) "type": "signature" },{ "name": "field4", - "type": "checksum" + "type": "checksum256" },{ "name": "field5", "type": "field_name" @@ -1288,8 +1288,8 @@ BOOST_AUTO_TEST_CASE(general) "time_arr" : ["2021-12-20T15:30","2021-12-20T15:31"], "signature" : "EOSJzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwT77X1U", "signature_arr" : ["EOSJzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwT77X1U","EOSJzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwT77X1U"], - "checksum" : "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - "checksum_arr" : ["ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad","ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"], + "checksum256" : "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + "checksum256_arr" : ["ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad","ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"], "fieldname" : "name1", "fieldname_arr" : ["name1","name2"], "fixedstring32" : "1234567890abcdef1234567890abcdef", diff --git a/tests/tests/message_buffer_tests.cpp b/tests/tests/message_buffer_tests.cpp index 83f93eb90cc4c5ff3e3f07f13f2fb22057cc2675..699f35d3cdd314640fb6c2d988ce690ee5ff2cf3 100644 --- a/tests/tests/message_buffer_tests.cpp +++ b/tests/tests/message_buffer_tests.cpp @@ -7,29 +7,6 @@ #include #include -#if BOOST_VERSION >= 106600 -namespace boost -{ - namespace asio - { - namespace detail - { - inline void* buffer_cast_helper(const mutable_buffer& b) - { - #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - if (b.size() && b.get_debug_check()) - b.get_debug_check()(); - #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - return b.data(); - } - inline size_t buffer_size_helper(const mutable_buffer& b) - { - return b.size(); - } - } - } -} -#endif namespace eosio { using namespace std; diff --git a/tests/tests/misc_tests.cpp b/tests/tests/misc_tests.cpp index f95eb3b0d3babe3be357ad7a54fda1589a24fbb4..c0f26ccb3100a425e074423f59a7056126a17c8d 100644 --- a/tests/tests/misc_tests.cpp +++ b/tests/tests/misc_tests.cpp @@ -22,26 +22,6 @@ using namespace std; BOOST_AUTO_TEST_SUITE(misc_tests) -/// Test processing of unbalanced strings -BOOST_AUTO_TEST_CASE(json_from_string_test) -{ - bool exc_found = false; - try { - auto val = fc::json::from_string("{\"}"); - } catch(...) { - exc_found = true; - } - BOOST_CHECK_EQUAL(exc_found, true); - - exc_found = false; - try { - auto val = fc::json::from_string("{\"block_num_or_id\":5"); - } catch(...) { - exc_found = true; - } - BOOST_CHECK_EQUAL(exc_found, true); -} - /// Test calculation of median values of blockchain operation properties BOOST_AUTO_TEST_CASE(median_properties_test) { try { diff --git a/tests/wasm_tests/eosio.system_tests.cpp b/tests/wasm_tests/eosio.system_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77d1ead48201c1d7faa50a373bbf410f8a064e6f --- /dev/null +++ b/tests/wasm_tests/eosio.system_tests.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include +#include + +#include + +#include + +using namespace eosio::testing; +using mvo = fc::mutable_variant_object; + +BOOST_AUTO_TEST_SUITE(eosio_system_tests) + +BOOST_FIXTURE_TEST_CASE( eosio_system_load, tester ) try { + + produce_block(); + edump((name(config::system_account_name))); + set_code(config::system_account_name, eosio_system_wast); + set_abi(config::system_account_name, eosio_system_abi); + produce_block(); + + + create_accounts( {N(dan),N(brendan)} ); + + push_action(N(eosio), N(issue), N(eosio), mvo() + ("to", "eosio") + ("quantity", "1000000.0000 EOS") + ); + push_action(N(eosio), N(transfer), N(eosio), mvo() + ("from", "eosio") + ("to", "dan") + ("quantity", "100.0000 EOS") + ("memo", "hi" ) + ); + + push_action(N(eosio), N(transfer), N(dan), mvo() + ("from", "dan") + ("to", "brendan") + ("quantity", "50.0000 EOS") + ("memo", "hi" ) + ); + + wlog( "reg producer" ); + auto regtrace = push_action(N(eosio), N(regproducer), N(dan), mvo() + ("producer", "dan") + ("producer_key", "") + ); + wdump((regtrace)); + produce_block(); + + wlog( "transfer" ); + push_action(N(eosio), N(transfer), N(dan), mvo() + ("from", "dan") + ("to", "brendan") + ("quantity", "5.0000 EOS") + ("memo", "hi" ) + ); + + /* + permission_level_weight plw{ permission_level{N(eosio),N(active)}, 1};; + set_authority( N(dan), N(active), + authority( 1, + vector({ {get_public_key(N(dan),"active"),1 } }), + vector({plw}) ) ); + */ + + + wlog( "stake vote" ); + auto trace = push_action(N(eosio), N(stakevote), N(dan), mvo() + ("voter", "dan") + ("amount", "5.0000 EOS") + ); + + wdump((trace)); + + /* + + produce_blocks(2); + create_accounts( {N(multitest)} ); + produce_blocks(2); + + set_code( N(multitest), eosio_system_test_wast ); + set_abi( N(multitest), eosio_system_test_abi ); + + + produce_blocks(1); + */ + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/wasm_tests/wasm_tests.cpp b/tests/wasm_tests/wasm_tests.cpp index e84f1da812c6ab43c911b286fa698dcad95cbff0..c954b4f4f80d1c6b9f22a09f5d78447c6c82e9ab 100644 --- a/tests/wasm_tests/wasm_tests.cpp +++ b/tests/wasm_tests/wasm_tests.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -57,32 +55,6 @@ struct provereset { FC_REFLECT_EMPTY(provereset); -constexpr uint32_t DJBH(const char* cp) -{ - uint32_t hash = 5381; - while (*cp) - hash = 33 * hash ^ (unsigned char) *cp++; - return hash; -} - -constexpr uint64_t TEST_METHOD(const char* CLASS, const char *METHOD) { - return ( (uint64_t(DJBH(CLASS))<<32) | uint32_t(DJBH(METHOD)) ); -} - - -template -struct test_api_action { - static account_name get_account() { - return N(tester); - } - - static action_name get_name() { - return action_name(NAME); - } -}; -FC_REFLECT_TEMPLATE((uint64_t T), test_api_action, BOOST_PP_SEQ_NIL); - - BOOST_AUTO_TEST_SUITE(wasm_tests) /** @@ -226,45 +198,6 @@ BOOST_FIXTURE_TEST_CASE( abi_from_variant, tester ) try { } FC_LOG_AND_RETHROW() /// prove_mem_reset -BOOST_FIXTURE_TEST_CASE( test_api_bootstrap, tester ) try { - produce_blocks(2); - - create_accounts( {N(tester)} ); - produce_block(); - - set_code(N(tester), test_api_wast); - produce_blocks(1); - - // make sure asserts function as we are predicated on them - { - signed_transaction trx; - trx.actions.emplace_back(vector{{N(tester), config::active_name}}, - test_api_action {}); - - set_tapos(trx); - trx.sign(get_private_key(N(tester), "active"), chain_id_type()); - BOOST_CHECK_EXCEPTION(push_transaction(trx), fc::assert_exception, assert_message_is("test_action::assert_false")); - produce_block(); - - BOOST_REQUIRE_EQUAL(false, chain_has_transaction(trx.id())); - } - - { - signed_transaction trx; - trx.actions.emplace_back(vector{{N(tester), config::active_name}}, - test_api_action {}); - - set_tapos(trx); - trx.sign(get_private_key(N(tester), "active"), chain_id_type()); - push_transaction(trx); - produce_block(); - - BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - const auto& receipt = get_transaction_receipt(trx.id()); - BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status); - } -} FC_LOG_AND_RETHROW() /// test_api_bootstrap - /** * Make sure WASM "start" method is used correctly */