diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml deleted file mode 100644 index 1f7c2aa82d..0000000000 --- a/.buildkite/pipeline.yml +++ /dev/null @@ -1,318 +0,0 @@ -steps: - # BUILDS - - command: | # High Sierra Build - echo "+++ :hammer: Building" && \ - echo 1 | ./build.sh && \ - echo "--- Compressing build directory :compression:" && \ - tar -pczf build.tar.gz build/ - artifact_paths: "build.tar.gz" - label: ":darwin: High Sierra Build" - agents: - role: "macos-builder" - os: "high-sierra" - timeout: 120 - - - command: | # Mojave Build - echo "+++ :hammer: Building" && \ - echo 1 | ./build.sh && \ - echo "--- Compressing build directory :compression:" && \ - tar -pczf build.tar.gz build/ - artifact_paths: "build.tar.gz" - label: ":darwin: Mojave Build" - agents: - role: "builder" - os: "mojave" - timeout: 120 - - - command: | # Ubuntu Build - echo "+++ :hammer: Building" && \ - echo 1 | ./build.sh && \ - echo "--- Compressing build directory :compression:" && \ - tar -pczf build.tar.gz build/ - artifact_paths: "build.tar.gz" - label: ":ubuntu: Ubuntu 18.04 Build" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:ubuntu18" - workdir: /data/job - timeout: 120 - - - command: | # Fedora Build - echo "+++ :hammer: Building" && \ - echo 1 | ./build.sh && \ - echo "--- Compressing build directory :compression:" && \ - tar -pczf build.tar.gz build/ - artifact_paths: "build.tar.gz" - label: ":fedora: Fedora Build" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:fedora" - workdir: /data/job - timeout: 120 - - - command: | # CentOS Build - echo "+++ :hammer: Building" && \ - echo 1 | ./build.sh && \ - echo "--- Compressing build directory :compression:" && \ - tar -pczf build.tar.gz build/ - artifact_paths: "build.tar.gz" - label: ":centos: CentOS Build" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:centos" - workdir: /data/job - timeout: 120 - - - command: | # Amazon Build - echo "+++ :hammer: Building" && \ - echo 1 | ./build.sh && \ - echo "--- Compressing build directory :compression:" && \ - tar -pczf build.tar.gz build/ - artifact_paths: "build.tar.gz" - label: ":aws: Amazon AWS Build" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:amazonlinux" - workdir: /data/job - timeout: 120 - - # UNIT TESTING - - wait - - # - command: | # High Sierra Unit Tests - # echo "--- :arrow_down: Downloading build directory" && \ - # buildkite-agent artifact download "build.tar.gz" . --step ":darwin: High Sierra Build" && \ - # tar -zxf build.tar.gz && \ - # echo "+++ :microscope: Running unit tests on macOS High Sierra" && \ - # cd build && \ - # ctest -V - # label: ":darwin: High Sierra Unit Tests" - # agents: - # role: "macos-tester" - # os: "high-sierra" - # timeout: 120 - - # - command: | # Mojave Unit Tests - # echo "--- :arrow_down: Downloading build directory" && \ - # buildkite-agent artifact download "build.tar.gz" . --step ":darwin: Mojave Build" && \ - # tar -zxf build.tar.gz && \ - # echo "+++ :microscope: Running unit tests on macOS Mojave" && \ - # cd build && \ - # ctest -V - # label: ":darwin: Mojave Unit Tests" - # agents: - # role: "tester" - # os: "mojave" - # timeout: 120 - - - command: | # Ubuntu 18.04 Unit Tests - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":ubuntu: Ubuntu 18.04 Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :microscope: Running unit tests on Ubuntu" && \ - cd build && \ - ctest -V - label: ":ubuntu: Ubuntu 18.04 Unit Tests" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:ubuntu18" - workdir: /data/job - timeout: 120 - - - command: | # Fedora Unit Tests - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":fedora: Fedora Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :microscope: Running unit tests on Fedora" && \ - cd build && \ - ctest -V - label: ":fedora: Fedora Unit Tests" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:fedora" - workdir: /data/job - timeout: 120 - - - command: | # CentOS Unit Tests - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":centos: CentOS Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :microscope: Running unit tests on CentOS" && \ - cd build && \ - ctest -V - label: ":centos: CentOS Unit Tests" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:centos" - workdir: /data/job - timeout: 120 - - - command: | # Amazon Unit Tests - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":aws: Amazon AWS Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :microscope: Running unit tests on Amazon AWS" && \ - cd build && \ - ctest -V - label: ":aws: Amazon AWS Unit Tests" - agents: - queue: "automation-large-builder-fleet" - plugins: - docker#v2.0.0: - image: "eosio/ci:amazonlinux" - workdir: /data/job - timeout: 120 - - # PACKAGE BUILDS - - wait - - - command: | # High Sierra Packaging - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":darwin: High Sierra Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :package: Starting package build" && \ - ln -s "$(pwd)" /data/job && cd /data/job/build/packages && bash generate_package.sh brew - label: ":darwin: High Sierra Package Builder" - agents: - role: "macos-builder" - os: "high-sierra" - artifact_paths: - - "build/packages/*.tar.gz" - timeout: 15 - - - command: | # Mojave Packaging - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":darwin: Mojave Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :package: Starting package build" && \ - ln -s "$(pwd)" /data/job && cd /data/job/build/packages && bash generate_package.sh brew - label: ":darwin: Mojave Package Builder" - agents: - role: "builder" - os: "mojave" - artifact_paths: - - "build/packages/*.tar.gz" - timeout: 15 - - - command: | # Ubuntu Packaging - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":ubuntu: Ubuntu 18.04 Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :package: Starting package build" && \ - cd /data/job/build/packages && bash generate_package.sh deb - label: ":ubuntu: Ubuntu 18.04 Package Builder" - agents: - queue: "automation-large-builder-fleet" - artifact_paths: - - "build/packages/*.deb" - plugins: - docker#v1.4.0: - image: "eosio/ci:ubuntu18" - workdir: /data/job - env: - OS: "ubuntu-18.04" - PKGTYPE: "deb" - timeout: 15 - - - command: | # Fedora Packaging - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":fedora: Fedora Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :package: Starting package build" && \ - yum install -y rpm-build && \ - mkdir -p /root/rpmbuild/BUILD && \ - mkdir -p /root/rpmbuild/BUILDROOT && \ - mkdir -p /root/rpmbuild/RPMS && \ - mkdir -p /root/rpmbuild/SOURCES && \ - mkdir -p /root/rpmbuild/SPECS && \ - mkdir -p /root/rpmbuild/SRPMS && \ - cd /data/job/build/packages && bash generate_package.sh rpm - label: ":fedora: Fedora Package Builder" - agents: - queue: "automation-large-builder-fleet" - artifact_paths: - - "build/packages/x86_64/*.rpm" - plugins: - docker#v1.4.0: - image: "eosio/ci:fedora" - workdir: /data/job - env: - OS: "fedora" - PKGTYPE: "rpm" - timeout: 15 - - - command: | # CentOS Packaging - echo "--- :arrow_down: Downloading build directory" && \ - buildkite-agent artifact download "build.tar.gz" . --step ":centos: CentOS Build" && \ - tar -zxf build.tar.gz && \ - echo "+++ :package: Starting package build" && \ - yum install -y rpm-build && \ - mkdir -p /root/rpmbuild/BUILD && \ - mkdir -p /root/rpmbuild/BUILDROOT && \ - mkdir -p /root/rpmbuild/RPMS && \ - mkdir -p /root/rpmbuild/SOURCES && \ - mkdir -p /root/rpmbuild/SPECS && \ - mkdir -p /root/rpmbuild/SRPMS && \ - cd /data/job/build/packages && bash generate_package.sh rpm - label: ":centos: CentOS Package Builder" - agents: - queue: "automation-large-builder-fleet" - artifact_paths: - - "build/packages/x86_64/*.rpm" - plugins: - docker#v1.4.0: - image: "eosio/ci:centos" - workdir: /data/job - env: - OS: "centos" - PKGTYPE: "rpm" - timeout: 15 - - # DOCKER BUILD - - wait - - - command: | # Docker Build - echo "--- :arrow_down: Downloading package" && \ - buildkite-agent artifact download "build/packages/*.deb" docker/dev/. --step ":ubuntu: Ubuntu 18.04 Package Builder" && \ - echo "--- :key: AUTHENTICATING GOOGLE SERVICE ACCOUNT" && \ - gcloud --quiet auth activate-service-account b1-automation-svc@b1-automation-dev.iam.gserviceaccount.com --key-file=/etc/gcp-service-account.json && \ - docker-credential-gcr configure-docker && \ - echo "--- :hammer_and_wrench: BUILDING BUILD IMAGE" && \ - cd docker/dev && \ - [[ "$BUILDKITE_TAG" != "" ]] && docker build -t eosio/cdt:latest -t eosio/cdt:$BUILDKITE_COMMIT -t eosio/cdt:$BUILDKITE_BRANCH -t eosio/cdt:$BUILDKITE_TAG . || docker build -t eosio/cdt:latest -t eosio/cdt:$BUILDKITE_COMMIT -t eosio/cdt:$BUILDKITE_BRANCH . && \ - docker tag eosio/cdt:$BUILDKITE_COMMIT gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_COMMIT && \ - docker tag eosio/cdt:$BUILDKITE_BRANCH gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_BRANCH && \ - [[ "$BUILDKITE_TAG" != "" ]] && docker tag eosio/cdt:$BUILDKITE_TAG gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_TAG || : && \ - docker tag eosio/cdt:latest gcr.io/b1-automation-dev/eosio/cdt:latest && \ - echo "--- :hand: PUSHING DOCKER IMAGES" && \ - docker push gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_COMMIT && \ - docker push gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_BRANCH && \ - [[ "$BUILDKITE_TAG" != "" ]] && docker push gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_TAG || : && \ - docker push gcr.io/b1-automation-dev/eosio/cdt:latest && \ - echo "--- :thought_balloon: TRASHING OLD IMAGES" && \ - docker rmi eosio/cdt:$BUILDKITE_COMMIT && \ - docker rmi eosio/cdt:$BUILDKITE_BRANCH && \ - [[ "$BUILDKITE_TAG" != "" ]] && docker rmi eosio/cdt:$BUILDKITE_TAG || : && \ - docker rmi eosio/cdt:latest && \ - docker rmi gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_COMMIT && \ - docker rmi gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_BRANCH && \ - [[ "$BUILDKITE_TAG" != "" ]] && docker rmi gcr.io/b1-automation-dev/eosio/cdt:$BUILDKITE_TAG || : && \ - docker rmi gcr.io/b1-automation-dev/eosio/cdt:latest - label: "Docker Build Builder" - agents: - queue: "automation-docker-builder-fleet" - timeout: 300 \ No newline at end of file diff --git a/.cicd/build.sh b/.cicd/build.sh index 19cc6bd442..0268ae9e6a 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -42,4 +42,4 @@ else # Linux eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" -fi +fi \ No newline at end of file diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 99a312a2e3..a9f896bd6c 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -208,4 +208,4 @@ steps: - "./.cicd/submodule-regression-checker.sh" agents: queue: "automation-basic-builder-fleet" - timeout: 5 + timeout: 5 \ No newline at end of file diff --git a/.cicd/submodule-regression-checker.sh b/.cicd/submodule-regression-checker.sh index 0cf02bcd84..47b4bcacc4 100755 --- a/.cicd/submodule-regression-checker.sh +++ b/.cicd/submodule-regression-checker.sh @@ -53,4 +53,4 @@ for k in "${!BASE_MAP[@]}"; do echo "$k was not in the diff; no regression detected" fi fi -done +done \ No newline at end of file diff --git a/.cicd/tests.sh b/.cicd/tests.sh index e0a68e452f..41a4537b36 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -12,8 +12,11 @@ if [[ $(uname) == 'Darwin' ]]; then # You can't use chained commands in execute cd $BUILD_DIR + set +e bash -c "$TEST" - + EXIT_STATUS=$? + cd $ROOT_DIR + else # Linux ARGS=${ARGS:-"--rm --init -v $(pwd):$MOUNTED_DIR"} @@ -29,7 +32,23 @@ else # Linux evars="$evars --env ${var%%=*}" done < "$BUILDKITE_ENV_FILE" fi - + set +e eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" - + EXIT_STATUS=$? +fi +# buildkite +if [[ "$BUILDKITE" == 'true' ]]; then + cd build + # upload artifacts + echo '+++ :arrow_up: Uploading Artifacts' + echo 'Exporting xUnit XML' + mv -f ./Testing/$(ls ./Testing/ | grep '2' | tail -n 1)/Test.xml test-results.xml + echo 'Uploading artifacts' + buildkite-agent artifact upload test-results.xml + echo 'Done uploading artifacts.' +fi +# re-throw +if [[ "$EXIT_STATUS" != 0 ]]; then + echo "Failing due to non-zero exit status from ctest: $EXIT_STATUS" + exit $EXIT_STATUS fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index 30aee9d425..3febf9557f 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,10 @@ # Build build/* + +# Python +__pycache__/ +.mypy_cache/ + +# Editor Files +.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index ab579c9eb3..81e9583759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,16 @@ cmake_minimum_required(VERSION 3.5) + +# Sanity check our source directory to make sure that we are not trying to +# generate an in-source build, and to make +# sure that we don't have any stray generated files lying around in the tree +if( CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + message(FATAL_ERROR "In-source builds are not allowed. +Please create a directory and run cmake from there, passing the path +to this source directory as the last argument. +This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. +Please delete them.") +endif() + project(eosio_cdt) find_program(SCCACHE_FOUND sccache) @@ -15,9 +27,9 @@ endif() set(VERSION_MAJOR 1) -set(VERSION_MINOR 6) -set(VERSION_PATCH 3) -#set(VERSION_SUFFIX rc2) +set(VERSION_MINOR 7) +set(VERSION_PATCH 0) +#set(VERSION_SUFFIX rc1) if (VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/README.md b/README.md index d5ba5eca1a..9ff4c63570 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,80 @@ # EOSIO.CDT (Contract Development Toolkit) -## Version : 1.6.3 +## Version : 1.7.0 -EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate contract writing for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are not available or incomplete. +EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. + +### New Introductions +As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to facilitate smart contract writers in crafting their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. ### Attention -EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the **_Differences between Version 1.2.x and Version 1.3.x_** section of this readme. +- Please see the [Upgrading Guide 1.2 to 1.3](https://eosio.github.io/eosio.cdt/latest/upgrading/1.2-to-1.3) and [Upgrading Guide 1.5 to 1.6](https://eosio.github.io/eosio.cdt/latest/upgrading/1.5-to-1.6) to be aware of any breaking changes. +- There is currently a known issue that a minimum of 2 CPU cores is required for using EOSIO.CDT -### Binary Releases +## Binary Releases EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. -**If you have previously installed EOSIO.CDT, please run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** +**If you have previously installed EOSIO.CDT, run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** + +### Mac OS X Brew Install +```sh +brew tap eosio/eosio.cdt +brew install eosio.cdt +``` -#### Mac OS X Brew Install +### Mac OS X Brew Uninstall ```sh -$ brew tap eosio/eosio.cdt -$ brew install eosio.cdt +brew remove eosio.cdt ``` -#### Mac OS X Brew Uninstall +### Debian Package Install ```sh -$ brew remove eosio.cdt +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb +$ sudo apt install ./eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb ``` -#### Debian Package Install +### Debian Package Uninstall ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb -$ sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +sudo apt remove eosio.cdt ``` -#### Debian Package Uninstall +### RPM Package Install ```sh -$ sudo apt remove eosio.cdt +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt-1.7.0-1.el7.x86_64.rpm +$ sudo yum install ./eosio.cdt-1.7.0-1.el7.x86_64.rpm ``` -#### RPM Package Install +### RPM Package Uninstall ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm -$ sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm +sudo yum remove eosio.cdt ``` -#### RPM Package Uninstall +## Guided Installation or Building from Scratch ```sh -$ sudo yum remove eosio.cdt +git clone --recursive https://github.com/eosio/eosio.cdt +cd eosio.cdt +mkdir build +cd build +cmake .. +make -j8 ``` -### Guided Installation (Building from Scratch) +From here onward you can build your contracts code by simply exporting the `build` directory to your path, so you don't have to install globally (makes things cleaner). +Or you can install globally by running this command: + ```sh -$ git clone --recursive https://github.com/eosio/eosio.cdt -$ cd eosio.cdt -$ ./build.sh -$ sudo ./install.sh +sudo make install ``` -### Installed Tools ---- +### Uninstall after manual installation + +```sh +sudo rm -fr /usr/local/eosio.cdt +sudo rm -fr /usr/local/lib/cmake/eosio.cdt +sudo rm /usr/local/bin/eosio-* +``` + +## Installed Tools + * eosio-cpp * eosio-cc * eosio-ld @@ -66,15 +87,22 @@ $ sudo ./install.sh * eosio-objdump * eosio-readelf +Below tools are not installed after brew install, you get them only by building the repository and installing from scracth, [see here](#guided_installation_or_building_from_scratch) +eosio-abidiff +eosio-ranlib +eosio-ar +eosio-objdump +eosio-readelf + ## Contributing -[Contributing Guide](./CONTRIBUTING.md) +[Contributing Guide](../CONTRIBUTING.md) -[Code of Conduct](./CONTRIBUTING.md#conduct) +[Code of Conduct](../CONTRIBUTING.md#conduct) ## License -[MIT](./LICENSE) +[MIT](../LICENSE) ## Important diff --git a/build.sh b/build.sh deleted file mode 100755 index 00a111daa9..0000000000 --- a/build.sh +++ /dev/null @@ -1,120 +0,0 @@ -#! /bin/bash - -printf "\t=========== Building eosio.cdt ===========\n\n" - -RED='\033[0;31m' -NC='\033[0m' -txtbld=$(tput bold) -bldred=${txtbld}$(tput setaf 1) -txtrst=$(tput sgr0) - -export DISK_MIN=10 -export TEMP_DIR="/tmp" -TEMP_DIR='/tmp' -DISK_MIN=10 - -# Use current directory's tmp directory if noexec is enabled for /tmp -if (mount | grep "/tmp " | grep --quiet noexec); then - mkdir -p $SOURCE_DIR/tmp - TEMP_DIR="${SOURCE_DIR}/tmp" - rm -rf $SOURCE_DIR/tmp/* -else # noexec wasn't found - TEMP_DIR="/tmp" -fi - -unamestr=`uname` -if [[ "${unamestr}" == 'Darwin' ]]; then - BOOST=/usr/local - CXX_COMPILER=g++ - export ARCH="Darwin" - bash ./scripts/eosio_build_darwin.sh -else - OS_NAME=$( cat /etc/os-release | grep ^NAME | cut -d'=' -f2 | sed 's/\"//gI' ) - - case "$OS_NAME" in - "Amazon Linux AMI") - export ARCH="Amazon Linux AMI" - bash ./scripts/eosio_build_amazon.sh - ;; - "CentOS Linux") - export ARCH="Centos" - export CMAKE=${HOME}/opt/cmake/bin/cmake - bash ./scripts/eosio_build_centos.sh - ;; - "elementary OS") - export ARCH="elementary OS" - bash ./scripts/eosio_build_ubuntu.sh - ;; - "Fedora") - export ARCH="Fedora" - bash ./scripts/eosio_build_fedora.sh - ;; - "Linux Mint") - export ARCH="Linux Mint" - bash ./scripts/eosio_build_ubuntu.sh - ;; - "Ubuntu") - export ARCH="Ubuntu" - bash ./scripts/eosio_build_ubuntu.sh - ;; - "Debian GNU/Linux") - export ARCH="Debian" - bash ./scripts/eosio_build_ubuntu.sh - ;; - *) - printf "\\n\\tUnsupported Linux Distribution. Exiting now.\\n\\n" - exit 1 - esac -fi - -if [[ `uname` == 'Darwin' ]]; then - FREE_MEM=`vm_stat | grep "Pages free:"` - read -ra FREE_MEM <<< "$FREE_MEM" - FREE_MEM=$((${FREE_MEM[2]%?}*(4096))) # free pages * page size -else - FREE_MEM=`LC_ALL=C free | grep "Mem:" | awk '{print $4}'` -fi - -CORES_AVAIL=`getconf _NPROCESSORS_ONLN` -MEM_CORES=$(( ${FREE_MEM}/4000000 )) # 4 gigabytes per core -MEM_CORES=$(( $MEM_CORES > 0 ? $MEM_CORES : 1 )) -CORES=$(( $CORES_AVAIL < $MEM_CORES ? $CORES_AVAIL : $MEM_CORES )) - -#check submodules -if [ $(( $(git submodule status --recursive | grep -c "^[+\-]") )) -gt 0 ]; then - printf "\\n\\tgit submodules are not up to date.\\n" - printf "\\tPlease run the command 'git submodule update --init --recursive'.\\n" - exit 1 -fi - -mkdir -p build -pushd build &> /dev/null - -if [ -z "$CMAKE" ]; then - CMAKE=$( command -v cmake ) -fi - -"$CMAKE" ../ -if [ $? -ne 0 ]; then - exit -1; -fi -make -j${CORES} -if [ $? -ne 0 ]; then - exit -1; -fi -popd &> /dev/null - -printf "\n${bldred}\t ___ ___ ___ ___\n" -printf "\t / /\\ / /\\ / /\\ ___ / /\\ \n" -printf "\t / /:/_ / /::\\ / /:/_ / /\\ / /::\\ \n" -printf "\t / /:/ /\\ / /:/\\:\\ / /:/ /\\ / /:/ / /:/\\:\\ \n" -printf "\t / /:/ /:/_ / /:/ \\:\\ / /:/ /::\\ /__/::\\ / /:/ \\:\\ \n" -printf "\t /__/:/ /:/ /\\ /__/:/ \\__\\:\\ /__/:/ /:/\\:\\ \\__\\/\\:\\__ /__/:/ \\__\\:\\ \n" -printf "\t \\ \\:\\/:/ /:/ \\ \\:\\ / /:/ \\ \\:\\/:/~/:/ \\ \\:\\/\\ \\ \\:\\ / /:/ \n" -printf "\t \\ \\::/ /:/ \\ \\:\\ /:/ \\ \\::/ /:/ \\__\\::/ \\ \\:\\ /:/ \n" -printf "\t \\ \\:\\/:/ \\ \\:\\/:/ \\__\\/ /:/ /__/:/ \\ \\:\\/:/ \n" -printf "\t \\ \\::/ \\ \\::/ /__/:/ \\__\\/ \\ \\::/ \n" -printf "\t \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n${txtrst}" - -printf "\\tFor more information:\\n" -printf "\\tEOSIO website: https://eos.io\\n" diff --git a/docs.json b/docs.json new file mode 100644 index 0000000000..28259a4389 --- /dev/null +++ b/docs.json @@ -0,0 +1,32 @@ +{ + "name": "eosio.cdt", + "generators": [ + { + "name": "collate_markdown", + "options": { + "docs_dir": "docs", + "disable_default_filters": true, + "filters": [ + { "name": "sort" }, + { "name": "remove_extension" }, + { "name": "sanitize", "options": { "exclude": ["command-reference/eosio-*.md"] } }, + { "name": "capitalize", "options": { "exclude": ["command-reference/eosio-*.md"] } } + ] + } + }, + { + "name": "doxygen_to_xml", + "options": { + "INPUT": "libraries/eosiolib", + "EXCLUDE": "libraries/eosiolib/memory.h libraries/eosiolib/memory.hpp libraries/eosiolib/action.h libraries/eosiolib/permission.h libraries/eosiolib/privileged.h libraries/eosiolib/print.h libraries/eosiolib/system.h", + "EXCLUDE_PATTERNS": "*.cpp *.c *.h" + }, + "disable_default_filters": true, + "filters": [] + }, + { + "name": "doxybook", + "options": {} + } + ] +} diff --git a/docs/02_installation.md b/docs/02_installation.md new file mode 100644 index 0000000000..88952be309 --- /dev/null +++ b/docs/02_installation.md @@ -0,0 +1,92 @@ +--- +content_title: Binary Releases +--- + +EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. + +**If you have previously installed EOSIO.CDT, run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** + +## Mac OS X Brew Install +```sh +$ brew tap eosio/eosio.cdt +$ brew install eosio.cdt +``` + +## Mac OS X Brew Uninstall +```sh +$ brew remove eosio.cdt +``` + +## Debian Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +$ sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +``` + +## Debian Package Uninstall +```sh +$ sudo apt remove eosio.cdt +``` + +## RPM Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm +$ sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm +``` + +## RPM Package Uninstall +```sh +$ sudo yum remove eosio.cdt +``` + +# Guided Installation or Building from Scratch +```sh +$ git clone --recursive https://github.com/eosio/eosio.cdt +$ cd eosio.cdt +$ mkdir build +$ cd build +$ cmake .. +$ make -j8 +``` + +From here onward you can build your contracts code by simply exporting the `build` directory to your path, so you don't have to install globally (makes things cleaner). +Or you can install globally by running this command + +```sh +sudo make install +``` + +## Uninstall after manual installation + +```sh +$ sudo rm -fr /usr/local/eosio.cdt +$ sudo rm -fr /usr/local/lib/cmake/eosio.cdt +$ sudo rm /usr/local/bin/eosio-* +``` + + +# Installed Tools + +* eosio-cpp +* eosio-cc +* eosio-ld +* eosio-init +* eosio-abidiff +* eosio-wasm2wast +* eosio-wast2wasm +* eosio-ranlib +* eosio-ar +* eosio-objdump +* eosio-readelf + +Below tools are not installed after brew install, you get them only by building the repository and installing from scracth, [see here](#guided_installation_or_building_from_scratch) +eosio-abidiff +eosio-ranlib +eosio-ar +eosio-objdump +eosio-readelf + + +License + +[MIT](../LICENSE) diff --git a/docs/tools/eosio-abidiff.md b/docs/03_command-reference/eosio-abidiff.md similarity index 82% rename from docs/tools/eosio-abidiff.md rename to docs/03_command-reference/eosio-abidiff.md index bcb93ac8f9..eb41f9ad45 100644 --- a/docs/tools/eosio-abidiff.md +++ b/docs/03_command-reference/eosio-abidiff.md @@ -1,6 +1,8 @@ -# eosio-abidiff +--- +content_title: eosio-abidiff tool +--- -Tool to diff two ABI files to flag and output differences. +The eosio-abidiff tool is used to diff two ABI files to flag and output differences. To report differences with ```eosio-abidiff```, you only need to pass the two ABI file names as command line arguments. Example: @@ -9,7 +11,7 @@ $ eosio-abidiff hello.abi old_hello.abi ``` This will generate dump the report output to the console. ---- + ``` OVERVIEW: eosio-abidiff USAGE: eosio-abidiff [options] ... ... diff --git a/docs/tools/eosio-abigen.md b/docs/03_command-reference/eosio-abigen.md similarity index 90% rename from docs/tools/eosio-abigen.md rename to docs/03_command-reference/eosio-abigen.md index 0855b94e4f..50b3a3a692 100644 --- a/docs/tools/eosio-abigen.md +++ b/docs/03_command-reference/eosio-abigen.md @@ -1,5 +1,9 @@ -# eosio-abigen -### This tool is deprecated, please use `eosio-cpp` for generation of your ABIs +--- +content_title: eosio-abigen tool +--- + +## This tool is deprecated, use `eosio-cpp` for generation of your ABIs + To generate an ABI with ```eosio-abigen```, only requires that you give the main '.cpp' file to compile and the output filename `--output` and generating against the contract name `--contract`. Example: @@ -9,7 +13,7 @@ $ eosio-abigen hello.cpp --contract=hello --output=hello.abi This will generate one file: * The generated ABI file (hello.abi) ---- + ``` USAGE: eosio-abigen [options] [... ] diff --git a/docs/03_command-reference/eosio-cc.md b/docs/03_command-reference/eosio-cc.md new file mode 100644 index 0000000000..11b08050d3 --- /dev/null +++ b/docs/03_command-reference/eosio-cc.md @@ -0,0 +1,74 @@ +--- +content_title: eosio-cc tool +--- + +To manually compile the source code, use `eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. + +``` +USAGE: eosio-cc [options] ... + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program + +compiler options: + + -C - Include comments in preprocessed output + -CC - Include comments from within macros in preprocessed output + -D= - Define to (or 1 if omitted) + -E - Only run the preprocessor + -I= - Add directory to include search path + -L= - Add directory to library search path + -MD - Write depfile containing user and system headers + -MF= - Write depfile output + -MMD - Write depfile containing user + -MT= - Specify name of main file output in depfile + -O= - Optimization level s, 0-3 + -R= - Add a resource path for inclusion + -S - Only run preprocess and compilation steps + -U= - Undefine macro + -W= - Enable the specified warning + -abigen - Generate ABI + -abigen_output= - ABIGEN output + -c - Only run preprocess, compile, and assemble steps + -contract= - Contract name + -dD - Print macro definitions in -E mode in addition to normal output + -dI - Print include directives in -E mode in addition to normal output + -dM - Print macro definitions in -E mode instead to normal output + -emit-ast - Emit Clang AST files for source inputs + -emit-llvm - Use the LLVM representation for assembler and object files + -fasm - Assemble file for x86-64 + -fcolor-diagnostics - Use colors in diagnostics + -finline-functions - Inline suitable functions + -finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline + -fmerge-all-constants - Allow merging of constants + -fnative - Compile and link for x86-64 + -fno-cfl-aa - Disable CFL Alias Analysis + -fno-elide-constructors - Disable C++ copy constructor elision + -fno-lto - Disable LTO + -fno-post-pass - Don't run post processing pass + -fno-stack-first - Don't set the stack first in memory + -fquery - Produce binaries for wasmql + -fquery-client - Produce binaries for wasmql + -fquery-server - Produce binaries for wasmql + -fstack-protector - Enable stack protectors for functions potentially vulnerable to stack smashing + -fstack-protector-all - Force the usage of stack protectors for all functions + -fstack-protector-strong - Use a strong heuristic to apply stack protectors to functions + -fstrict-enums - Enable optimizations based on the strict definition of an enum's value range + -fstrict-return - Always treat control flow paths that fall off the end of a non-void function as unreachable + -fstrict-vtable-pointers - Enable optimizations based on the strict rules for overwriting polymorphic C++ objects + -fuse-main - Use main as entry + -include= - Include file before parsing + -isystem= - Add directory to SYSTEM include search path + -l= - Root name of library to link + -lto-opt= - LTO Optimization level (O0-O3) + -o= - Write output to + -stack-size= - Specifies the maximum stack size for the contract. Defaults to 8192 bytes. + -sysroot= - Set the system root directory + -v - Show commands to run and use verbose output + -w - Suppress all warnings +``` diff --git a/docs/tools/eosio-cpp.md b/docs/03_command-reference/eosio-cpp.md similarity index 95% rename from docs/tools/eosio-cpp.md rename to docs/03_command-reference/eosio-cpp.md index 2cde5b53df..27b9053abd 100644 --- a/docs/tools/eosio-cpp.md +++ b/docs/03_command-reference/eosio-cpp.md @@ -1,9 +1,9 @@ -### Usage --- -To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. - -###$ eosio-cpp +content_title: eosio-cpp tool --- + +To manually compile the source code, use `eosio-cpp` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. + ``` USAGE: eosio-cpp [options] ... diff --git a/docs/tools/eosio-init.md b/docs/03_command-reference/eosio-init.md similarity index 96% rename from docs/tools/eosio-init.md rename to docs/03_command-reference/eosio-init.md index f721ba33b4..2f83eb4333 100644 --- a/docs/tools/eosio-init.md +++ b/docs/03_command-reference/eosio-init.md @@ -1,4 +1,6 @@ -# eosio-init +--- +content_title: eosio-init tool +--- This tool is used to generate a skeleton smart contract and directory structure. To generate a new smart contract project you can either generate a "bare" project (no CMake) or the default is to generate a CMake project. @@ -9,7 +11,7 @@ $ eosio-abigen hello.cpp --contract=hello --output=hello.abi This will generate one file: * The generated ABI file (hello.abi) ---- + ``` USAGE: eosio-init [options] diff --git a/docs/tools/eosio-ld.md b/docs/03_command-reference/eosio-ld.md similarity index 88% rename from docs/tools/eosio-ld.md rename to docs/03_command-reference/eosio-ld.md index 87f368e834..21b28fe974 100644 --- a/docs/tools/eosio-ld.md +++ b/docs/03_command-reference/eosio-ld.md @@ -1,5 +1,10 @@ -### eosio-ld --- +content_title: eosio-ld tool +--- + +The eosio-ld tool is a the custom web assembly linker for EOSIO platform smart contracts. + + ``` USAGE: eosio-ld [options] ... diff --git a/docs/upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md similarity index 87% rename from docs/upgrading/1.2-to-1.3.md rename to docs/04_upgrading/1.2-to-1.3.md index d76ef1f15e..840c22b6b0 100644 --- a/docs/upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -1,6 +1,8 @@ -## Version 1.3 +--- +content_title: Version 1.3 +--- -### eosiolib C API +## eosiolib C API - Removed the following typedefs to `uint64_t`: - `account_name` - `permission_name` @@ -22,7 +24,7 @@ - `signature` -> `capi_signature` - Removed the non-existent intrinsics declarations `require_write_lock` and `require_read_lock`. -### eosiolib C++ API +## eosiolib C++ API - Removed eosiolib/vector.hpp: - Removed alias `eosio::vector` and typedef `bytes`. - Going forward contract writers should include `` from the STL and use `std::vector` instead of bytes. @@ -31,14 +33,14 @@ - Removed eosiolib/core_symbol.hpp. The contract writer should explicitly specify the symbol. - Added eosiolib/name.hpp. -#### eosiolib/types.hpp +### eosiolib/types.hpp - Moved the typedef `eosio::extensions_types` to eosiolib/transaction.hpp. - Removed comparison functions for `checksum` structs. - Removal of `eosio::char_to_symbol`, `eosio::string_to_name`, `eosio::name_suffix` functions - Removal of the `N` macro. The `""_n` operator or the `name` constructor should be used as a type safe replacement. Example: `N(foo)` -> `"foo"_n`, or `N(foo)` -> `name("foo")`. - Moved `eosio::name` struct definition and `""_n` operator to eosiolib/name.hpp. -#### eosiolib/name.hpp +### eosiolib/name.hpp - Removed implicit and explicit conversions to `uint64_t`. - Added `enum class` `eosio::name::raw` which is implicitly converted from an `eosio::name` (used for template non-type parameters). - Added `bool` conversion operator for conditionally testing if a name is empty. @@ -46,7 +48,7 @@ - Added `constexpr` methods `eosio::name::length` and `eosio::name::suffix`. - Added equivalence, inverted equivalence and less than operators to `eosio::name`. -#### eosiolib/symbol.hpp +### eosiolib/symbol.hpp - Removed `eosio::symbol_type` struct and replaced with `eosio::symbol` class. - Added struct `eosio::symbol_code`: - Added two `constexpr` constructors that take either a raw `uint64_t` or an `std::string_view`. @@ -65,41 +67,41 @@ - Added `constexpr` methods `get_symbol` and `get_contract`. - Made existing comparison operators `constexpr`. -#### eosiolib/asset.hpp +### eosiolib/asset.hpp - The main constructor now requires a `int64_t` (quantity) and `eosio::symbol` explicitly. - The default constructor no longer initializes the instance to a valid zero quantity asset with a symbol equivalent to "core symbol". Instead the default constructed `eosio::asset` is a bit representation of all zeros (which will cause `is_valid` to fail) so that check is bypassed to allow for `multi_index` and `datastream` to work. - Old contracts that use `eosio::asset()` should be changed to either use the core symbol of the specific chain they are targeting i.e. `eosio::asset(0, symbol(symbol_code("SYS"),4))`. To reduce writing `symbol(symbol_code("SYS"),4)` over and over, a `constexpr` function to return the symbol or `constexpr` global variable should be used. -#### eosiolib/contract.hpp +### eosiolib/contract.hpp - The constructor for `eosio::contract` now takes an `eosio::name` for the receiver, an `eosio::name` for the code, and a `eosio::datastream` for the datastream used for the contract. The last argument is for manually unpacking an action, see the section on `eosio::ignore` for a more indepth usage. -#### eosiolib/dispatcher.hpp +### eosiolib/dispatcher.hpp - Renamed the macro `EOSIO_ABI` to `EOSIO_DISPATCH` as this is more descriptive of what this macro actually does. - Modified the definition of `EOSIO_DISPATCH` to work with the new constructor for `eosio::contract`. -#### eosiolib/multi_index.hpp +### eosiolib/multi_index.hpp - The first template parameter for `indexed_by` now requires the argument be convertible to `eosio::name::raw` (replacing `uint64_t`). - The first template parameter for `multi_index` now requires the argument be convertible to `eosio::name::raw` (replacing `uint64_t`). - The constructor now takes an `eosio::name` type for the code (replacing `uint64_t`). Scope is still `uint64_t`. - Various other replacements of `uint64_t` to `eosio::name`. -#### eosiolib/singleton.hpp +### eosiolib/singleton.hpp - The first template parameter for `eosio::singleton` now requires the argument be convertible to `eosio::name::raw` (replacing `uint64_t`). - The constructor now takes an `eosio::name` type for the code. - In the methods `get_or_create` and `set`, the argument `bill_to_account` is now of type `eosio::name` (replacing `uint64_t`). -#### eosiolib/action.hpp +### eosiolib/action.hpp - Added C++ function `eosio::require_auth`. - Added C++ function `eosio::has_auth`. - Added C++ function `eosio::is_account`. - Redefined `eosio::permission_level` to use `eosio::name` in place of `uint64_t`. - Removed the macro `ACTION`. (The identifier `ACTION` has been reused for another macro described below in the Macros section.) -#### eosiolib/permission.hpp +### eosiolib/permission.hpp - The optional provided_keys argument of the function `eosio::check_transaction_authorization` is now of the type `std::set` rather than the type `std::set`. C++ contract code should most likely be using the `eosio::public_key` struct (defined in "eosiolib/public_key.hpp") if they need to deal with EOSIO-compatible public keys rather than the `capi_public_key` struct (now renamed from its original name of `::public_key`) from the eosiolib C API. Note that existing contract code that just referred to the type `public_key` without namespace qualification may have accidentally been using the `capi_public_key` struct and therefore should ideally be modified to use the `eosio::public_key` C++ type. - The `account` and `permission` arguments of `eosio::check_permission_authorization` are both `eosio::name` now instead of `uint64_t`. -#### eosiolib/ignore.hpp +### eosiolib/ignore.hpp - Added new type `ignore`: - This type acts as a placeholder for actions that don't want to deserialize their fields but want the types to be reflected in the ABI. ``` @@ -108,25 +110,25 @@ - Added new type `ignore_wrapper`: - This allows for calling `SEND_INLINE_ACTION` with `ignore_wrapper(some_value)` against an action with an `ignore` of matching types. -### Macros +## Macros - Added `ACTION` macro which is simply a shortcut for `[[eosio::action]] void`. - Added `TABLE` macro which is simply a shortcut for `struct [[eosio::table]]`. - Added `CONTRACT` macro which is simply a shortcut for `class [[eosio::contract]]`. -### CMake +## CMake - Added `eosio.cdt-config.cmake` to allow for `find_package(eosio.cdt)`. See eosio.cdt/examples/hello or eosio.cdt/examples/template for an example. - Added new macro `add_contract`. This new contract takes a contract name, cmake target, then any normal arguments you would give to `add_executable`. See eosio.cdt/examples/hello or eosio.cdt/examples/template. - New version checking mechanism is included. See eosio.contracts/CMakeLists.txt to see this in use. -### libc +## libc - Replaced `printf`, `sprintf`, and `snprintf` with new minimal variants. This allows contracts to use these functions without causing stack overflow issues. -### libcxx +## libcxx - Removed `sstream` with the intent to return this after more has been done. - Added `__cxa_pure_virtual` to allow for pure virtual methods in contract classes. - `std::to_string` now works without the issues of stack overflows. -### attributes +## attributes - Added `[[eosio::ignore]]` attribute to flag a type as being ignored by the deserializer. This attribute is primarily only used for internal use within eosiolib. - Added `[[eosio::contract]]` attribute. This new attribute is used to mark a contract class as "contract" with the name being either the C++ name of the class or a user specified name (i.e. `[[eosio::contract("somecontract")]]`). This attribute can also be used in conjunction with the `eosio::action` and `eosio::table` attributes for tables that you would like to define outside of the `eosio::contract` class. This is used in conjunction with either the raw `eosio-cpp` option `--contract `, `-o .wasm` or with CMake `add_contract`. It acts as a filter enabling contract developers to include a header file with attributes from another contract (e.g. eosio.token) while generating an ABI devoid of those actions and tables. ```c++ @@ -153,13 +155,13 @@ ``` The above code will produce the tables `testtaba` and `testtabb` in your ABI. Example: `eosio-cpp -abigen test.cpp -o test.wasm` will mark this compilation and ABI generation for the `eosio::contract` `test`. The same thing can be done with `eosio-cpp -abigen test.cpp -o test_contract.wasm --contract test` or with the CMake command `add_contract( test, test_contract, test.cpp )`. Either of the previous two approaches will produce a test_contract.wasm and test_contract.abi generated under the context of the contract name of `test`. -### Boost +## Boost - Boost is now part of the library. No more external dependence on Boost and all system inclusion are within it's `sysroot`. (Boost will be removed in a future release.) -## ABI generator attributes +# ABI generator attributes Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. -#### [[eosio::action]] +### [[eosio::action]] This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation): ```c++ @@ -203,24 +205,23 @@ typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; ``` If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. -For an example contract of ABI generation please see the file ./examples/abigen_test/test.cpp. You can generate the ABI for this file with `eosio-abigen test.cpp --output=test.abi`. +For an example contract of ABI generation see the file ./examples/abigen_test/test.cpp. You can generate the ABI for this file with `eosio-abigen test.cpp --output=test.abi`. -### Fixing an ABI or Writing an ABI Manually +## Fixing an ABI or Writing an ABI Manually - The sections to the ABI are pretty simple to understand and the syntax is purely JSON, so it is reasonable to write an ABI file manually. -- The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. +- The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. -### Adding Ricardian Contracts and Clauses to ABI -- As of EOSIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. -- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - - For each Ricardian clause the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. +## Adding Ricardian Contracts and Clauses to ABI +- As of EOSIO.CDT v1.4.0, the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. +- The Ricardian contract should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. +- For each Ricardian contract, the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. +- For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. +- The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. +- For exemplification see [hello.contracts.md](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/ricardian/hello.contracts.md). License ----- -MIT +[MIT](../../LICENSE) diff --git a/docs/upgrading/1.5-to-1.6.md b/docs/04_upgrading/1.5-to-1.6.md similarity index 96% rename from docs/upgrading/1.5-to-1.6.md rename to docs/04_upgrading/1.5-to-1.6.md index c78d18a4ee..83d438fec6 100644 --- a/docs/upgrading/1.5-to-1.6.md +++ b/docs/04_upgrading/1.5-to-1.6.md @@ -1,7 +1,9 @@ -## Version 1.6 +--- +content_title: Version 1.6 +--- -### eosiolib -#### Partitioning +## eosiolib +### Partitioning In `eosio.cdt` v1.6.0, `eosiolib` will now be partitioned into 3 groups. These allow for finer grained allowance for particular modes of compilation. - CAPI - Contracts @@ -13,7 +15,7 @@ In `eosio.cdt` v1.6.0, `eosiolib` will now be partitioned into 3 groups. These a To access these new partitioned header files, use `` instead of ``. Please note that all the old header files are still available at the old `eosiolib` directory, but these are deprecated and will be removed in v1.7.0. Also, once you change one header file from `eosiolib` to `eosio` you will need to do so for all other occurrences at that point, because of some conflicts with the auto generated dispatcher. -### eosiolib C API +## eosiolib C API - `action.h` - `chain.h` - `crypto.h` @@ -27,7 +29,7 @@ To access these new partitioned header files, use `` inst This entire API is now only available to C developers (i.e. using `eosio-cc`), and all internal uses in `Core` and `Contracts` have been guarded behind the namespace `eosio::internal_use_do_not_use`. -### eosiolib Contracts API +## eosiolib Contracts API - `action.hpp` - added C++ wrappers for - `publication_time` -> `time_point publication_time()` @@ -80,7 +82,7 @@ This entire API is now only available to C developers (i.e. using `eosio-cc`), a - `expiration` - `get_context_free_data` -#### eosiolib Core API +### eosiolib Core API - `asset.hpp` - no changes - `binary_extension.hpp` @@ -119,10 +121,10 @@ This entire API is now only available to C developers (i.e. using `eosio-cc`), a - `varint.hpp` - no changes -### Auto Code Generation +## Auto Code Generation There is no more need to add the `EOSIO_DISPATCH` macro to your smart contracts. The compiler/linker will now automatically generate a dispatcher for you the proper `eosio::contract`, `eosio::action` and `eosio::on_notify` attributes are used. Of course, if you don't have these attributes then you will still need to either use the old macro or hand write the `apply` function yourself. -#### How the auto dispatcher will work +### How the auto dispatcher will work Given that you have marked your classes with the `eosio::contract` macro and any sub-contracts with the macro with the same given name (i.e. `eosio::contract("")`) then any actions and notify handlers that are contained within these will be dispatchable by your smart contract. This will allow for aggregate patterns for smart contract development and better separation of concerns. In addition to actions and notification handlers, two new "hooks" are available. @@ -138,3 +140,7 @@ If the dispatcher fails to find a suitable action to dispatch, then the new patt If the dispatcher is in notification handling mode and if your contract receives an `eosio::onerror` notification, then the contract will assert with an error code. You can circumvent this check if you explicitly supply an error handler for it ([[eosio::on_notify("eosio::onerror")]]). For a real world example of this new style of contract in use see `tests/unit/test_contracts/simple_test.cpp`. + +License + +[MIT](../../LICENSE) diff --git a/docs/05_best-practices/03_resource-planning.md b/docs/05_best-practices/03_resource-planning.md new file mode 100644 index 0000000000..4b3b70e44f --- /dev/null +++ b/docs/05_best-practices/03_resource-planning.md @@ -0,0 +1,23 @@ +--- +content_title: Resource planning +--- + +How much RAM do I need? This is not an easy question to answer, and there's really no perfect answer for it. You need to find out by measuring your contracts' actions and by planning accordingly based on your predictions on how fast and how much your blockchain application will grow. If your blockchain application growth is requiring more storage capacity you'll need to buy more RAM. If it requires more actions to be executed in the 3 day window (the staking time) you need to stake more tokens for CPU bandwidth. If your blockchain application growth means more actions will be stored on the blockchain then you also will need to expand your NET bandwidth maximum limit by staking more tokens for NET bandwidth. + +*Ok, you say, but how much?* + +You need to test and simulate various business scenarios that apply to your blockchain application and measure their resource usage. Hence, the existence of the public test networks. These allow you to measure how much RAM, CPU, and NET each action consumes, and to measure worst and best case business scenarios. You can then extrapolate and build a fairly good view of your blockchain application's resource needs. + +Once you have a fair idea of how your contract, blockchain application, and user base are consuming blockchain resources on a public test-net you can estimate what you'll need to start with on any EOSIO-based networks, public or private. From that point onward, as with any other application, it is advisable to have monitors that tell you statistics and metrics about your application performance. + +Of course some aspects might differ from network to network, because each network might have altered its system contracts. The EOSIO code base is open sourced and it can be tailored to each network's requirements. You need to be aware of these differences and take them into account if this is the case with a network you're testing on. + +The EOSIO community is also providing tools that can help you in this endeavor. One example is https://www.eosrp.io +Because the RAM price varies and because the CPU and NET bandwidth allocations vary too, as it is explained in the previous section, this tool can help you estimate how much of each resource you can allocate based on a specific amount of tokens and vice-versa. + +Another aspect of resource planning involves making sure your contract is efficient, that is, not consuming resources unnecessarily. Therefore, it is beneficial for you to find answers to the following questions when writing your own smart contracts and blockchain applications: + + * Is your smart contract storing only the information that is necessary to be stored on a blockchain and for the rest is using alternative ways for storing data (e.g. IPFS)? + * If you have multiple smart contracts, are they communicating between them too much via inline actions? Could some of the smart contracts be merged into one and thus eliminate the need to spawn inline actions between them, reducing the overall inline actions count and thus resource consumption? + * Could you change your smart contracts so that your clients pay for some parts of the RAM used? Recall how originally the addressbook contract was making each new account added to the book pay for the RAM needed to store its individual data? + * Or conversely, are you making your clients pay too much RAM or CPU in order to access your contracts' actions, to the point where you are prohibiting their use of your smart contract? Would it be better for your blockchain application's growth and success to take on some of those costs? diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md new file mode 100644 index 0000000000..5d847064a9 --- /dev/null +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -0,0 +1,43 @@ +--- +content_title: Data design and migration +--- + +EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below you will find a few possible approaches which you can consider when you design your smart contract data and its migration. + +# How to modify the structure of a multi index table + +Modifying a multi-index table structure that has already been deployed to an EOSIO-based blockchain may be done by selecting one of the different strategies outlined below, depending on your requirements: + +## 1. If you don't mind losing the existing data + +If you don't mind losing the data from the initial table you can follow these two steps: +1. Erase all records from first table +2. Deploy a new contract with modified table structure + +## 2. If you want to keep the existing data + +If you want to keep the existing data there are two ways to do it: + +### 2.1. Using binary extentions +To learn how to modify the structure using binary extensions read this [tutorial](../09_tutorials/01_binary-extension.md). + +### 2.2. Using ABI variants +To learn how to modify the structure using ABI variants read this [tutorial](../09_tutorials/02_abi-variants.md). + +### 2.3. Migrate the existing data to a second table + +#### 2.3.1. Migration without downtime, but slower + +1. Create the new version of your multi index table alongside the old one; +2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs. +3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. + +#### 2.3.2. Migration with downtime, but faster + +If you prefer less code complexity and can accept downtime for your application: + +1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a large number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a limited number of rows each time it runs; +2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. + +[[caution]] +| Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) diff --git a/docs/05_best-practices/05_securing_your_contract.md b/docs/05_best-practices/05_securing_your_contract.md new file mode 100644 index 0000000000..122e5c52d7 --- /dev/null +++ b/docs/05_best-practices/05_securing_your_contract.md @@ -0,0 +1,17 @@ +--- +content_title: Securing your contract +--- + +These are basic recommendations that should be the foundation of securing your smart contract: + +1. The master git branch has the `has_auth`, `require_auth`, `require_auth2` and `require_recipient` methods available in the EOSIO library. They can be found in detail [here](https://eosio.github.io/eosio.cdt/1.6.0-rc1/group__action.html#function-requirerecipient) and implemented [here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L144) (they end up calling the methods implemented in the `apply_context` class). + +2. Understand how each of your contracts' actions is impacting the RAM, CPU, and NET consumption, and which account ends up paying for these resources. + +3. Have a solid and comprehensive development process that includes security considerations from day one of the product planning and development. + +4. Test your smart contracts with every update announced for the blockchain you have deployed to. To ease your work, automate the testing as much as possible so you can run them often, and improve them periodically. + +5. Conduct independent smart contract audits, at least two from different organizations. + +6. Host periodic bug bounties on your smart contracts and keep a continuous commitment to reward real security problems reported at any time. \ No newline at end of file diff --git a/docs/05_best-practices/07_error_handling.md b/docs/05_best-practices/07_error_handling.md new file mode 100644 index 0000000000..549a21ce59 --- /dev/null +++ b/docs/05_best-practices/07_error_handling.md @@ -0,0 +1,19 @@ +--- +content_title: Error handling +--- + +Contracts can use `uint64_t` error codes as an alternative (and shorter) means of signaling error conditions, as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. Contract developers must be aware of the following ranges and restrictions: + +1. $0 - 4,999,999,999,999,999,999$: +Available for contract developers to assign error codes specific to their contracts. + +2. $5,000,000,000,000,000,000 - 7,999,999,999,999,999,999$: +Reserved for the EOSIO.CDT compiler to allocate as appropriate. Although the WASM code generated by the EOSIO.CDT compiler may use error code values that were automatically generated from within this range, the error codes in this range are meant to have meaning specific to the particular compiled contract (the meaning would typically be conveyed through the mapping between the error code value and strings in the associated generated ABI file). + +3. $8,000,000,000,000,000,000 - 9,999,999,999,999,999,999$: +Reserved for the EOSIO.CDT compiler to allocate as appropriate. The error codes in this range are not specific to any contract but rather are used to convey general runtime error conditions associated with the generated code by EOSIO.CDT. + +4. $10,000,000,000,000,000,000 - 18,446,744,073,709,551,615$: +Reserved for EOSIO to represent system-level error conditions. EOSIO will actually enforce this by restricting the ability for `eosio_assert_code` to be used to fail with error code values used within this range. + +Therefore, contract developers should only reserve error codes from the first range above to use in their contracts. diff --git a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md new file mode 100644 index 0000000000..cf2864d8dc --- /dev/null +++ b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md @@ -0,0 +1,94 @@ +--- +content_title: ABI/Code generator attributes explained +--- + +The new ABI generator tool uses C++11 or GNU style attributes to mark `actions` and `tables`. + +## [[eosio::action]] +This attribute marks either a struct or a method as an action. +Example (four ways to declare an action for ABI generation): +```cpp +// this is the C++11 and greater style attribute +[[eosio::action]] +void testa( name n ) { + // do something +} + +// this is the GNU style attribute, this can be used in C code and prior to C++ 11 +__attribute__((eosio_action)) +void testa( name n ){ + // do something +} + +struct [[eosio::action]] testa { + name n; + EOSLIB_SERIALIZE( testa, (n) ) +}; + +struct __attribute__((eosio_action)) testa { + name n; + EOSLIB_SERIALIZE( testa, (n) ) +}; +``` + +If your action name is not a valid [EOSIO name](https://developers.eos.io/eosio-cpp/docs/naming-conventions) you can explicitly specify the name in the attribute ```c++ [[eosio::action("")]]``` + +## [[eosio::table]] +Example (two ways to declare a table for ABI generation): +```cpp +struct [[eosio::table]] testtable { + uint64_t owner; + /* all other fields */ +}; + +struct __attribute__((eosio_table)) testtable { + uint64_t owner; + /* all other fields */ +}; + +typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; +``` + +If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. + +## [[eosio::contract("ANY_NAME_YOU_LIKE")]] +```cpp +class [[eosio::contract("ANY_NAME_YOU_LIKE")]] test_contract : public eosio::contract { +}; +``` + +The code above will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. + +## [[eosio::on_notify("VALID_EOSIO_ACCOUNT_NAME::VALID_EOSIO_ACTION_NAME")]] +```cpp +[[eosio::on_notify("eosio.token::transfer")]] +void on_token_transfer(name from, name to, assert quantity, std::string memo) { + // do something on eosio.token contract's transfer action from any account to the account where the contract is deployed. +} + +[[eosio::on_notify("*::transfer")]] +void on_any_transfer(name from, name to, assert quantity, std::string memo) { + // do something on any contract's transfer action from any account to the account where the contract is deployed. +} +``` + +## [[eosio::wasm_entry]] +```cpp +[[eosio::wasm_entry]] +void some_function(...) { + // do something +} +``` + +The code above will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. + +## [[eosio::wasm_import]] +```cpp +extern "C" { + __attribute__((eosio_wasm_import)) + void some_intrinsic(...); +} +``` + +The code above will mark a function declaration as being a WebAssembly import. This allows for other compilation modes to specify which functions are import only (i.e. do not link) without having to maintain a secondary file with duplicate declarations. + diff --git a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md new file mode 100644 index 0000000000..c97a45726a --- /dev/null +++ b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md @@ -0,0 +1,14 @@ +--- +content_title: Manually write, or fix, an ABI file +--- + +- Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. +- Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. + +## Adding Ricardian Contracts and Clauses to ABI +- The ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. +- The Ricardian contracts should be housed in a file with the name `.contracts.md` and the clauses should be in a file named `.clauses.md`. + - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. + - For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. + - The option `-R` has been added to [`eosio-cpp`](../../03_command-reference/eosio-cpp.md) and [`eosio-abigen`](../../03_command-reference/eosio-abigen.md) to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. + - For exemplification see [hello.contracts.md](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/ricardian/hello.contracts.md). diff --git a/docs/05_best-practices/09_deferred_transactions.md b/docs/05_best-practices/09_deferred_transactions.md new file mode 100644 index 0000000000..63ca63c2aa --- /dev/null +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -0,0 +1,10 @@ +--- +content_title: Deferred transactions +--- + +Deferred communication conceptually takes the form of action notifications sent to a peer transaction. Deferred actions get scheduled to run, at best, at a later time, at the producer's discretion. There is no guarantee that a deferred action will be executed. + +As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction. + +[[warning | Warning about deferred transaction usage]] +| Because of the above, it is not recommended to use `deferred transactions`. There is consideration to deprecate deferred transactions in a future version. diff --git a/docs/guides/native-tester.md b/docs/05_best-practices/10_native-tester-compilation.md similarity index 75% rename from docs/guides/native-tester.md rename to docs/05_best-practices/10_native-tester-compilation.md index b52e450f74..c1dc48e348 100644 --- a/docs/guides/native-tester.md +++ b/docs/05_best-practices/10_native-tester-compilation.md @@ -1,7 +1,10 @@ -## Native Tester/Compilation -As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. `eosio-cc\cpp` and `eosio-ld` now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) +--- +content_title: How to use native tester/compilation +--- -#### Getting Started +As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. [`eosio-cc`](../03_command-reference/eosio-cc.md), [`eosio-cpp`](../03_command-reference/eosio-cpp.md) and [`eosio-ld`](../03_command-reference/eosio-ld.md) now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) + +## Getting Started Once you have your smart contract written then a test source file can be written. `hello.hpp` @@ -10,11 +13,11 @@ Once you have your smart contract written then a test source file can be written using namespace eosio; -CONTRACT hello : public eosio::contract { +class [[eosio::contract]] hello : public eosio::contract { public: using contract::contract; - ACTION hi( name user ); + [[eosio::action]] void hi( name user ); // accessor for external contracts to easily send inline actions to your contract using hi_action = action_wrapper<"hi"_n, &hello::hi>; @@ -34,7 +37,7 @@ using namespace eosio::native; EOSIO_TEST_BEGIN(hello_test) // These can be redefined by the user to suit there needs per unit test - // the idea is that in a future release we will have a base library that + // the idea is that in a future release there will be a base library that // initializes these to "useable" default implementations and probably // helpers to more easily define read_action_data and action_data_size intrinsics // like these" @@ -88,14 +91,14 @@ int main(int argc, char** argv) { } ``` -Every `intrinsic` that is defined for eosio (prints, require_auth, etc.) is redefinable given the `intrinsics::set_intrinsics()` functions. These take a lambda whose arguments and return type should match that of the intrinsic you are trying to define. This gives the contract writer the flexibility to modify behavior to suit the unit test being written. A sister function `intrinsics::get_intrinsics()` will return the function object that currently defines the behavior for said intrinsic. This pattern can be used to mock functionality and allow for easier testing of smart contracts. For more information please see, either the `./tests` directory or `./examples/hello/tests/hello_test.cpp` for working examples. +Every `intrinsic` that is defined for eosio (prints, require_auth, etc.) is re-definable given the `intrinsics::set_intrinsics()` functions. These take a lambda whose arguments and return type should match that of the intrinsic you are trying to define. This gives the contract writer the flexibility to modify behavior to suit the unit test being written. A sister function `intrinsics::get_intrinsics()` will return the function object that currently defines the behavior for said intrinsic. This pattern can be used to mock functionality and allow for easier testing of smart contracts. For more information see, either the [tests](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/tests/) directory or [hello_test.cpp](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/tests/hello_test.cpp) for working examples. -### Compiling Native Code +## Compiling Native Code - Raw `eosio-cpp` to compile the test or program the only addition needed to the command line is to add the flag `-fnative` this will then generate native code instead of `wasm` code. - Via CMake - `add_native_library` and `add_native_executable` CMake macros have been added (these are a drop in replacement for add_library and add_executable). -### Eosio.CDT Native Tester API +## Eosio.CDT Native Tester API - CHECK_ASSERT(...) : This macro will check whether a particular assert has occured and flag the tests as failed but allow the rest of the tests to run. - This is called either by - `CHECK_ASSERT("", [](){ whatever_function(); })` diff --git a/docs/05_best-practices/11_debugging_a_smart_contract.md b/docs/05_best-practices/11_debugging_a_smart_contract.md new file mode 100644 index 0000000000..2debfd3f4b --- /dev/null +++ b/docs/05_best-practices/11_debugging_a_smart_contract.md @@ -0,0 +1,118 @@ +--- +content_title: Debugging a smart contract +--- + +In order to be able to debug your smart contract, you will need to setup a local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of a public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. + +When you are creating your smart contract for the first time, it is recommended to test and debug your smart contract on a private testnet first, since you have full control of the whole blockchain and can easily add suitable logging. This enables you to have unlimited amount of eos needed and you can just reset the state of the blockchain whenever you want. When it is ready for production, debugging on the public testnet (or official testnet) can be done by connecting your local nodeos to the public testnet (or official testnet) so you can see the log of the testnet in your local nodeos. + +The concept is the same, so for the following guide, debugging on the private testnet will be covered. + +If you haven't set up your own local nodeos, follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. + +# Method +The main method used to debug smart contract is **Caveman Debugging**. Printing is utilized to inspect the value of a variable and check the flow of the contract. Printing in smart contracts can be done through the Print API. The C++ API is a wrapper for C API and is the recommended API. + +# Print +Print C API supports the following data type that you can print: +- prints - a null terminated char array (string) +- prints_l - any char array (string) with given size +- printi - 64-bit signed integer +- printui - 64-bit unsigned integer +- printi128 - 128-bit signed integer +- printui128 - 128-bit unsigned integer +- printsf - single-precision floating point number +- printdf - double encoded as 64-bit unsigned integer +- printqf - quadruple encoded as 64-bit unsigned integer +- printn - 64 bit names as base32 encoded string +- printhex - hex given binary of data and its size + +The Print C++ API wraps some of the above C API by overriding the print() function, so the user doesn't need to determine which specific print function to use. Print C++ API supports: +- a null terminated char array (string) +- integer (128-bit unsigned, 64-bit unsigned, 32-bit unsigned, signed, unsigned) +- base32 string encoded as 64-bit unsigned integer +- struct that has print() method + +# Example +Here's an example contract for debugging + +## debug.hpp + +```cpp +namespace debug { + struct foo { + account_name from; + account_name to; + uint64_t amount; + void print() const { + eosio::print("Foo from ", eosio::name(from), " to ", eosio::name(to), " with amount ", amount, "\n"); + } + }; +} +``` +## debug.cpp + +```cpp +#include + +extern "C" { + + void apply( uint64_t code, uint64_t action ) { + if (code == N(debug)) { + eosio::print("Code is debug\n"); + if (action == N(foo)) { + eosio::print("Action is foo\n"); + debug::foo f = eosio::unpack_action_data(); + if (f.amount >= 100) { + eosio::print("Amount is larger or equal than 100\n"); + } else { + eosio::print("Amount is smaller than 100\n"); + eosio::print("Increase amount by 10\n"); + f.amount += 10; + eosio::print(f); + } + } + } + } +} // extern "C" +``` +## debug.abi + +```json +{ + "structs": [{ + "name": "foo", + "base": "", + "fields": { + "from": "account_name", + "to": "account_name", + "amount": "uint64" + } + } + ], + "actions": [{ + "action_name": "foo", + "type": "foo" + } + ] +} +``` +Deploy it and push an action to it. It is assumed you have a `debug` account created and have its key in your wallet. + +```bash +$ eosio-cpp -abigen debug.cpp -o debug.wasm +$ cleos set contract debug CONTRACT_DIR/debug -p youraccount@active +$ cleos push action debug foo '{"from":"inita", "to":"initb", "amount":10}' --scope debug +``` + +When you check your local `nodeos` node log, you will see the following lines after the above message is sent. + +``` +Code is debug +Action is foo +Amount is smaller than 100 +Increase amount by 10 +Foo from inita to initb with amount 20 +``` + +There, you can confirm that your message is going to the right control flow and the amount is updated correctly. You might see the above message at least 2 times and that's normal because each transaction is being applied during verification, block generation, and block application. \ No newline at end of file diff --git a/docs/05_best-practices/12_binary-extension.md b/docs/05_best-practices/12_binary-extension.md new file mode 100644 index 0000000000..c7783641ac --- /dev/null +++ b/docs/05_best-practices/12_binary-extension.md @@ -0,0 +1,720 @@ +--- +content_title: The eosio::binary_extension type +--- + +Let's fully explain what the `eosio::binary_extension` type is, what it does, and why we need it for contract upgrades in certain situations. + +You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in file: `eosio.cdt/libraries/eosiolib/core/eosio/binary_extension.hpp`. + +Our primary concern when using this type is when we are adding a new field to a smart contract's data structure that is currently utilized in an `eosio::multi_index` type (AKA a _table_), or when adding a new parameter to an action declaration. + +By wrapping the new field in an `eosio::binary_extension`, you are enabling your contract to be backwards compatible for future use. Note that this new field/parameter **MUST** be appended at the end of a data structure (this is due to implementation details in `eosio::multi_index`, which relies on the `boost::multi_index` type), or at the end of the parameter list in an action declaration. + +If you don't wrap the new field in an `eosio::binary_extension`, the `eosio::multi_index` table will be reformatted in such a way that disallows reads to the former datum; or in an action's case, the function will be uncallable. + +
+ +But let's see how the `eosio::binary_extension` type works with a good example. + +Take a moment to study this smart contract and its corresponding `.abi`. + +This contract not only serves as a good example to the `eosio::binary_extension` type, but can also be used as a gateway for developing smart contracts on the eosio protocol. + +**binary_extension_contract.hpp** + +```c++ +#include // eosio::contract +#include // eosio::binary_extension +#include // eosio::datastream +#include // eosio::name +#include // eosio::indexed_by, eosio::multi_index +#include // eosio::print_f + +class [[eosio::contract]] binary_extension_contract : public eosio::contract { +public: + using contract::contract; + binary_extension_contract(eosio::name receiver, eosio::name code, eosio::datastream ds) + : contract{receiver, code, ds}, _table{receiver, receiver.value} + { } + + [[eosio::action]] void regpkey (eosio::name primary_key); ///< Register primary key. + [[eosio::action]] void printbyp(eosio::name primary_key); ///< Print by primary key. + [[eosio::action]] void printbys(eosio::name secondary_key); ///< Print by secondary key. + [[eosio::action]] void modifyp (eosio::name primary_key, eosio::name n); ///< Modify primary key by primary key. + [[eosio::action]] void modifys (eosio::name primary_key, eosio::name n); ///< Modify secondary key by primary key. + + struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } + }; + + using index1 = eosio::indexed_by<"index1"_n, eosio::const_mem_fun>; + using index2 = eosio::indexed_by<"index2"_n, eosio::const_mem_fun>; + using table = eosio::multi_index<"table"_n, structure, index1, index2>; + +private: + table _table; +}; + +``` + +**binary_extension_contract.cpp** + +```c++ +#include "binary_extension_contract.hpp" + +using eosio::name; + +[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + row._secondary_key = "nothin"_n; + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::printbyp(eosio::name primary_key) { + eosio::print_f("`printbyp` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value) }; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; printing.\n", primary_key.to_string()); + eosio::print_f("{%, %}\n", iter->_primary_key, iter->_secondary_key); + } + else { + eosio::print_f("`_primary_key`: % not found; not printing.\n", primary_key.to_string()); + } + + eosio::print_f("`printbyp` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::printbys(eosio::name secondary_key) { + eosio::print_f("`printbys` executing.\n"); + + auto index{_table.get_index<"index2"_n>()}; + auto iter {index.find(secondary_key.value)}; + + if (iter != _table.get_index<"index2"_n>().end()) { + eosio::print_f("`_secondary_key`: % found; printing.\n", secondary_key.to_string()); + printbyp(iter->_primary_key); + } + else { + eosio::print_f("`_secondary_key`: % not found; not printing.\n", secondary_key.to_string()); + } + + eosio::print_f("`printbys` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::modifyp(eosio::name primary_key, name n) { + eosio::print_f("`modifyp` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value)}; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; modifying `_primary_key`.\n", primary_key.to_string()); + index.modify(iter, _self, [&](auto& row) { + row._primary_key = n; + }); + } + else { + eosio::print_f("`_primary_key`: % not found; not modifying `_primary_key`.\n", primary_key.to_string()); + } + + eosio::print_f("`modifyp` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::modifys(eosio::name primary_key, name n) { + eosio::print_f("`modifys` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value)}; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; modifying `_secondary_key`.\n", primary_key.to_string()); + index.modify(iter, _self, [&](auto& row) { + row._secondary_key = n; + }); + } + else { + eosio::print_f("`_primary_key`: % not found; not modifying `_secondary_key`.\n", primary_key.to_string()); + } + + eosio::print_f("`modifys` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** + +```javascript +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "modifyp", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "n", + "type": "name" + } + ] + }, + { + "name": "modifys", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "n", + "type": "name" + } + ] + }, + { + "name": "printbyp", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] + }, + { + "name": "printbys", + "base": "", + "fields": [ + { + "name": "secondary_key", + "type": "name" + } + ] + }, + { + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] + }, + { + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + } + ] + } + ], + "actions": [ + { + "name": "modifyp", + "type": "modifyp", + "ricardian_contract": "" + }, + { + "name": "modifys", + "type": "modifys", + "ricardian_contract": "" + }, + { + "name": "printbyp", + "type": "printbyp", + "ricardian_contract": "" + }, + { + "name": "printbys", + "type": "printbys", + "ricardian_contract": "" + }, + { + "name": "regpkey", + "type": "regpkey", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "table", + "type": "structure", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [] +} +``` + +
+ +Take note of the action `regpkey`, and the struct `structure` in `con.hpp` and `con.cpp`; the parts of the contract we will be upgrading. + +**binary_extension_contract.hpp** + +```c++ +[[eosio::action]] void regpkey (eosio::name primary_key); +``` + +```c++ +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```c++ +[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + row._secondary_key = "nothin"_n; + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +And their corresponding sections in the `.abi` files: + +**binary_extension_contract.abi** + +```javascript +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] +} +``` + +```javascript +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + } + ] +} +``` + +
+ +Now, let's start up a blockchain instance, compile this smart contract, and test it out. + +``` +~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm +``` + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: 6c5c7d869a5be67611869b5f300bc452bc57d258d11755f12ced99c7d7fe154c 4160 bytes 729 us +# eosio <= eosio::setcode "0000000000ea30550000d7600061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60067... +# eosio <= eosio::setabi "0000000000ea3055d1020e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Next, let's push some data to our contract. + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: 3c708f10dcbf4412801d901eb82687e82287c2249a29a2f4e746d0116d6795f0 104 bytes 248 us +# eosio <= eosio::regpkey {"primary_key":"eosio.name"} +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`regpkey` executing. +`_primary_key`: eosio.name not found; registering. +`regpkey` finished executing. +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Finally, let's read back the data we have just written. + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: e9b77d3cfba322a7a3a93970c0c883cb8b67e2072a26d714d46eef9d79b2f55e 104 bytes 227 us +# eosio <= eosio::printbyp {"primary_key":"eosio.name"} +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`printbyp` executing. +`_primary_key`: eosio.name found; printing. +{eosio.name, nothin} +`printbyp` finished executing. +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +
+ +Now, let's upgrade the smart contract by adding a new field to the table and a new parameter to an action while **NOT** wrapping the new field/parameter in an `eosio::binary_extension` type and see what happens: + +**binary_extension_contract.hpp** + +```diff ++[[eosio::action]] void regpkey (eosio::name primary_key, eosio::name secondary_key); +-[[eosio::action]] void regpkey (eosio::name primary_key); +``` + +```diff +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; ++ eosio::name _non_binary_extension_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```diff ++[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, name secondary_key) { +-[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; ++ if (secondary_key) { ++ row._secondary_key = secondary_key; ++ } ++ else { + row._secondary_key = "nothin"_n; ++ } + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** +```diff +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" ++ }, ++ { ++ "name": "secondary_key", ++ "type": "name" + } + ] +} +``` + +```diff +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" ++ }, ++ { ++ "name": "_non_binary_extension_key", ++ "type": "name" + } + ] +} +``` + +Next, let's upgrade the contract and try to read from our table and write to our table the original way: + +``` +~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm +``` + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: b8ea485842fa5645e61d35edd97e78858e062409efcd0a4099d69385d9bc6b3e 4408 bytes 664 us +# eosio <= eosio::setcode "0000000000ea30550000a2660061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60067... +# eosio <= eosio::setabi "0000000000ea305583030e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +Error 3050003: eosio_assert_message assertion failure +Error Details: +assertion failure with message: read +``` + +Whoops! We aren't able to read the data we've previously written to our table! + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio +``` + +``` +Error 3015014: Pack data exception +Error Details: +Missing field 'secondary_key' in input object while processing struct 'regpkey' +``` + +Whoops! We aren't able to write to our table the original way with the upgraded action either! + +
+ +Ok, let's back up and wrap the new field and the new action parameter in an `eosio::binary_extension` type: + +**binary_extension_contract.hpp** + +```diff ++[[eosio::action]] void regpkey (eosio::name primary_key. eosio::binary_extension secondary_key); +-[[eosio::action]] void regpkey (eosio::name primary_key, eosio::name secondary_key); +``` + +```diff +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; ++ eosio::binary_extension _binary_extension_key; +- eosio::name _non_binary_extension_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```diff ++[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, binary_extension secondary_key) { +-[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, name secondary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + if (secondary_key) { ++ row._secondary_key = secondary_key.value(); +- row._secondary_key = secondary_key; + } + else { + row._secondary_key = "nothin"_n; + } + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** +```diff +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "secondary_key", ++ "type": "name$" +- "type": "name" + } + ] +} +``` + +```diff +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + }, + { ++ "name": "_binary_extension_key", ++ "type": "name$" +- "name": "_non_binary_extension_key", +- "type": "name" + } + ] +} +``` + +Note the `$` after the types now; this indicates that this type is an `eosio::binary_extension` type field. +```diff +{ + "name": "secondary_key", ++ "type": "name$" +- "type": "name" +} +``` + +```diff +{ + "name": "_binary_extension_key", ++ "type": "name$" +- "type": "name" +} +``` + +Now, let's upgrade the contract again and try to read/write from/to our table: + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: 497584d4e43ec114dbef83c134570492893f49eacb555d0cd47d08ea4a3a72f7 4696 bytes 648 us +# eosio <= eosio::setcode "0000000000ea30550000cb6a0061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60017... +# eosio <= eosio::setabi "0000000000ea305581030e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: 6108f3206e1824fe3a1fdcbc2fe733f38dc07ae3d411a1ccf777ecef56ddec97 104 bytes 224 us +# eosio <= eosio::printbyp {"primary_key":"eosio.name"} +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`printbyp` executing. +`_primary_key`: eosio.name found; printing. +{eosio.name, nothin} +`printbyp` finished executing. +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio +``` + +``` +executed transaction: 75a135d1279a9c967078b0ebe337dc0cd58e1ccd07e370a899d9769391509afc 104 bytes 227 us +# eosio <= eosio::regpkey {"primary_key":"eosio.name2"} +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`regpkey` executing. +`_primary_key`: eosio.name2 not found; registering. +`regpkey` finished executing. +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Nice! The smart contract is now backwards compatible for the future use of its tables and/or actions. + +
+ +Just keep these simple rules in mind when upgrading a smart contract. +If you are adding a new field to a struct currently in use by a `eosio::multi_index` be **SURE** to: +- add the field at the end of the struct. +- wrap the type using an `eosio::binary_extension` type. diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md new file mode 100644 index 0000000000..060efe3869 --- /dev/null +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -0,0 +1,20 @@ +--- +content_title: How to compile a contract via CLI +--- + +## Preconditions +- You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` +For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) + +Follow these steps to compile your contract: + +1. Navigate to the hello folder in examples (./examples/hello), you should then see the ./src/hello.cpp file +2. Now run following commands: +```sh +$ mkdir build +$ cd build +$ eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/ +``` +3. This will generate two files: +- The compiled binary wasm, hello.wasm +- The generated ABI file, hello.abi diff --git a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md new file mode 100644 index 0000000000..22549b473c --- /dev/null +++ b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md @@ -0,0 +1,54 @@ +--- +content_title: How to configure CMake +--- + +## CMake Configuration + +### Automatic generation of CMake configuration + +To compile an EOSIO smart contract with CMake, you'll need a CMake file. To use the new `eosio-init` tool to generate the directory structure stub .hpp/.cpp files and the cmake configuration files follow these steps: + +1. cd ~ +2. eosio-init --path=. --project=test_contract +3. cd test_contract +4. cd build +5. cmake .. +6. make +7. ls -al test_contract + +At this point, you'll have the `test_contract.abi` and `test_contract.wasm` files in `~/test_contract/test_contract`. These files are ready to be deployed. + +### Manual generation of CMake configuration + +To create manually the cmake configuration, the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. + +1. In `CMakeLists.txt`: +``` +cmake_minimum_required(VERSION 3.5) +project(test_example VERSION 1.0.0) + +find_package(eosio.cdt) + +add_contract( test test test.cpp ) +``` + +2. In `test.cpp`: +``` +#include +using namespace eosio; + +class [[eosio::contract]] test : public eosio::contract { +public: + using contract::contract; + + [[eosio::action]] void testact( name test ) { + } +}; + +EOSIO_DISPATCH( test, (testact) ) +``` + +3. The following CMake macros are provided: +- `add_contract` is used to build your smart contract and generate an ABI. The first parameter is the contract name, the second is the cmake target name, and the rest are the CPP files needed to build the contract. +- `target_ricardian_directory` can be used to add the directory where your ricardian contracts live to a specific cmake target. +- `add_native_library` and `add_native_executable` are CMake macros for the native tester. They are drop in replacements for `add_library` and `add_executable`. diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md new file mode 100644 index 0000000000..54bd0814d6 --- /dev/null +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -0,0 +1,21 @@ +--- +content_title: How to compile a smart contract with CMake +--- + +## Preconditions +- You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` +For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) + +Follow these steps to compile your contract: + +1. Navigate to the hello folder in examples (./examples/hello), you should then see the ./src/hello.cpp file +2. Run following commands: +```sh +$ mkdir build +$ cd build +$ cmake .. +$ make +``` +3. This will generate two files: +- The compiled binary wasm, hello.wasm +- The generated ABI file, hello.abi diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md new file mode 100644 index 0000000000..7bf18d8491 --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -0,0 +1,77 @@ +--- +content_title: How to define a primary index +--- + +A primary key is required when defining a multi index table structure. See the following example: + +1. Include the `eosio.hpp` header and declare the `eosio` namespace usage +``` +#include +using namespace eosio; +``` +2. Define the data structure for the multi index table +```cpp + struct [[eosio::table]] test_table { + }; +``` +3. Add to the data structure the fields which define the multi index table +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { ++ // this field stores a name for each row of the multi index table ++ name test_primary; ++ // additional data stored in table row, e.g. an uint64_t type data ++ uint64_t datum; + }; +``` +4. Add the definition of the primary index for the multi index table. The primary index type must be uint64_t and must be unique +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; ++ // mandatory definition for primary key getter ++ uint64_t primary_key( ) const { return test_primary.value; } + }; +``` + +[[info | Secondary indexes information]] +| Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. + +5. For ease of use, define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + ++ typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; +``` + +Declare the multi index table as a data member of type `test_tables`, as defined above. +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; ++ test_tables testtab; +``` + +Now you have instantiated the `testtab` as a multi index table which has a primary index defined for its `test_primary` data member. + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md new file mode 100644 index 0000000000..c6a36082d5 --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -0,0 +1,92 @@ +--- +content_title: How to define a secondary index +--- + +## Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +The steps below show how to add a secondary index to the existing multi index table. + +1. Add a second field, `secondary`, to the data structure that defines the row of the table, in your case `test_table` +```diff + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; ++ name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; +``` + +2. Add `by_secondary( )` method, which is the index accessor method to the new field value added. The secondary index, that will be added in step 3, will index this new data structure field. +```diff + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } ++ uint64_t by_secondary( ) const { return secondary.value; } + }; +``` + +3. In the `test_table` alias definition (typedef), add the definition of the secondary index by making use of the `eosio::indexed_by` template. `eosio::index_by` needs two parameters: the name of the index, `"secid"_n`, and a function call operator which extracts the value from the secondary data member as an index key. The function call operator is achieved by employing the `eosio::const_mem_fun` template which receives two parameters: the data structure `test_table` and the reference to the getter function member `by_secondary`. + +```diff +- typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; ++ typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; +``` + +The full contract definition code with all the changes described above could look like this: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) + { } + + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; + + // the multi index type definition, for ease of use a type alias `test_tables` is defined, + // based on the multi_index template type, parametarized with a random name, the + // test_table data structure, and the secondary index + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; + + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md new file mode 100644 index 0000000000..b20846a9bd --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -0,0 +1,116 @@ +--- +content_title: How to define a singleton +--- + +To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`, follow the steps below: + +1. Include the `eosio.hpp` and `singleton.hpp` headers and declare the `eosio` namespace usage +``` +#include +#include +using namespace eosio; +``` + +2. Define the data structure for the multi index table +```cpp +struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; +}; +``` + +3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above +```diff +struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; +}; ++using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; +``` + +4. Define the singleton table instance declared as a data member of type `singleton_type` defined in the privious step +```diff +struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; +}; + +using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; ++singleton_type singleton_instance; +``` + +5. Instantiate the data member `singleton_instance` by passing to its constructor the `receiver` and the `code` (in this case `receiver.value`) parameters; these two combined with "testsingletona" provide access to the partition of the RAM cache used by this singleton. In this example you will initialize the `singleton_instance` data member in the smart contract constructor, see below: +```diff +// singleton contract constructor +singleton_example( name receiver, name code, datastream ds ) : + contract(receiver, code, ds), ++ singleton_instance(receiver, receiver.value) + { } +} +``` + +Now you have defined and instantiated a singleton. Below you can find a possible implementation for the full class singleton example contract. + +__singleton_example.hpp__ +```cpp +#include +#include +using namespace eosio; + +class [[eosio::contract]] singleton_example : public contract { + public: + using contract::contract; + singleton_example( name receiver, name code, datastream ds ) : + contract(receiver, code, ds), + singleton_instance(receiver, receiver.value) + { } + + [[eosio::action]] void set( name user, uint64_t value ); + [[eosio::action]] void get( ); + + struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; + } tt; + + using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; + singleton_type singleton_instance; + + using set_action = action_wrapper<"set"_n, &singleton_example::set>; + using get_action = action_wrapper<"get"_n, &singleton_example::get>; +}; +``` + +And below is a possible implementation for the two `get` and `set` actions defined above. It also demonstrates the usage of a couple of singleton methods. Note that the `set` action makes use of the singleton's `set` method, for which parameter is the account to pay for the new value stored. In this case, the same account name that is stored in the primary value is the payer. However, it can be a different account if so required. + +__singleton_example.cpp__ +```cpp +#include + +[[eosio::action]] void singleton_example::set( name user, uint64_t value ) { + if (!singleton_instance.exists()) + { + singleton_instance.get_or_create(user, tt); + } + auto entry_stored = singleton_instance.get(); + entry_stored.primary_value = user; + entry_stored.secondary_value = value; + singleton_instance.set(entry_stored, user); +} + +[[eosio::action]] void singleton_example::get( ) { + if (singleton_instance.exists()) + eosio::print( + "Value stored for: ", + name{singleton_instance.get().primary_value.value}, + " is ", + singleton_instance.get().secondary_value, + "\n"); + else + eosio::print("Singleton is empty\n"); +} +``` + + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of singleton can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/singleton_example). diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md new file mode 100644 index 0000000000..3f2fbc5050 --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -0,0 +1,33 @@ +--- +content_title: How to delete data from a multi index table +--- + +## Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +To delete data from a multi index table follow the steps below: + +1. Make use of the multi index table iterator to find out if the data exists +```cpp +[[eosio::action]] void multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); +} +``` + +2. If the data exists use the `delete` method to delete the row from table +```diff +[[eosio::action]] void multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); ++ if ( itr == testtab.end() ) { ++ printf("user does not exist in table, nothing to delete" ); ++ return; ++ } + ++ testtab.erase( itr ); +} +``` + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md new file mode 100644 index 0000000000..4a747e643e --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -0,0 +1,36 @@ +--- +content_title: How to insert data into a multi index table +--- + +## Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +To insert data into a multi index table follow the following steps + +1. Make use of the multi index table iterator to find out if the data doesn't already exist +```cpp +[[eosio::action]] void multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + +} +``` + +2. Use the `emplace` method to make the insertion if the user is not already in table +```diff +[[eosio::action]] void multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + ++ if ( itr == testtab.end() ) { ++ testtab.emplace( _self, [&]( auto& u ) { ++ u.test_primary = user; ++ u.secondary = "second"_n; ++ u.datum = 0; ++ }); ++ } +} +``` + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md new file mode 100644 index 0000000000..3a2120a6e0 --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -0,0 +1,133 @@ +--- +content_title: How to instantiate a multi index table +--- + +1. Include the `eosio.hpp` header and declare the `eosio` namespace usage +``` +#include +using namespace eosio; +``` +2. Define the data structure for the multi index table +```cpp + struct [[eosio::table]] test_table { + }; +``` +3. Add to the data structure the fields which define the multi index table +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { ++ // this field stores a name for each row of the multi index table ++ name test_primary; ++ // additional data stored in table row, e.g. an uint64_t type data ++ uint64_t datum; + }; +``` +4. Add definition of the primary index for the multi index table. The primary index type must be uint64_t, it must be unique and and it must be named `primary_key()`, if you don't have this the compiler (eosio-cpp) will generate an error saying it can't find the field to use as the primary key: +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; ++ // mandatory definition for primary key getter ++ uint64_t primary_key( ) const { return test_primary.value; } + }; +``` + +[[info | Additional indexes information]] +| Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. + +5. For ease of use, define a type alias `test_tables` based on the multi_index template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + ++ typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; +``` + +6. Define the multi index table data member of type `test_tables` defined in the privious step +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; ++ test_tables testtab; +``` + +7. Instantiate the data member `testtab` by passing to its constructor the `scope` (in this case `receiver`) and the `code` parameters, these two combined with table name `"testtaba"` provide access to the partition of the RAM cache used by this multi index table, in this example you will initialize the `testtab` data member in the smart contract constructor + +```diff +// contract class constructor +multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) ++ testtab(receiver, receiver.value) + { } +``` +Now you have instantiated the `testtab` variable as a multi index table which has a primary index defined for its `test_primary` data member. + +Here is how the definition of a `multi_index_example` contract containing a multi index table could look like after following all the steps above. + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) + { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // the multi index type definition, for ease of use define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; + + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md new file mode 100644 index 0000000000..939abbd7e8 --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -0,0 +1,175 @@ +--- +content_title: How to iterate and retrieve a multi index table based on secondary index +--- + +## Preconditions +- It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). + +You'll start with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: + +```cpp +#include +using namespace eosio; + +// multi index example contract class +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) + { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; + + // the multi index type definition, for ease of use define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name, the + // test_table data structure, and the secondary index + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; + + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary`, define a third action `bysec` which will do exactly that. + +1. In the contract definition, add the new action definition, using the `[[eosio::action]] void` and the `eosio::action_wrapper` template like this: + +```cpp + [[eosio::action]] void bysec( name secid ); + + using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; +``` + +2. In the contract implementation add the new action implementation like this: + +```cpp +// iterates the multi index table rows using the secondary index and prints the row's values +[[eosio::action]] void multi_index_example::bysec( name secid ) { + // access the secondary index + auto idx = testtab.get_index<"secid"_n>(); + // iterate through secondary index + for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { + // print each row's values + eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); + } +} +``` + +3. The full code for both the contract definition and contract implementation follow: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) + { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; + + // the multi index type definition, for ease of use define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name, the + // test_table data structure, and the secondary index + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; + + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); + [[eosio::action]] void bysec( name secid ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; + using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; +}; +``` + +__multi_index_example.cpp__ +```cpp +#include + +[[eosio::action]] void multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + + if ( itr == testtab.end() ) { + // user is not found in table, use emplace to insert a new row data structure in table + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} + +[[eosio::action]] void multi_index_example::print( name user ) { + // searches for the row that corresponds to the user parameter + auto itr = testtab.find(user.value); + + // asserts if the row was found for user parameter, if fails use the given message + check( itr != testtab.end(), "user does not exist in table" ); + + // prints the test_primary and datum fields stored for user parameter + eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); +} + +// iterates the multi index table rows using the secondary index and prints the row's values +[[eosio::action]] void multi_index_example::bysec( name secid ) { + // access the secondary index + auto idx = testtab.get_index<"secid"_n>(); + + // iterate through secondary index + for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { + // print each row's values + eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); + } +} +``` + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md new file mode 100644 index 0000000000..3654701d8a --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -0,0 +1,157 @@ +--- +content_title: How to iterate and retrieve a multi index table +--- + +## Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +For exemplification define the multi index contract definition like below: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) + { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // the multi index type definition, for ease of use define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; + + [[eosio::action]] void set( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; +}; +``` + +The steps below show how to iterate and retrieve a multi index table. + +1. Add to the above multi index example contract an action `print` which gets as parameter an acount name + +```cpp +[[eosio::action]] void print( name user ); +``` +2. For ease of use add the action wrapper defition as well +```diff +[[eosio::action]] void print( name user ); + ++using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +``` +3. Implement the action code, by searching for the `user` name in the multi index table using the primary index. If found, print out the value stored in that row for field `datum`. Otherwise asserts with a custom message. In the contract definition add the following implementation for `print` action: +```cpp + [[eosio::action]] void multi_index_example::print( name user ) { + // searches for the row that corresponds to the user parameter + auto itr = testtab.find(user.value); + + // asserts if the row was found for user parameter, if fails use the given message + check( itr != testtab.end(), "user does not exist in table" ); + + // prints the test_primary and datum fields stored for user parameter + eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); +} +``` +4. Finally the whole definition and implementation files for the contract should look like this: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) + { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // the multi index type definition, for ease of use define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; + + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +__multi_index_example.cpp__ +```cpp +#include + +[[eosio::action]] void multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + + if ( itr == testtab.end() ) { + // user is not found in table, use emplace to insert a new row data structure in table + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} + +[[eosio::action]] void multi_index_example::print( name user ) { + // searches for the row that corresponds to the user parameter + auto itr = testtab.find(user.value); + + // asserts if the row was found for user parameter, if fails use the given message + check( itr != testtab.end(), "user does not exist in table" ); + + // prints the test_primary and datum fields stored for user parameter + eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); +} +``` + +[[info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md new file mode 100644 index 0000000000..8450f39cfd --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -0,0 +1,41 @@ +--- +content_title: How to modify data in a multi index table +--- + +## Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +To modify data in the multi index table defined in the above tutorial, you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. + +1. Make use of the multi index table iterator to find out if the data exists +```cpp +[[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { + auto itr = testtab.find(user.value); +} +``` + +2. If the row you want to update is not found, then assert by using the `check` method and yield an error message +```diff +[[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { + auto itr = testtab.find(user.value); ++ check( itr != testtab.end(), "user does not exist in table" ); +} +``` + +3. If the row you want to update is found, the `check` method will do nothing and the iterator `itr` will be pointing at the row which you want to update, so then use the multi index `modify` method to make the update like below + +```diff +[[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { + // check if the user already exists + auto itr = testtab.find(user.value); + check( itr != testtab.end(), "user does not exist in table" ); + ++ testtab.modify( itr, _self, [&]( auto& row ) { ++ row.secondary = user; ++ row.datum = value; ++ }); +} +``` + +[[info | Full example location] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md new file mode 100644 index 0000000000..f717d9a960 --- /dev/null +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -0,0 +1,42 @@ +--- +content_title: How to create and use action wrappers +--- + +1. Start with a contract `multi_index_example` which has an action `mod` defined like below in file `multi_index_example.hpp`; the action modifies the integer value `n` stored for row with key `user`. +```cpp +class [[eosio::contract]] multi_index_example : public contract { + // ... + [[eosio::action]] void mod( name user, uint32_t n ); + // ... +} +``` +2. To define an action wrapper for the `mod` action, make use of the `eosio::action_wrapper` template, with the first parameter the action name as a `eosio::name` and second parameter as the reference to the action method +```diff +class [[eosio::contract]] multi_index_example : public contract { + // ... + [[eosio::action]] void mod(name user); + // ... ++ using mod_action = action_wrapper<"mod"_n, &multi_index_example::mod>; + // ... +} +``` +3. To use the action wrapper, you have to include the header file where the action wrapper is defined +```cpp +#include +``` +4. Then instantiate the `mod_action` defined above, specifying the contract to send the action to as the first argument. In this case, it is assumed the contract is deployed to `multiindexex` account, and a structure which is defined by two parameters: the self account, obtained by `get_self()` call, and the `active` permission (you can modify these two parameters based on your requirements). +```diff +#include + ++multi_index_example::mod_action modaction("multiindexex"_n, {get_self(), "active"_n}); +``` +5. And finally call the `send` method of the action wrapper and pass in the `mod` action's parameters as positional arguments +```diff +#include + +multi_index_example::mod_action modaction("multiindexex"_n, {get_self(), 1}); + ++modaction.send("eostutorial"_n, 1); +``` + +For a full example see the [`multi_index` contract implementation](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md new file mode 100644 index 0000000000..4ec1229724 --- /dev/null +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -0,0 +1,33 @@ +--- +content_title: How to restrict access to an action by a user +--- + +## Preconditions +- It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. + +To restrict access to the `hi` action, you can do it in two ways: + +1. Using require_auth +The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). + +```cpp +void hi( name user ) { + require_auth( user ); + print( "Hello, ", name{user} ); +} +``` + +2. Or using require_auth2 + +The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action and only if the permission used to sign the transaction is the 'active' one. In other words, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. + +```cpp +#include + +void hi( name user ) { + require_auth2(nm.value, "active"_n.value); + print( "Hello, ", name{user} ); +} +``` + +An example of this contract can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/src/hello.cpp) diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md new file mode 100644 index 0000000000..b41d979018 --- /dev/null +++ b/docs/08_troubleshooting.md @@ -0,0 +1,134 @@ +--- +content_title: Troubleshooting +--- + +## When sending an action to the blockchain you get the error below +```{ + "code":500, + "message":"Internal Service Error", + "error":{ + "code":3090003, + "name":"unsatisfied_authorization", + "what":"Provided keys, permissions, and delays do not satisfy declared authorizations", + "details":[ + { + "message":"transaction declares authority '{"actor":"account_name","permission":"permission_name"}', but does not have signatures for it under a provided delay of 0 ms, provided permissions [], provided keys ["EOS5ZcMvpgtDMdVtvCFewAQYTyfN6Vqhg4kdgauffx3jiaKaeWfY1"], and a delay max limit of 3888000000 ms", + "file":"authorization_manager.cpp", + "line_number":524, + "method":"check_authorization" + } + ] + } +} +``` +__Possible solution__: Verify if you did not forget to set code for contract, is it possible that you only set the `abi` for the contract but not the code as well? + +## When sending an action to the blockchain an error similar to the one below is encountered: +```sh +Error 3015014: Pack data exception +Error Details: +Unexpected input encountered while processing struct 'action_name_here' +``` +__Possible solution__: You did not specify correctly the parameter when sending the action to the blockchain. When no parameter is needed the command should look like the one below: +```sh +cleos push action eostutorial1 get '[]' -p eostutorial1@active +``` +The command above is one way of sending correctly `get` action with no parameters to the blockchain. + +## When sending an action to the blockchain an error similar to the one below is encountered: +```sh +error 2019-09-25T07:38:14.859 thread-0 main.cpp:3449 main ] Failed with error: Assert Exception (10) +!action_type.empty(): Unknown action action_name in contract eostutorial1 +``` +__Possible solution__: Verify if the action attribute `[[eosio::action]]` is used when defining and/or declaring the action `action_name` for the contract. + +## When deploying a contract code to the blockchain a similar error with the ones below is encountered: +```sh +Error 3160010: No abi file found +or +Error 3160009: No wasm file found +``` +__Possible solution__: Verify that `abi` and `wasm` files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. + +## Action triggers ram charge which cannot be initiated from a notification. + +__Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control + +## You successfully re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: +```sh +Error 3050003: eosio_assert_message assertion failure +Error Details: +assertion failure with message: singleton does not exist +pending console output: +``` +__Possible solution__: It is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. + +## You successfully re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. + +__Possible solution__: It is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. + +## You successfully re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. +```sh +error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) +Couldn't parse type_name +``` +__Possible solution__: It is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. + +## eosio-cpp process never completes. + +__Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) + +## You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. + +__Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. + +## You successfully re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: +```sh +Error 3050004: eosio_assert_code assertion failure +Error Details: +assertion failure with error code: 8000000000000000000 +``` +__Possible solution__: If you are referencing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. + +## Print statements from smart contract code are not seen in the output. + +__Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iteration will be printed, nothing else after that, nothing from the second iteration onwards either. + +The below code will print just the first line of the iteration. + +```cpp + auto index=0; + for (auto& item : testtab) + { + eosio::print_f("{item %}={%, %, %} \n", ++index, item.test_primary, item.secondary, item.datum); + } +``` + +The below code will print all lines of the iteration separated by `'|'` char. +```cpp + auto index=0; + for (auto& item : testtab) + { + eosio::print_f("{item %}={%, %, %} |", ++index, item.test_primary, item.secondary, item.datum); + } +``` + +## Print statements from smart contract code are not shown in the `expected order`. + +__Possible solution__: The key point here is the `expected order` and what you think it should be. Although the EOSIO is single threaded, when looking at your smart contract action code implementation, which let's say it has a series of `print` (either `print_f` or `printf`) statements, they might not necessarily be outputted in the order the `apparent` code workflow is. One example is when inline transactions are sent from your smart contract action code, and you expect to see the `print` statements from within the inline action code outputted before the `print` statements made after the inline action `send` statement. For better exemplification let's look at the code below: + +```cpp +[[eosio::action]] void multi_index_example::mod( name user, uint64_t n ) { + + // `mod` action implementation code goes here... + + print_f("Output line before the inline send action.") + + singleton_set_action singleton_set("eostutorial1"_n, {get_self(), "active"_n}); + singleton_set.send(get_self(), n, get_self()); + + print_f("Output line after the inline send action.") +} +``` + +The code above has one `print` statement before the `singleton_set.send` and another one after the `singleton_set.send`. If you wrote some more `print` statements in the code that implements the `singleton_set.send` action and expect to see them before the second `print` statement then it is a wrong assumption. The inline actions are broadcasted to the network and they are executed at a different time, asynchronous of the current execution thread of the current `multi_index_example::mod` action, therefor it is impossible to predict when the `print` statements from inline action code will be outputted. \ No newline at end of file diff --git a/docs/09_tutorials/01_binary-extension.md b/docs/09_tutorials/01_binary-extension.md new file mode 100644 index 0000000000..c149089790 --- /dev/null +++ b/docs/09_tutorials/01_binary-extension.md @@ -0,0 +1,789 @@ +--- +content_title: eosio::binary_extension +--- + +You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in [binary_extension.hpp](https://github.com/EOSIO/eosio.cdt/blob/master/libraries/eosiolib/binary_extension.hpp). + +The primary concern when using this type is when you are adding a new field to a smart contract's data structure that is currently utilized in an `eosio::multi_index` type (AKA a _table_), or when adding a new parameter to an action declaration. + +By wrapping the new field in an `eosio::binary_extension`, you are enabling your contract to be backwards compatible for future use. Note that this new field/parameter **MUST** be appended at the end of a data structure (this is due to implementation details in `eosio::multi_index`, which relies on the `boost::multi_index` type), or at the end of the parameter list in an action declaration. + +If you don't wrap the new field in an `eosio::binary_extension`, the `eosio::multi_index` table will be reformatted in such a way that disallows reads to the former datum; or in an action's case, the function will be un-callable. + +
How the `eosio::binary_extension` type works + +Take a moment to study this smart contract and its corresponding `.abi`. + +This contract not only serves as a good example to the `eosio::binary_extension` type, but can also be used as a gateway for developing smart contracts on the eosio protocol. + +**binary_extension_contract.hpp** + +```c++ +#include // eosio::contract +#include // eosio::binary_extension +#include // eosio::datastream +#include // eosio::name +#include // eosio::indexed_by, eosio::multi_index +#include // eosio::print_f + +class [[eosio::contract]] binary_extension_contract : public eosio::contract { +public: + using contract::contract; + binary_extension_contract(eosio::name receiver, eosio::name code, eosio::datastream ds) + : contract{receiver, code, ds}, _table{receiver, receiver.value} + { } + + [[eosio::action]] void regpkey (eosio::name primary_key); ///< Register primary key. + [[eosio::action]] void printbyp(eosio::name primary_key); ///< Print by primary key. + [[eosio::action]] void printbys(eosio::name secondary_key); ///< Print by secondary key. + [[eosio::action]] void modifyp (eosio::name primary_key, eosio::name n); ///< Modify primary key by primary key. + [[eosio::action]] void modifys (eosio::name primary_key, eosio::name n); ///< Modify secondary key by primary key. + + struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } + }; + + using index1 = eosio::indexed_by<"index1"_n, eosio::const_mem_fun>; + using index2 = eosio::indexed_by<"index2"_n, eosio::const_mem_fun>; + using table = eosio::multi_index<"table"_n, structure, index1, index2>; + +private: + table _table; +}; + +``` + +**binary_extension_contract.cpp** + +```c++ +#include "binary_extension_contract.hpp" + +using eosio::name; + +[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + row._secondary_key = "nothin"_n; + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::printbyp(eosio::name primary_key) { + eosio::print_f("`printbyp` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value) }; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; printing.\n", primary_key.to_string()); + eosio::print_f("{%, %}\n", iter->_primary_key, iter->_secondary_key); + } + else { + eosio::print_f("`_primary_key`: % not found; not printing.\n", primary_key.to_string()); + } + + eosio::print_f("`printbyp` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::printbys(eosio::name secondary_key) { + eosio::print_f("`printbys` executing.\n"); + + auto index{_table.get_index<"index2"_n>()}; + auto iter {index.find(secondary_key.value)}; + + if (iter != _table.get_index<"index2"_n>().end()) { + eosio::print_f("`_secondary_key`: % found; printing.\n", secondary_key.to_string()); + printbyp(iter->_primary_key); + } + else { + eosio::print_f("`_secondary_key`: % not found; not printing.\n", secondary_key.to_string()); + } + + eosio::print_f("`printbys` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::modifyp(eosio::name primary_key, name n) { + eosio::print_f("`modifyp` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value)}; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; modifying `_primary_key`.\n", primary_key.to_string()); + index.modify(iter, _self, [&](auto& row) { + row._primary_key = n; + }); + } + else { + eosio::print_f("`_primary_key`: % not found; not modifying `_primary_key`.\n", primary_key.to_string()); + } + + eosio::print_f("`modifyp` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::modifys(eosio::name primary_key, name n) { + eosio::print_f("`modifys` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value)}; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; modifying `_secondary_key`.\n", primary_key.to_string()); + index.modify(iter, _self, [&](auto& row) { + row._secondary_key = n; + }); + } + else { + eosio::print_f("`_primary_key`: % not found; not modifying `_secondary_key`.\n", primary_key.to_string()); + } + + eosio::print_f("`modifys` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** + +```javascript +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "modifyp", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "n", + "type": "name" + } + ] + }, + { + "name": "modifys", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "n", + "type": "name" + } + ] + }, + { + "name": "printbyp", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] + }, + { + "name": "printbys", + "base": "", + "fields": [ + { + "name": "secondary_key", + "type": "name" + } + ] + }, + { + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] + }, + { + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + } + ] + } + ], + "actions": [ + { + "name": "modifyp", + "type": "modifyp", + "ricardian_contract": "" + }, + { + "name": "modifys", + "type": "modifys", + "ricardian_contract": "" + }, + { + "name": "printbyp", + "type": "printbyp", + "ricardian_contract": "" + }, + { + "name": "printbys", + "type": "printbys", + "ricardian_contract": "" + }, + { + "name": "regpkey", + "type": "regpkey", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "table", + "type": "structure", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [] +} +``` + +
+ +Take note of the action `regpkey`, and the struct `structure` in `con.hpp` and `con.cpp`; the parts of the contract you will be upgrading. + +**binary_extension_contract.hpp** + +```c++ +[[eosio::action]] void regpkey (eosio::name primary_key); +``` + +```c++ +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```c++ +[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + row._secondary_key = "nothin"_n; + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +And their corresponding sections in the `.abi` files: + +**binary_extension_contract.abi** + +```javascript +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] +} +``` + +```javascript +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + } + ] +} +``` + +
Start up a blockchain instance, compile this smart contract, and test it out. + +``` +~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm +``` + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: 6c5c7d869a5be67611869b5f300bc452bc57d258d11755f12ced99c7d7fe154c 4160 bytes 729 us +# eosio <= eosio::setcode "0000000000ea30550000d7600061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60067... +# eosio <= eosio::setabi "0000000000ea3055d1020e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Next, push some data to the contract defined. + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: 3c708f10dcbf4412801d901eb82687e82287c2249a29a2f4e746d0116d6795f0 104 bytes 248 us +# eosio <= eosio::regpkey {"primary_key":"eosio.name"} +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`regpkey` executing. +`_primary_key`: eosio.name not found; registering. +`regpkey` finished executing. +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Finally, read back the data you have just written. + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: e9b77d3cfba322a7a3a93970c0c883cb8b67e2072a26d714d46eef9d79b2f55e 104 bytes 227 us +# eosio <= eosio::printbyp {"primary_key":"eosio.name"} +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`printbyp` executing. +`_primary_key`: eosio.name found; printing. +{eosio.name, nothin} +`printbyp` finished executing. +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +
Upgrade the smart contract by adding a new field to the table and a new parameter to an action while **NOT** wrapping the new field/parameter in an `eosio::binary_extension` type and see what happens: + +**binary_extension_contract.hpp** + +```diff ++[[eosio::action]] void regpkey (eosio::name primary_key, eosio::name secondary_key); +-[[eosio::action]] void regpkey (eosio::name primary_key); +``` + +```diff +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; ++ eosio::name _non_binary_extension_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```diff ++[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, name secondary_key) { +-[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; ++ if (secondary_key) { ++ row._secondary_key = secondary_key; ++ } ++ else { + row._secondary_key = "nothin"_n; ++ } + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** +```diff +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" ++ }, ++ { ++ "name": "secondary_key", ++ "type": "name" + } + ] +} +``` + +```diff +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" ++ }, ++ { ++ "name": "_non_binary_extension_key", ++ "type": "name" + } + ] +} +``` + +Next, upgrade the contract and try to read from table and write to table the original way: + +``` +~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm +``` + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: b8ea485842fa5645e61d35edd97e78858e062409efcd0a4099d69385d9bc6b3e 4408 bytes 664 us +# eosio <= eosio::setcode "0000000000ea30550000a2660061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60067... +# eosio <= eosio::setabi "0000000000ea305583030e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +Error 3050003: eosio_assert_message assertion failure +Error Details: +assertion failure with message: read +``` + +Whoops, you aren't able to read the data you've previously written to table. + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio +``` + +``` +Error 3015014: Pack data exception +Error Details: +Missing field 'secondary_key' in input object while processing struct 'regpkey' +``` + +Whoops, you aren't able to write to table the original way with the upgraded action either. + +
Ok, back up and wrap the new field and the new action parameter in an `eosio::binary_extension` type: + +**binary_extension_contract.hpp** + +```diff ++[[eosio::action]] void regpkey (eosio::name primary_key. eosio::binary_extension secondary_key); +-[[eosio::action]] void regpkey (eosio::name primary_key, eosio::name secondary_key); +``` + +```diff +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; ++ eosio::binary_extension _binary_extension_key; +- eosio::name _non_binary_extension_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```diff ++[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, binary_extension secondary_key) { +-[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, name secondary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + if (secondary_key) { ++ row._secondary_key = secondary_key.value(); +- row._secondary_key = secondary_key; + } + else { + row._secondary_key = "nothin"_n; + } + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** +```diff +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "secondary_key", ++ "type": "name$" +- "type": "name" + } + ] +} +``` + +```diff +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + }, + { ++ "name": "_binary_extension_key", ++ "type": "name$" +- "name": "_non_binary_extension_key", +- "type": "name" + } + ] +} +``` + +Note the `$` after the types now; this indicates that this type is an `eosio::binary_extension` type field. +```diff +{ + "name": "secondary_key", ++ "type": "name$" +- "type": "name" +} +``` + +```diff +{ + "name": "_binary_extension_key", ++ "type": "name$" +- "type": "name" +} +``` + +Now, upgrade the contract again and try to read/write from/to table: + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: 497584d4e43ec114dbef83c134570492893f49eacb555d0cd47d08ea4a3a72f7 4696 bytes 648 us +# eosio <= eosio::setcode "0000000000ea30550000cb6a0061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60017... +# eosio <= eosio::setabi "0000000000ea305581030e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: 6108f3206e1824fe3a1fdcbc2fe733f38dc07ae3d411a1ccf777ecef56ddec97 104 bytes 224 us +# eosio <= eosio::printbyp {"primary_key":"eosio.name"} +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`printbyp` executing. +`_primary_key`: eosio.name found; printing. +{eosio.name, nothin} +`printbyp` finished executing. +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio +``` + +``` +executed transaction: 75a135d1279a9c967078b0ebe337dc0cd58e1ccd07e370a899d9769391509afc 104 bytes 227 us +# eosio <= eosio::regpkey {"primary_key":"eosio.name2"} +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`regpkey` executing. +`_primary_key`: eosio.name2 not found; registering. +`regpkey` finished executing. +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Nice! The smart contract is now backwards compatible for the future use of its tables and/or actions. + +
+ +Just keep these simple rules in mind when upgrading a smart contract. +If you are adding a new field to a struct currently in use by a `eosio::multi_index` be **SURE** to: +- add the field at the end of the struct, +- and wrap the type using an `eosio::binary_extension` type. + +# There are a few restrictions you have to be aware of, and they are outlined below + +Binary extensions only operate correctly in certain locations. + +* ok: a non-embedded struct stored in a row may have binary extensions at its end +* ok: an action may use binary extensions to add additional arguments to its end +* ok: a struct with binary extensions may be used inside another struct, but only if the inner struct is the last field of the outer struct and the outer struct is allowed to contain binary extensions +* not ok: a struct with binary extensions may not be used inside an array +* not ok: a struct with binary extensions may not be used as a base of another struct +* not ok: fields with types which don't end in `$` following fields with types which do +* not ok: `$` used anywhere except in struct field types + +## ABI version string + +`eosio::abi/1.1` + +## ABI Text format + +Types may have a `$` suffix. During binary-to-json conversion, fields with a `$` type don't error out when end-of-data has been reached; instead they're omitted. During json-to-binary conversion, missing fields don't error out as long as no non-missing fields follow in the ABI. This omits the bytes from the output stream. + +e.g. + +```json + { + "name": "my_table_struct", + "base": "", + "fields": [ + { + "name": "required_field_1", + "type": "string" + }, + { + "name": "required_field_2", + "type": "float32[]" + }, + { + "name": "optional_field_3", + "type": "float32[]$" + }, + { + "name": "optional_field_4", + "type": "string$" + }, + ] + }, +``` + +## JSON representation + +Missing fields aren't included; null isn't used. E.g. all of these are valid JSON representations of `my_table_struct`: + +```json +{ + "required_field_1": "foo", + "required_field_2": [1,2,3,4] +} +``` + +```json +{ + "required_field_1": "foo", + "required_field_2": [1,2,3,4], + "optional_field_3": [5,6,7,8] +} +``` + +```json +{ + "required_field_1": "foo", + "required_field_2": [1,2,3,4], + "optional_field_3": [5,6,7,8], + "optional_field_4": "bar" +} +``` + +## ABI Binary format + +`$` can be included in type strings. No other changes. diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md new file mode 100644 index 0000000000..e20f4bb461 --- /dev/null +++ b/docs/09_tutorials/02_abi-variants.md @@ -0,0 +1,159 @@ +--- +content_title: ABI variants +--- + +ABI variants give the flexibility of using more than one type for a defined variable or data member. +In EOSIO, the variants make use of the standard template library `variant` which was introduced in C++ 17. An instance of `std::variant` at any given time either holds a value of one of its alternative types, or in the case of error - no value. Because of this trait, variants can be used to build the multi index table structure with flexibility. Used in conjunction with ABI extensions, it allows for modification of the structure of an exiting multi index table, a.k.a. table. + +## Use variant when building the multi index table the first time + +To define a `variant` for your table structure one example is shown below + +```cpp + std::variant variant_field; +``` + +This defines `variant` which can hold three different types, one at a time though. +So the contract interface could look like this: + +```diff +#include +using namespace eosio; + +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) + { } + + struct [[eosio::table]] test_table { + name test_primary; + name secondary; + uint64_t datum; ++ std::variant variant_field; + + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } ++ std::variant get_variant_field()const { ++ return std::visit( ++ [](auto&& arg) -> std::variant { ++ return arg; ++ }, ++ variant_field); + } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + test_tables testtab; + + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +Notice above the declaration of the `variant_field` data memember and also the declaration and inline implementation for the `get_variant_field()` accessor for this data member. + +In the future, this allows you the flexibility to store in the `variant_field` three different types of data `int8_t`, `int16_t`, and `int32_t`, and also allows you to add more types in the list of supported types for this field. One important thing to keep in mind is that you can only append at the end of the supported types, you can not modify the existing supported types order nor drop one of them. That means if you want in the next version of your contract to add also type `int32_t` to the supported list types for this field, your contract implementation could look like this: + +```diff +#include +using namespace eosio; + +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) + { } + + struct [[eosio::table]] test_table { + name test_primary; + name secondary; + uint64_t datum; ++ std::variant variant_field; + + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } ++ std::variant get_variant_field()const { ++ return std::visit( ++ [](auto&& arg) -> std::variant { ++ return arg; ++ }, ++ variant_field); + } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + test_tables testtab; + + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +Now you can deploy the contract and it will be backwards compatible with the previous existing multi index table. + +## Use variant when changing an already deployed multi index table + +### Preconditions +- It is assumed you deployed the contract defined in [this section](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) and now you are going to change its table structure. + +To change the existing table structure, you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: + +```cpp + eosio::binary_extension> binary_extension_variant_key; +``` + +Notice, the use of the `eosio::binary_extension` template which wraps the `std::variant` template parameterized with the types you want to support for the new data field. The full contract implementation can look like this: + +```diff +#include +#include +using namespace eosio; + +class [[eosio::contract]] multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) + { } + + struct [[eosio::table]] test_table { + name test_primary; + name secondary; + uint64_t datum; ++ eosio::binary_extension> binary_extension_variant_key; + + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } ++ eosio::binary_extension> get_binary_extension_variant_field()const { ++ return binary_extension_variant_key; ++ } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + test_tables testtab; + + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +[[warning | Not recommended warning]] +| Be aware, it is not recommend to use `eosio::binary_extension` inside variant definition, this can lead to data corruption unless one is very careful in understanding how these two templates work and how to ABI gets generated! + +[[info | Implemenatation location]] +| The implementation for ABI `variants' section can be found [here](https://github.com/EOSIO/eos/pull/5652). \ No newline at end of file diff --git a/docs/guides/cmake.md b/docs/guides/cmake.md deleted file mode 100644 index 0ab8518474..0000000000 --- a/docs/guides/cmake.md +++ /dev/null @@ -1,39 +0,0 @@ -# CMake - -## CMake Configuration -To compile an EOSIO smart contract with CMake you'll need a CMake file. The new `eosio-init` tool can be used to generate the directory structure stub .hpp/.cpp files and subsequent cmake files. Or the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. - -For example: - -In `CMakeLists.txt`: -``` -cmake_minimum_required(VERSION 3.5) -project(test_example VERSION 1.0.0) - -find_package(eosio.cdt) - -add_contract( test test test.cpp ) -``` - - -In `test.cpp`: - -``` -#include -using namespace eosio; - -CONTRACT test : public eosio::contract { -public: - using contract::contract; - - ACTION testact( name test ) { - } -}; - -EOSIO_DISPATCH( test, (testact) ) -``` - -## CMake Macros -- `add_contract` is used to build your smart contract and generate an ABI, the first parameter is the contract name, the second is the cmake target name, and the rest are the CPP files needed to build the contract. -- `target_ricardian_directory` can be used to add the directory where your ricardian contracts live to a specific cmake target. -- (new for native tester) `add_native_library` and `add_native_executable` CMake macros have been added (these are a drop in replacement for add_library and add_executable). diff --git a/docs/guides/first-smart-contract.md b/docs/guides/first-smart-contract.md deleted file mode 100644 index 8be919d63e..0000000000 --- a/docs/guides/first-smart-contract.md +++ /dev/null @@ -1,32 +0,0 @@ -### Building your first smart contract -```c++ -#include -#include - -class [[eosio::contract]] hello : public eosio::contract { - public: - using eosio::contract::contract; - - [[eosio::action]] - void hi(eosio::name nm) { - eosio::print_f("Hello, %\n", nm); - } -}; -``` - -- Navigate to the hello folder in examples (./examples/hello). -- You should then see the hello.cpp file -- Now run the compiler -```sh -$ eosio-cpp -abigen hello.cpp -o hello.wasm -``` -- Or with CMake -```sh -$ mkdir build -$ cd build -$ cmake .. -$ make -``` -This will generate two files: -* The compiled binary wasm (hello.wasm) -* The generated ABI file (hello.abi) diff --git a/docs/guides/generator-attributes.md b/docs/guides/generator-attributes.md deleted file mode 100644 index 7b0bdca566..0000000000 --- a/docs/guides/generator-attributes.md +++ /dev/null @@ -1,98 +0,0 @@ -## ABI/Code generator attributes -Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. -#### [[eosio::action]] -This attribute marks either a struct or a method as an action. -Example (four ways to declare an action for ABI generation): -```c++ -// this is the C++11 and greater style attribute -[[eosio::action]] -void testa( name n ) { - // do something -} - -// this is the GNU style attribute, this can be used in C code and prior to C++ 11 -__attribute__((eosio_action)) -void testa( name n ){ - // do something -} - -struct [[eosio::action]] testa { - name n; - EOSLIB_SERIALIZE( testa, (n) ) -}; - -struct __attribute__((eosio_action)) testa { - name n; - EOSLIB_SERIALIZE( testa, (n) ) -}; -``` -If your action name is not a valid [EOSIO name](https://developers.eos.io/eosio-cpp/docs/naming-conventions) you can explicitly specify the name in the attribute ```c++ [[eosio::action("")]]``` - -#### [[eosio::table]] -Example (two ways to declare a table for ABI generation): -``` -struct [[eosio::table]] testtable { - uint64_t owner; - /* all other fields */ -}; - -struct __attribute__((eosio_table)) testtable { - uint64_t owner; - /* all other fields */ -}; - -typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; -``` -If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. - -#### [[eosio::contract("\")]] -``` -class [[eosio::contract("")]] test_contract : public eosio::contract { -}; -``` -This will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. - -#### [[eosio::on_notify("\::\")]] -``` -[[eosio::on_notify("eosio.token::transfer")]] -void on_token_transfer(name from, name to, asset quantity, std::string memo) { - do something on transfer from eosio.token... -} - -[[eosio::on_notify("*::transfer")]] -void on_any_transfer(name from, name to, asset quantity, std::string memo) { - do something on transfer from any account... -} -``` - -#### [[eosio::wasm_entry]] -``` -[[eosio::wasm_entry]] -void some_function(...) { - do something... -} -``` - -This will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. - -#### [[eosio::wasm_import]] -``` -extern "C" { - __attribute__((eosio_wasm_import)) - void some_intrinsic(...); -} -``` - -This will mark a function declaration as being a WebAssembly import. This allows for other compilation modes to specify which functions are import only (i.e. do not link) without having to maintain a secondary file with duplicate declarations. - -### Fixing an ABI or Writing an ABI Manually -- Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. -- Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. - -### Adding Ricardian Contracts and Clauses to ABI -- As of EOSIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. -- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - - For each Ricardian clause the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..87b023e2e3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,25 @@ +# EOSIO.CDT (Contract Development Toolkit) + +## Version : 1.7.0 + +EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. + +## New Introductions +As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to assist smart contract developers in craftinng their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. + +## Upgrading +There's been a round of breaking changes, if you are upgrading please read the [Upgrade guide from 1.2 to 1.3](./04_upgrading/1.2-to-1.3.md) and [Upgrade guide from 1.5 to 1.6](./04_upgrading/1.5-to-1.6.md). + +## Contributing + +[Contributing Guide](../CONTRIBUTING.md) + +[Code of Conduct](../CONTRIBUTING.md#conduct) + +## License + +[MIT](../LICENSE) + +## Important + +See LICENSE for copyright and license terms. Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the software or any related documentation, whether expressed or implied, including but not limited to the warranties or merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, service or other resource is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate. diff --git a/examples/hello/README.txt b/examples/hello/README.txt index b200d54092..069019e07e 100644 --- a/examples/hello/README.txt +++ b/examples/hello/README.txt @@ -1,12 +1,22 @@ --- hello Project --- - - How to Build - - - cd to 'build' directory + -- How to Build with CMake and Make -- + - mkdir build + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'hello' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/hello' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/hello' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file +- Additions to cmake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to build with eosio-cpp -- + - mkdir build + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/' + + - After build - + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/hello/include/hello.hpp b/examples/hello/include/hello.hpp index a8abfc60b8..3019d18a30 100644 --- a/examples/hello/include/hello.hpp +++ b/examples/hello/include/hello.hpp @@ -1,12 +1,14 @@ #include using namespace eosio; -CONTRACT hello : public contract { +class [[eosio::contract]] hello : public contract { public: using contract::contract; - ACTION hi( name nm ); - ACTION check( name nm ); + [[eosio::action]] + void hi( name nm ); + [[eosio::action]] + void check( name nm ); using hi_action = action_wrapper<"hi"_n, &hello::hi>; using check_action = action_wrapper<"check"_n, &hello::check>; diff --git a/examples/hello/src/hello.cpp b/examples/hello/src/hello.cpp index 7b2c68387d..8c858132d7 100644 --- a/examples/hello/src/hello.cpp +++ b/examples/hello/src/hello.cpp @@ -1,9 +1,11 @@ #include -ACTION hello::hi( name nm ) { +[[eosio::action]] +void hello::hi( name nm ) { print_f("Name : %\n", nm); } -ACTION hello::check( name nm ) { +[[eosio::action]] +void hello::check( name nm ) { print_f("Name : %\n", nm); eosio::check(nm == "hello"_n, "check name not equal to `hello`"); } diff --git a/examples/multi_index_example/README.txt b/examples/multi_index_example/README.txt index 844225edaa..2f9e854dc8 100644 --- a/examples/multi_index_example/README.txt +++ b/examples/multi_index_example/README.txt @@ -1,12 +1,22 @@ --- multi_index_example Project --- - - How to Build - - - cd to 'build' directory + -- How to Build with CMake and Make -- + - mkdir build + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'multi_index_example' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/multi_index_example' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/multi_index_example' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to build with eosio-cpp -- + - mkdir build + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/multi_index_example.cpp -o multi_index_example.wasm -I ../include/' + + - After build - + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/multi_index_example/include/multi_index_example.hpp b/examples/multi_index_example/include/multi_index_example.hpp index ef4905ffea..bd08eb9a7e 100644 --- a/examples/multi_index_example/include/multi_index_example.hpp +++ b/examples/multi_index_example/include/multi_index_example.hpp @@ -1,18 +1,13 @@ #include using namespace eosio; -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), testtab(receiver, receiver.value) {} - ACTION set(name user); - ACTION print( name user ); - ACTION bysec( name secid ); - ACTION mod( name user, uint32_t n ); - - TABLE test_table { + struct [[eosio::table]] test_table { name test_primary; name secondary; uint64_t datum; @@ -22,9 +17,22 @@ CONTRACT multi_index_example : public contract { typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + test_tables testtab; + + [[eosio::action]] + void set(name user); + [[eosio::action]] + void print( name user ); + [[eosio::action]] + void bysec( name secid ); + [[eosio::action]] + void mod( name user, uint32_t n ); + [[eosio::action]] + void del( name user ); + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; using mod_action = action_wrapper<"mod"_n, &multi_index_example::mod>; - test_tables testtab; + using del_action = action_wrapper<"del"_n, &multi_index_example::del>; }; diff --git a/examples/multi_index_example/src/multi_index_example.cpp b/examples/multi_index_example/src/multi_index_example.cpp index c784f406ef..0072c3566f 100644 --- a/examples/multi_index_example/src/multi_index_example.cpp +++ b/examples/multi_index_example/src/multi_index_example.cpp @@ -1,5 +1,6 @@ #include -ACTION multi_index_example::set( name user ) { +[[eosio::action]] +void multi_index_example::set( name user ) { auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { testtab.emplace( _self, [&]( auto& u ) { @@ -10,25 +11,41 @@ ACTION multi_index_example::set( name user ) { } } -ACTION multi_index_example::print( name user ) { +[[eosio::action]] +void multi_index_example::print( name user ) { auto itr = testtab.find(user.value); - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); } -ACTION multi_index_example::bysec( name secid ) { +[[eosio::action]] +void multi_index_example::bysec( name secid ) { auto idx = testtab.get_index<"secid"_n>(); for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { print( itr->test_primary ); } } - -ACTION multi_index_example::mod( name user, uint32_t n ) { +[[eosio::action]] +void multi_index_example::mod( name user, uint32_t n ) { auto itr = testtab.find(user.value); - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); testtab.modify( itr, _self, [&]( auto& row ) { row.secondary = user; row.datum = n; }); } + +[[eosio::action]] +void multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + if ( itr == testtab.end() ) { + printf("user does not exist in table, nothing to delete" ); + return; + } + + // if we got so far it means user exists so we can delete it using + // the iterator found based on its primary key + testtab.erase( itr ); +} diff --git a/examples/send_inline/README.txt b/examples/send_inline/README.txt index cf339a7835..9f2183e211 100644 --- a/examples/send_inline/README.txt +++ b/examples/send_inline/README.txt @@ -1,12 +1,22 @@ --- send_inline Project --- - - How to Build - - - cd to 'build' directory + -- How to Build with CMake and Make -- + - mkdir build + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'send_inline' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/send_inline' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/send_inline' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to build with eosio-cpp -- + - mkdir build + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/send_inline.cpp -o send_inline.wasm -I ../include/ -I ../../hello/include/' + + - After build - + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/send_inline/include/send_inline.hpp b/examples/send_inline/include/send_inline.hpp index 7efde6e619..af99668590 100644 --- a/examples/send_inline/include/send_inline.hpp +++ b/examples/send_inline/include/send_inline.hpp @@ -1,11 +1,12 @@ #include using namespace eosio; -CONTRACT send_inline : public contract { +class [[eosio::contract]] send_inline : public contract { public: using contract::contract; - ACTION test( name user, name inline_code ); + [[eosio::action]] + void test( name user, name inline_code ); using test_action = action_wrapper<"test"_n, &send_inline::test>; }; diff --git a/examples/send_inline/src/send_inline.cpp b/examples/send_inline/src/send_inline.cpp index 058c613221..96647e0914 100644 --- a/examples/send_inline/src/send_inline.cpp +++ b/examples/send_inline/src/send_inline.cpp @@ -1,6 +1,7 @@ #include #include -ACTION send_inline::test( name user, name inline_code ) { +[[eosio::action]] +void send_inline::test( name user, name inline_code ) { print_f( "Hello % from send_inline", user ); // constructor takes two arguments (the code the contract is deployed on and the set of permissions) hello::hi_action hi(inline_code, {_self, "active"_n}); diff --git a/examples/singleton_example/CMakeLists.txt b/examples/singleton_example/CMakeLists.txt new file mode 100644 index 0000000000..cc78459a7b --- /dev/null +++ b/examples/singleton_example/CMakeLists.txt @@ -0,0 +1,17 @@ +include(ExternalProject) +# if no cdt root is given use default path +if(EOSIO_CDT_ROOT STREQUAL "" OR NOT EOSIO_CDT_ROOT) + find_package(eosio.cdt) +endif() + +ExternalProject_Add( + singleton_example_project + SOURCE_DIR ${CMAKE_SOURCE_DIR}/src + BINARY_DIR ${CMAKE_BINARY_DIR}/singleton_example + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${EOSIO_CDT_ROOT}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake + UPDATE_COMMAND "" + PATCH_COMMAND "" + TEST_COMMAND "" + INSTALL_COMMAND "" + BUILD_ALWAYS 1 +) \ No newline at end of file diff --git a/examples/singleton_example/README.txt b/examples/singleton_example/README.txt new file mode 100644 index 0000000000..8d948e46a0 --- /dev/null +++ b/examples/singleton_example/README.txt @@ -0,0 +1,20 @@ +--- singleton_example Project --- + + -- How to Build with CMake and Make -- + - cd into the 'build' directory + - run the command 'cmake ..' + - run the command 'make' + + - After build - + - The built smart contract is under the 'singleton_example' directory in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/singleton_example' directory + + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to build with eosio-cpp -- + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/singleton_example.cpp -o singleton_example.wasm -I ../include/' + + - After build - + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp new file mode 100644 index 0000000000..8b67639c62 --- /dev/null +++ b/examples/singleton_example/include/singleton_example.hpp @@ -0,0 +1,29 @@ +#include +#include +using namespace eosio; + +class [[eosio::contract]] singleton_example : public contract { + public: + using contract::contract; + singleton_example( name receiver, name code, datastream ds ) : + contract(receiver, code, ds), + singleton_instance(receiver, receiver.value) + {} + + [[eosio::action]] + void set( name user, uint64_t value ); + [[eosio::action]] + void get( ); + + struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; + uint64_t primary_key() const { return primary_value.value; } + } tt; + + using singleton_type = eosio::singleton<"testtable"_n, testtable>; + singleton_type singleton_instance; + + using set_action = action_wrapper<"set"_n, &singleton_example::set>; + using get_action = action_wrapper<"get"_n, &singleton_example::get>; +}; diff --git a/examples/singleton_example/ricardian/singleton_example.contracts.md b/examples/singleton_example/ricardian/singleton_example.contracts.md new file mode 100644 index 0000000000..5c7d6556a7 --- /dev/null +++ b/examples/singleton_example/ricardian/singleton_example.contracts.md @@ -0,0 +1,3 @@ +

hi

+ +Stub for hi action's ricardian contract \ No newline at end of file diff --git a/examples/singleton_example/src/CMakeLists.txt b/examples/singleton_example/src/CMakeLists.txt new file mode 100644 index 0000000000..8e5dbe960f --- /dev/null +++ b/examples/singleton_example/src/CMakeLists.txt @@ -0,0 +1,8 @@ +project(singleton_example) + +set(EOSIO_WASM_OLD_BEHAVIOR "Off") +find_package(eosio.cdt) + +add_contract( singleton_example singleton_example singleton_example.cpp ) +target_include_directories( singleton_example PUBLIC ${CMAKE_SOURCE_DIR}/../include ) +target_ricardian_directory( singleton_example ${CMAKE_SOURCE_DIR}/../ricardian ) \ No newline at end of file diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp new file mode 100644 index 0000000000..4e896bb25a --- /dev/null +++ b/examples/singleton_example/src/singleton_example.cpp @@ -0,0 +1,26 @@ +#include + +[[eosio::action]] +void singleton_example::set( name user, uint64_t value ) { + if (!singleton_instance.exists()) + { + singleton_instance.get_or_create(user, tt); + } + auto entry_stored = singleton_instance.get(); + entry_stored.primary_value = user; + entry_stored.secondary_value = value; + singleton_instance.set(entry_stored, user); +} + +[[eosio::action]] +void singleton_example::get( ) { + if (singleton_instance.exists()) + eosio::print( + "Value stored for: ", + name{singleton_instance.get().primary_value.value}, + " is ", + singleton_instance.get().secondary_value, + "\n"); + else + eosio::print("Singleton is empty\n"); +} diff --git a/install.sh b/install.sh deleted file mode 100755 index f19a1113bf..0000000000 --- a/install.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash -########################################################################## -# This is the EOSIO automated install script for Linux and Mac OS. -# This file was downloaded from https://github.com/EOSIO/eos -# -# Copyright (c) 2017, Respective Authors all rights reserved. -# -# After June 1, 2018 this software is available under the following terms: -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# https://github.com/EOSIO/eos/blob/master/LICENSE.txt -########################################################################## - - - CWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - if [ "${CWD}" != "${PWD}" ]; then - printf "\\n\\tPlease cd into directory %s to run this script.\\n \\tExiting now.\\n\\n" "${CWD}" - exit 1 - fi - - BUILD_DIR="${PWD}/build" - CMAKE_BUILD_TYPE=Release - TIME_BEGIN=$( date -u +%s ) - INSTALL_PREFIX="/usr/local/eosio.cdt" - VERSION=1.2 - - txtbld=$(tput bold) - bldred=${txtbld}$(tput setaf 1) - txtrst=$(tput sgr0) - - if [ ! -d "${BUILD_DIR}" ]; then - printf "\\n\\tError, build.sh has not ran. Please run ./build.sh first!\\n\\n" - exit -1 - fi - if ! pushd "${BUILD_DIR}"; then - printf "Unable to enter build directory %s.\\n Exiting now.\\n" "${BUILD_DIR}" - exit 1; - fi - if ! make install; then - printf "\\n\\t>>>>>>>>>>>>>>>>>>>> MAKE installing EOSIO has exited with the above error.\\n\\n" - exit -1 - fi - popd &> /dev/null - - printf "\n${bldred}\t ___ ___ ___ ___\n" - printf "\t / /\\ / /\\ / /\\ ___ / /\\ \n" - printf "\t / /:/_ / /::\\ / /:/_ / /\\ / /::\\ \n" - printf "\t / /:/ /\\ / /:/\\:\\ / /:/ /\\ / /:/ / /:/\\:\\ \n" - printf "\t / /:/ /:/_ / /:/ \\:\\ / /:/ /::\\ /__/::\\ / /:/ \\:\\ \n" - printf "\t /__/:/ /:/ /\\ /__/:/ \\__\\:\\ /__/:/ /:/\\:\\ \\__\\/\\:\\__ /__/:/ \\__\\:\\ \n" - printf "\t \\ \\:\\/:/ /:/ \\ \\:\\ / /:/ \\ \\:\\/:/~/:/ \\ \\:\\/\\ \\ \\:\\ / /:/ \n" - printf "\t \\ \\::/ /:/ \\ \\:\\ /:/ \\ \\::/ /:/ \\__\\::/ \\ \\:\\ /:/ \n" - printf "\t \\ \\:\\/:/ \\ \\:\\/:/ \\__\\/ /:/ /__/:/ \\ \\:\\/:/ \n" - printf "\t \\ \\::/ \\ \\::/ /__/:/ \\__\\/ \\ \\::/ \n" - printf "\t \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n${txtrst}" - - printf "\\tFor more information:\\n" - printf "\\tEOSIO website: https://eos.io\\n" diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index f4e6b33b13..0649c46049 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,3 +1,5 @@ +cmake_minimum_required(VERSION 3.5) + project(eosio_libraries) find_program(CCACHE_FOUND ccache) diff --git a/libraries/eosiolib/action.h b/libraries/eosiolib/action.h deleted file mode 100644 index 140d3a53b0..0000000000 --- a/libraries/eosiolib/action.h +++ /dev/null @@ -1,171 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "system.hpp" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -extern "C" { - /** - * @addtogroup action_c Action C API - * @ingroup c_api - * @brief Defines API for querying action and sending action - * - * - * A EOS.IO action has the following abstract structure: - * - * ``` - * struct action { - * capi_name account_name; // the contract defining the primary code to execute for code/type - * capi_name action_name; // the action to be taken - * permission_level authorization; // the accounts and permission levels provided - * bytes data; // opaque data processed by code - * }; - * ``` - * - * This API enables your contract to inspect the fields on the current action and act accordingly. - * - * Example: - * @code - * // Assume this action is used for the following examples: - * // { - * // "code": "eos", - * // "type": "transfer", - * // "authorization": [{ "account": "inita", "permission": "active" }], - * // "data": { - * // "from": "inita", - * // "to": "initb", - * // "amount": 1000 - * // } - * // } - * - * char buffer[128]; - * uint32_t total = read_action(buffer, 5); // buffer contains the content of the action up to 5 bytes - * print(total); // Output: 5 - * - * uint32_t msgsize = action_size(); - * print(msgsize); // Output: size of the above action's data field - * - - * require_recipient("initc"_n); // initc account will be notified for this action - * - * require_auth("inita"_n); // Do nothing since inita exists in the auth list - * require_auth("initb"_n); // Throws an exception - * - * print(current_time()); // Output: timestamp (in microseconds since 1970) of current block - * - * @endcode - * - * - * @{ - */ - - /** - * Copy up to length bytes of current action data to the specified location - * - * @brief Copy current action data to the specified location - * @param msg - a pointer where up to length bytes of the current action data will be copied - * @param len - len of the current action data to be copied, 0 to report required size - * @return the number of bytes copied to msg, or number of bytes that can be copied if len==0 passed - * @pre `msg` is a valid pointer to a range of memory at least `len` bytes long - * @post `msg` is filled with packed action data - */ - __attribute__((eosio_wasm_import)) - uint32_t read_action_data( void* msg, uint32_t len ); - - /** - * Get the length of the current action's data field. This method is useful for dynamically sized actions - * - * @brief Get the length of current action's data field - * @return the length of the current action's data field - */ - __attribute__((eosio_wasm_import)) - uint32_t action_data_size(); - - /** - * Add the specified account to set of accounts to be notified - * - * @brief Add the specified account to set of accounts to be notified - * @param name - name of the account to be verified - */ - __attribute__((eosio_wasm_import)) - void require_recipient( capi_name name ); - - /** - * Verifies that name exists in the set of provided auths on a action. Throws if not found. - * - * @brief Verify specified account exists in the set of provided auths - * @param name - name of the account to be verified - */ - __attribute__((eosio_wasm_import)) - void require_auth( capi_name name ); - - /** - * Verifies that name has auth. - * - * @brief Verifies that name has auth. - * @param name - name of the account to be verified - */ - __attribute__((eosio_wasm_import)) - bool has_auth( capi_name name ); - - /** - * Verifies that name exists in the set of provided auths on a action. Throws if not found. - * - * @brief Verify specified account exists in the set of provided auths - * @param name - name of the account to be verified - * @param permission - permission level to be verified - */ - __attribute__((eosio_wasm_import)) - void require_auth2( capi_name name, capi_name permission ); - - /** - * Verifies that @ref name is an existing account. - * - * @brief Verifies that @ref name is an existing account. - * @param name - name of the account to check - */ - __attribute__((eosio_wasm_import)) - bool is_account( capi_name name ); - - /** - * Send an inline action in the context of this action's parent transaction - * - * @param serialized_action - serialized action - * @param size - size of serialized action in bytes - * @pre `serialized_action` is a valid pointer to an array at least `size` bytes long - */ - __attribute__((eosio_wasm_import)) - void send_inline(char *serialized_action, size_t size); - - /** - * /function - * Send an inline context free action in the context of this action's parent transaction - * - * @param serialized_action - serialized action - * @param size - size of serialized action in bytes - * @pre `serialized_action` is a valid pointer to an array at least `size` bytes long - */ - __attribute__((eosio_wasm_import)) - void send_context_free_inline(char *serialized_action, size_t size); - - /** - * Returns the time in microseconds from 1970 of the publication_time - * @brief Get the publication time - * @return the time in microseconds from 1970 of the publication_time - */ - __attribute__((eosio_wasm_import)) - uint64_t publication_time(); - - /** - * Get the current receiver of the action - * @brief Get the current receiver of the action - * @return the account which specifies the current receiver of the action - */ - __attribute__((eosio_wasm_import)) - capi_name current_receiver(); - - /// @} action -} diff --git a/libraries/eosiolib/action.hpp b/libraries/eosiolib/action.hpp deleted file mode 100644 index be2396681a..0000000000 --- a/libraries/eosiolib/action.hpp +++ /dev/null @@ -1,503 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include - -#include "action.h" -#include "datastream.hpp" -#include "serialize.hpp" - -#include -#include -#include -#include - -#warning " is deprecated use " - -namespace eosio { - - /** - * @addtogroup action Action C++ API - * @ingroup core - * @brief Defines type-safe C++ wrapers for querying action and sending action - * - * @note There are some methods from the @ref action that can be used directly from C++ - * @{ - */ - - /** - * - * @brief Interpret the action body as type T. - * @return Unpacked action data casted as T. - * - * Example: - * - * @code - * struct dummy_action { - * char a; //1 - * unsigned long long b; //8 - * int c; //4 - * - * EOSLIB_SERIALIZE( dummy_action, (a)(b)(c) ) - * }; - * dummy_action msg = unpack_action_data(); - * @endcode - */ - - template - T unpack_action_data() { - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - return unpack( buffer, size ); - } - - /** - * Add the specified account to set of accounts to be notified - * - * @brief Add the specified account to set of accounts to be notified - * @param notify_account - name of the account to be verified - */ - inline void require_recipient( name notify_account ){ - ::require_recipient( notify_account.value ); - } - - /** - * All of the listed accounts will be added to the set of accounts to be notified - * - * This helper method enables you to add multiple accounts to accounts to be notified list with a single - * call rather than having to call the similar C API multiple times. - * - * @note action.code is also considered as part of the set of notified accounts - * - * @brief Notify an account for this action - * @param notify_account account to be notified - * @param remaining_accounts accounts to be notified - * - * Example: - * - * @code - * require_recipient("Account1"_n, "Account2"_n, "Account3"_n); // throws exception if any of them not in set. - * @endcode - */ - template - void require_recipient( name notify_account, accounts... remaining_accounts ){ - ::require_recipient( notify_account.value ); - require_recipient( remaining_accounts... ); - } - - /** - * Verifies that @ref name exists in the set of provided auths on a action. Fails if not found. - * - * @brief Verify specified account exists in the set of provided auths - * @param name - name of the account to be verified - */ - inline void require_auth( name n ) { - ::require_auth( n.value ); - } - - /** - * Packed representation of a permission level (Authorization) - * - * @brief Packed representation of a permission level (Authorization) - */ - struct permission_level { - /** - * Construct a new permission level object with actor name and permission name - * - * @brief Construct a new permission level object - * @param a - Name of the account who owns this authorization - * @param p - Name of the permission - */ - permission_level( name a, name p ):actor(a),permission(p){} - - /** - * Default Constructor - * - * @brief Construct a new permission level object - */ - permission_level(){} - - /** - * Name of the account who owns this permission - * - * @brief Name of the account who owns this permission - */ - name actor; - /** - * Name of the permission - * - * @brief Name of the permission - */ - name permission; - - /// @cond OPERATORS - - /** - * Check equality of two permissions - * - * @brief Check equality of two permissions - * @param a - first permission to compare - * @param b - second permission to compare - * @return true if equal - * @return false if unequal - */ - friend constexpr bool operator == ( const permission_level& a, const permission_level& b ) { - return std::tie( a.actor, a.permission ) == std::tie( b.actor, b.permission ); - } - - /// @endcond - - EOSLIB_SERIALIZE( permission_level, (actor)(permission) ) - }; - - /** - * Require the specified authorization for this action. If this action doesn't contain the specified auth, it will fail. - * - * @brief Require the specified authorization for this action - * - * @param level - Authorization to be required - */ - inline void require_auth( const permission_level& level ) { - ::require_auth2( level.actor.value, level.permission.value ); - } - - /** - * Verifies that @ref n has auth. - * - * @brief Verifies that @ref n has auth. - * @param n - name of the account to be verified - */ - inline bool has_auth( name n ) { - return ::has_auth( n.value ); - } - - /** - * Verifies that @ref n is an existing account. - * - * @brief Verifies that @ref n is an existing account. - * @param n - name of the account to check - */ - inline bool is_account( name n ) { - return ::is_account( n.value ); - } - - /** - * This is the packed representation of an action along with - * meta-data about the authorization levels. - * - * @brief Packed representation of an action - */ - struct action { - /** - * Name of the account the action is intended for - * - * @brief Name of the account the action is intended for - */ - name account; - - /** - * Name of the action - * - * @brief Name of the action - */ - name name; - - /** - * List of permissions that authorize this action - * - * @brief List of permissions that authorize this action - */ - std::vector authorization; - - /** - * Payload data - * - * @brief Payload data - */ - std::vector data; - - /** - * Default Constructor - * - * @brief Construct a new action object - */ - action() = default; - - /** - * Construct a new action object with the given action struct - * - * @brief Construct a new action object with the given permission, action receiver, action name, action struct - * @tparam T - Type of action struct, must be serializable by `pack(...)` - * @param auth - The permissions that authorizes this action - * @param a - The name of the account this action is intended for (action receiver) - * @param n - The name of the action - * @param value - The action struct that will be serialized via pack into data - */ - template - action( const permission_level& auth, struct name a, struct name n, T&& value ) - :account(a), name(n), authorization(1,auth), data(pack(std::forward(value))) {} - - /** - * Construct a new action object with the given action struct - * - * @brief Construct a new action object with the given list of permissions, action receiver, action name, action struct - * @tparam T - Type of action struct, must be serializable by `pack(...)` - * @param auths - The list of permissions that authorize this action - * @param a - The name of the account this action is intended for (action receiver) - * @param n - The name of the action - * @param value - The action struct that will be serialized via pack into data - */ - template - action( std::vector auths, struct name a, struct name n, T&& value ) - :account(a), name(n), authorization(std::move(auths)), data(pack(std::forward(value))) {} - - EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) ) - - /** - * Send the action as inline action - * - * @brief Send the action as inline action - */ - void send() const { - auto serialize = pack(*this); - ::send_inline(serialize.data(), serialize.size()); - } - - /** - * Send the action as inline context free action - * - * @brief Send the action as inline context free action - * @pre This action should not contain any authorizations - */ - void send_context_free() const { - eosio::check( authorization.size() == 0, "context free actions cannot have authorizations"); - auto serialize = pack(*this); - ::send_context_free_inline(serialize.data(), serialize.size()); - } - - /** - * Retrieve the unpacked data as T - * - * @brief Retrieve the unpacked data as T - * @tparam T expected type of data - * @return the action data - */ - template - T data_as() { - return unpack( &data[0], data.size() ); - } - - }; - - namespace detail { - template - struct unwrap { typedef T type; }; - - template - struct unwrap> { typedef T type; }; - - template - auto get_args(R(Act::*p)(Args...)) { - return std::tuple::type>...>{}; - } - - template - auto get_args_nounwrap(R(Act::*p)(Args...)) { - return std::tuple...>{}; - } - - template - using deduced = decltype(get_args(Action)); - - template - using deduced_nounwrap = decltype(get_args_nounwrap(Action)); - - template - struct convert { typedef T type; }; - - template <> - struct convert { typedef std::string type; }; - - template <> - struct convert { typedef std::string type; }; - - template - struct is_same { static constexpr bool value = std::is_convertible::value; }; - - template - struct is_same { static constexpr bool value = std::is_integral::value; }; - - template - struct is_same { static constexpr bool value = std::is_integral::value; }; - - template - struct get_nth_impl { static constexpr auto value = get_nth_impl::value; }; - - template - struct get_nth_impl { static constexpr auto value = Arg; }; - - template - struct get_nth { static constexpr auto value = get_nth_impl::value; }; - - template - struct check_types { - static_assert(detail::is_same::type, typename convert>::type>::type>::value); - using type = check_types; - static constexpr bool value = true; - }; - template - struct check_types { - static_assert(detail::is_same::type, typename convert>::type>::type>::value); - static constexpr bool value = true; - }; - - template - constexpr bool type_check() { - static_assert(sizeof...(Ts) == std::tuple_size>::value); - return check_types::value; - } - } - - template - struct action_wrapper { - template - constexpr action_wrapper(Code&& code, std::vector&& perms) - : code_name(std::forward(code)), permissions(std::move(perms)) {} - - template - constexpr action_wrapper(Code&& code, const std::vector& perms) - : code_name(std::forward(code)), permissions(perms) {} - - template - constexpr action_wrapper(Code&& code, eosio::permission_level&& perm) - : code_name(std::forward(code)), permissions({1, std::move(perm)}) {} - - template - constexpr action_wrapper(Code&& code, const eosio::permission_level& perm) - : code_name(std::forward(code)), permissions({1, perm}) {} - - static constexpr eosio::name action_name = eosio::name(Name); - eosio::name code_name; - std::vector permissions; - - static constexpr auto get_mem_ptr() { - return Action; - } - - template - action to_action(Args&&... args)const { - static_assert(detail::type_check()); - return action(permissions, code_name, action_name, detail::deduced{std::forward(args)...}); - } - template - void send(Args&&... args)const { - to_action(std::forward(args)...).send(); - } - - template - void send_context_free(Args&&... args)const { - to_action(std::forward(args)...).send_context_free(); - } - - }; - - template - struct variant_action_wrapper { - template - constexpr variant_action_wrapper(Code&& code, std::vector&& perms) - : code_name(std::forward(code)), permissions(std::move(perms)) {} - - template - constexpr variant_action_wrapper(Code&& code, const std::vector& perms) - : code_name(std::forward(code)), permissions(perms) {} - - template - constexpr variant_action_wrapper(Code&& code, eosio::permission_level&& perm) - : code_name(std::forward(code)), permissions({1, std::move(perm)}) {} - - template - constexpr variant_action_wrapper(Code&& code, const eosio::permission_level& perm) - : code_name(std::forward(code)), permissions({1, perm}) {} - - static constexpr eosio::name action_name = eosio::name(Name); - eosio::name code_name; - std::vector permissions; - - template - static constexpr auto get_mem_ptr() { - return detail::get_nth::value; - } - - template - action to_action(Args&&... args)const { - static_assert(detail::type_check::value, Args...>()); - unsigned_int var = Variant; - return action(permissions, code_name, action_name, std::tuple_cat(std::make_tuple(var), detail::deduced::value>{std::forward(args)...})); - } - - - template - void send(Args&&... args)const { - to_action(std::forward(args)...).send(); - } - - template - void send_context_free(Args&&... args) const { - to_action(std::forward(args)...).send_context_free(); - } - - }; - - template - void dispatch_inline( name code, name act, - std::vector perms, - std::tuple args ) { - action( perms, code, act, std::move(args) ).send(); - } - - template - struct inline_dispatcher; - - - template - struct inline_dispatcher { - static void call(name code, const permission_level& perm, std::tuple args) { - dispatch_inline(code, name(Name), std::vector(1, perm), std::move(args)); - } - static void call(name code, std::vector perms, std::tuple args) { - dispatch_inline(code, name(Name), std::move(perms), std::move(args)); - } - }; - -} // namespace eosio - -#define INLINE_ACTION_SENDER3( CONTRACT_CLASS, FUNCTION_NAME, ACTION_NAME )\ -::eosio::inline_dispatcher::call - -#define INLINE_ACTION_SENDER2( CONTRACT_CLASS, NAME )\ -INLINE_ACTION_SENDER3( CONTRACT_CLASS, NAME, ::eosio::name(#NAME) ) - -#define INLINE_ACTION_SENDER(...) BOOST_PP_OVERLOAD(INLINE_ACTION_SENDER,__VA_ARGS__)(__VA_ARGS__) - -/** - * @addtogroup action - * @{ - */ - -/** - * Send inline action - * - * @brief Send inline action - * @param CONTRACT - The account this action is intended for - * @param NAME - The name of the action - * @param ... - The member of the action specified as ("action_member1_name", action_member1_value)("action_member2_name", action_member2_value) - */ -#define SEND_INLINE_ACTION( CONTRACT, NAME, ... )\ -INLINE_ACTION_SENDER(std::decay_t, NAME)( (CONTRACT).get_self(),\ -BOOST_PP_TUPLE_ENUM(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__)) ); - - /// @} diff --git a/libraries/eosiolib/asset.hpp b/libraries/eosiolib/asset.hpp deleted file mode 100644 index af767e6f37..0000000000 --- a/libraries/eosiolib/asset.hpp +++ /dev/null @@ -1,512 +0,0 @@ -#pragma once -#include "serialize.hpp" -#include "print.hpp" -#include "system.hpp" -#include "symbol.hpp" - -#include -#include - -#warning " is deprecated use " - -namespace eosio { - - char* write_decimal( char* begin, char* end, bool dry_run, uint64_t number, uint8_t num_decimal_places, bool negative ); - - /** - * Defines C++ API for managing assets - * @addtogroup asset Asset C++ API - * @ingroup core - * @{ - */ - - /** - * @struct Stores information for owner of asset - */ - - struct asset { - /** - * The amount of the asset - */ - int64_t amount = 0; - - /** - * The symbol name of the asset - */ - symbol symbol; - - /** - * Maximum amount possible for this asset. It's capped to 2^62 - 1 - */ - static constexpr int64_t max_amount = (1LL << 62) - 1; - - asset() {} - - /** - * Construct a new asset given the symbol name and the amount - * - * @param a - The amount of the asset - * @param s - The name of the symbol - */ - asset( int64_t a, class symbol s ) - :amount(a),symbol{s} - { - eosio::check( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" ); - eosio::check( symbol.is_valid(), "invalid symbol name" ); - } - - /** - * Check if the amount doesn't exceed the max amount - * - * @return true - if the amount doesn't exceed the max amount - * @return false - otherwise - */ - bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; } - - /** - * Check if the asset is valid. %A valid asset has its amount <= max_amount and its symbol name valid - * - * @return true - if the asset is valid - * @return false - otherwise - */ - bool is_valid()const { return is_amount_within_range() && symbol.is_valid(); } - - /** - * Set the amount of the asset - * - * @param a - New amount for the asset - */ - void set_amount( int64_t a ) { - amount = a; - eosio::check( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" ); - } - - /** - * Unary minus operator - * - * @return asset - New asset with its amount is the negative amount of this asset - */ - asset operator-()const { - asset r = *this; - r.amount = -r.amount; - return r; - } - - /** - * Subtraction assignment operator - * - * @param a - Another asset to subtract this asset with - * @return asset& - Reference to this asset - * @post The amount of this asset is subtracted by the amount of asset a - */ - asset& operator-=( const asset& a ) { - eosio::check( a.symbol == symbol, "attempt to subtract asset with different symbol" ); - amount -= a.amount; - eosio::check( -max_amount <= amount, "subtraction underflow" ); - eosio::check( amount <= max_amount, "subtraction overflow" ); - return *this; - } - - /** - * Addition Assignment operator - * - * @param a - Another asset to subtract this asset with - * @return asset& - Reference to this asset - * @post The amount of this asset is added with the amount of asset a - */ - asset& operator+=( const asset& a ) { - eosio::check( a.symbol == symbol, "attempt to add asset with different symbol" ); - amount += a.amount; - eosio::check( -max_amount <= amount, "addition underflow" ); - eosio::check( amount <= max_amount, "addition overflow" ); - return *this; - } - - /** - * Addition operator - * - * @param a - The first asset to be added - * @param b - The second asset to be added - * @return asset - New asset as the result of addition - */ - inline friend asset operator+( const asset& a, const asset& b ) { - asset result = a; - result += b; - return result; - } - - /** - * Subtraction operator - * - * @param a - The asset to be subtracted - * @param b - The asset used to subtract - * @return asset - New asset as the result of subtraction of a with b - */ - inline friend asset operator-( const asset& a, const asset& b ) { - asset result = a; - result -= b; - return result; - } - - /** - * @brief Multiplication assignment operator, with a number - * - * @details Multiplication assignment operator. Multiply the amount of this asset with a number and then assign the value to itself. - * @param a - The multiplier for the asset's amount - * @return asset - Reference to this asset - * @post The amount of this asset is multiplied by a - */ - asset& operator*=( int64_t a ) { - int128_t tmp = (int128_t)amount * (int128_t)a; - eosio::check( tmp <= max_amount, "multiplication overflow" ); - eosio::check( tmp >= -max_amount, "multiplication underflow" ); - amount = (int64_t)tmp; - return *this; - } - - /** - * Multiplication operator, with a number proceeding - * - * @brief Multiplication operator, with a number proceeding - * @param a - The asset to be multiplied - * @param b - The multiplier for the asset's amount - * @return asset - New asset as the result of multiplication - */ - friend asset operator*( const asset& a, int64_t b ) { - asset result = a; - result *= b; - return result; - } - - - /** - * Multiplication operator, with a number preceeding - * - * @param a - The multiplier for the asset's amount - * @param b - The asset to be multiplied - * @return asset - New asset as the result of multiplication - */ - friend asset operator*( int64_t b, const asset& a ) { - asset result = a; - result *= b; - return result; - } - - /** - * @brief Division assignment operator, with a number - * - * @details Division assignment operator. Divide the amount of this asset with a number and then assign the value to itself. - * @param a - The divisor for the asset's amount - * @return asset - Reference to this asset - * @post The amount of this asset is divided by a - */ - asset& operator/=( int64_t a ) { - eosio::check( a != 0, "divide by zero" ); - eosio::check( !(amount == std::numeric_limits::min() && a == -1), "signed division overflow" ); - amount /= a; - return *this; - } - - /** - * Division operator, with a number proceeding - * - * @param a - The asset to be divided - * @param b - The divisor for the asset's amount - * @return asset - New asset as the result of division - */ - friend asset operator/( const asset& a, int64_t b ) { - asset result = a; - result /= b; - return result; - } - - /** - * Division operator, with another asset - * - * @param a - The asset which amount acts as the dividend - * @param b - The asset which amount acts as the divisor - * @return int64_t - the resulted amount after the division - * @pre Both asset must have the same symbol - */ - friend int64_t operator/( const asset& a, const asset& b ) { - eosio::check( b.amount != 0, "divide by zero" ); - eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount / b.amount; - } - - /** - * Equality operator - * - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if both asset has the same amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator==( const asset& a, const asset& b ) { - eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount == b.amount; - } - - /** - * Inequality operator - * - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if both asset doesn't have the same amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator!=( const asset& a, const asset& b ) { - return !( a == b); - } - - /** - * Less than operator - * - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is less than the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator<( const asset& a, const asset& b ) { - eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount < b.amount; - } - - /** - * Less or equal to operator - * - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is less or equal to the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator<=( const asset& a, const asset& b ) { - eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount <= b.amount; - } - - /** - * Greater than operator - * - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is greater than the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator>( const asset& a, const asset& b ) { - eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount > b.amount; - } - - /** - * Greater or equal to operator - * - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is greater or equal to the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator>=( const asset& a, const asset& b ) { - eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount >= b.amount; - } - - /** - * Writes the asset as a string to the provided char buffer - * - * @brief Writes the asset as a string to the provided char buffer - * @pre is_valid() == true - * @pre The range [begin, end) must be a valid range of memory to write to. - * @param begin - The start of the char buffer - * @param end - Just past the end of the char buffer - * @param dry_run - If true, do not actually write anything into the range. - * @return char* - Just past the end of the last character that would be written assuming dry_run == false and end was large enough to provide sufficient space. (Meaning only applies if returned pointer >= begin.) - * @post If the output string fits within the range [begin, end) and dry_run == false, the range [begin, returned pointer) contains the string representation of the asset. Nothing is written if dry_run == true or returned pointer > end (insufficient space) or if returned pointer < begin (overflow in calculating desired end). - */ - char* write_as_string( char* begin, char* end, bool dry_run = false )const { - bool negative = (amount < 0); - uint64_t abs_amount = static_cast(negative ? -amount : amount); - // 0 <= abs_amount <= std::numeric_limits::max() < 10^19 < std::numeric_limits::max() - - uint8_t precision = symbol.precision(); - - int sufficient_size = std::max(static_cast(precision), 19) + 11; - if( dry_run || (begin + sufficient_size < begin) || (begin + sufficient_size > end) ) { - char* start_of_symbol = write_decimal( begin, end, true, abs_amount, precision, negative ) + 1; - char* actual_end = symbol.code().write_as_string( start_of_symbol, end, true ); - if( dry_run || (actual_end < begin) || (actual_end > end) ) return actual_end; - } - - char* end_of_number = write_decimal( begin, end, false, abs_amount, precision, negative ); - *(end_of_number) = ' '; - - return symbol.code().write_as_string( end_of_number + 1, end ); - } - - /** - * %asset to std::string - * - * @brief %asset to std::string - */ - std::string to_string()const { - int buffer_size = std::max(static_cast(symbol.precision()), 19) + 11; - char buffer[buffer_size]; - char* end = write_as_string( buffer, buffer + buffer_size ); - check( end <= buffer + buffer_size, "insufficient space in buffer" ); // should never fail - - return {buffer, end}; - } - - /** - * %Print the asset - * - * @brief %Print the asset - */ - void print()const { - int buffer_size = std::max(static_cast(symbol.precision()), 19) + 11; - char buffer[buffer_size]; - char* end = write_as_string( buffer, buffer + buffer_size ); - check( end <= buffer + buffer_size, "insufficient space in buffer" ); // should never fail - - if( buffer < end ) - printl( buffer, (end-buffer) ); - } - - EOSLIB_SERIALIZE( asset, (amount)(symbol) ) - }; - - /** - * @struct Extended asset which stores the information of the owner of the asset - */ - struct extended_asset { - /** - * The asset - */ - asset quantity; - - /** - * The owner of the asset - */ - name contract; - - /** - * Get the extended symbol of the asset - * - * @return extended_symbol - The extended symbol of the asset - */ - extended_symbol get_extended_symbol()const { return extended_symbol{ quantity.symbol, contract }; } - - /** - * Default constructor - */ - extended_asset() = default; - - /** - * Construct a new extended asset given the amount and extended symbol - */ - extended_asset( int64_t v, extended_symbol s ):quantity(v,s.get_symbol()),contract(s.get_contract()){} - /** - * Construct a new extended asset given the asset and owner name - */ - extended_asset( asset a, name c ):quantity(a),contract(c){} - - /** - * %Print the extended asset - */ - void print()const { - quantity.print(); - prints("@"); - printn(contract.value); - } - - /** - * Unary minus operator - * - * @return extended_asset - New extended asset with its amount is the negative amount of this extended asset - */ - extended_asset operator-()const { - return {-quantity, contract}; - } - - /** - * @brief Subtraction operator - * - * @details Subtraction operator. This subtracts the amount of the extended asset. - * @param a - The extended asset to be subtracted - * @param b - The extended asset used to subtract - * @return extended_asset - New extended asset as the result of subtraction - * @pre The owner of both extended asset need to be the same - */ - friend extended_asset operator - ( const extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - return {a.quantity - b.quantity, a.contract}; - } - - /** - * @brief Addition operator - * - * @details Addition operator. This adds the amount of the extended asset. - * @param a - The extended asset to be added - * @param b - The extended asset to be added - * @return extended_asset - New extended asset as the result of addition - * @pre The owner of both extended asset need to be the same - */ - friend extended_asset operator + ( const extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - return {a.quantity + b.quantity, a.contract}; - } - - /// Addition operator. - friend extended_asset& operator+=( extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - a.quantity += b.quantity; - return a; - } - - /// Subtraction operator. - friend extended_asset& operator-=( extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - a.quantity -= b.quantity; - return a; - } - - /// Less than operator - friend bool operator<( const extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - return a.quantity < b.quantity; - } - - - /// Comparison operator - friend bool operator==( const extended_asset& a, const extended_asset& b ) { - return std::tie(a.quantity, a.contract) == std::tie(b.quantity, b.contract); - } - - /// Comparison operator - friend bool operator!=( const extended_asset& a, const extended_asset& b ) { - return std::tie(a.quantity, a.contract) != std::tie(b.quantity, b.contract); - } - - /// Comparison operator - friend bool operator<=( const extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - return a.quantity <= b.quantity; - } - - /// Comparison operator - friend bool operator>=( const extended_asset& a, const extended_asset& b ) { - eosio::check( a.contract == b.contract, "type mismatch" ); - return a.quantity >= b.quantity; - } - - EOSLIB_SERIALIZE( extended_asset, (quantity)(contract) ) - }; - -/// @} asset type -} diff --git a/libraries/eosiolib/binary_extension.hpp b/libraries/eosiolib/binary_extension.hpp deleted file mode 100644 index 248c8515cf..0000000000 --- a/libraries/eosiolib/binary_extension.hpp +++ /dev/null @@ -1,217 +0,0 @@ -#pragma once -#include "print.hpp" - -#warning " is deprecated use " - - namespace eosio { - /** - * Container to hold a binary payload for an extension - * - * @defgroup binary_extension Binary Extension - * @ingroup types - * @{ - */ - /** - * Binary Extension - * @brief container to hold a binary payload for an extension - * @tparam T - Contained typed - * @ingroup types - */ - template - class binary_extension { - public: - using value_type = T; - - constexpr binary_extension() {} - constexpr binary_extension( const T& ext ) - :_has_value(true) - { - ::new (&_data) T(ext); - } - constexpr binary_extension( T&& ext ) - :_has_value(true) - { - ::new (&_data) T(std::move(ext)); - } - - /// @cond IMPLEMENTATIONS - - /** construct contained type in place */ - template - constexpr binary_extension( std::in_place_t, Args&&... args ) - :_has_value(true) - { - ::new (&_data) T(std::forward(args)...); - } - - /// @endcond - - ~binary_extension() { reset(); } - - constexpr binary_extension( const binary_extension& other ) - :_has_value(other._has_value) - { - if( other._has_value ) ::new (&_data) T( *other ); - } - - constexpr binary_extension( binary_extension&& other ) - :_has_value(other._has_value) - { - if( other._has_value ) { - ::new (&_data) T( *std::move(other) ); - other._has_value = false; - } - } - - /** test if container is holding a value */ - constexpr explicit operator bool()const { return _has_value; } - - /** test if container is holding a value */ - constexpr bool has_value()const { return _has_value; } - - /** get the contained value */ - constexpr T& value()& { - if (!_has_value) { - eosio_assert(false, "cannot get value of empty binary_extension"); - } - return _get(); - } - /** get the contained value */ - constexpr const T& value()const & { - if (!_has_value) { - eosio_assert(false, "cannot get value of empty binary_extension"); - } - return _get(); - } - - - /// @cond OPERATORS - - /** - * Get the contained value or a user specified default - * - * @pre def should be convertible to type T - **/ - template - constexpr auto value_or( U&& def ) -> std::enable_if_t::value, T&>& { - if (_has_value) - return _get(); - return def; - } - constexpr T&& value_or()&& { - if (!_has_value) - return std::move(T()); - _has_value = false; - return std::move(_get()); - } - constexpr const T&& value_or()const&& { - if (!_has_value) - return std::move(T()); - _has_value = false; - return std::move(_get()); - } - constexpr T value_or()& { - if (!_has_value) - return {}; - return _get(); - } - constexpr T value_or()const& { - if (!_has_value) - return {}; - return _get(); - } - - constexpr T* operator->() { - return &_get(); - } - constexpr const T* operator->()const { - return &_get(); - } - - constexpr T& operator*()& { - return _get(); - } - constexpr const T& operator*()const& { - return _get(); - } - constexpr const T&& operator*()const&& { - return std::move(_get()); - } - constexpr T&& operator*()&& { - return std::move(_get()); - } - - /// @endcond - - /// @cond IMPLEMENTATIONS - - template - T& emplace(Args&& ... args)& { - if (_has_value) { - reset(); - } - - ::new (&_data) T( std::forward(args)... ); - _has_value = true; - - return _get(); - } - - void reset() { - if( _has_value ) { - _get().~value_type(); - _has_value = false; - } - } - - /// @endcond - - /** - * Serialize a binary_extension into a stream - * - * @brief Serialize a binary_extension - * @param ds - The stream to write - * @param opt - The value to serialize - * @tparam DataStream - Type of datastream buffer - * @return DataStream& - Reference to the datastream - */ - template - friend inline DataStream& operator<<(DataStream& ds, const eosio::binary_extension& be) { - ds << be.value_or(); - return ds; - } - - /** - * Deserialize a binary_extension from a stream - * - * @brief Deserialize a binary_extension - * @param ds - The stream to read - * @param opt - The destination for deserialized value - * @tparam DataStream - Type of datastream buffer - * @return DataStream& - Reference to the datastream - */ - template - friend inline DataStream& operator>>(DataStream& ds, eosio::binary_extension& be) { - if( ds.remaining() ) { - T val; - ds >> val; - be.emplace(val); - } - return ds; - } - - - - private: - bool _has_value = false; - typename std::aligned_storage::type _data; - - constexpr T& _get() { - return *reinterpret_cast(&_data); - } - - constexpr const T& _get()const { - return *reinterpret_cast(&_data); - } - }; -} // namespace eosio diff --git a/libraries/eosiolib/capi/eosio/privileged.h b/libraries/eosiolib/capi/eosio/privileged.h index 9694929a81..523bf436a3 100644 --- a/libraries/eosiolib/capi/eosio/privileged.h +++ b/libraries/eosiolib/capi/eosio/privileged.h @@ -1,5 +1,5 @@ #pragma once - +#include "types.h" #ifdef __cplusplus extern "C" { #endif @@ -35,6 +35,8 @@ void set_resource_limits( capi_name account, int64_t ram_bytes, int64_t net_weig /** * Proposes a schedule change * + * This is exactly equivalent to calling `set_proposed_producers_ex(0, producer_data, producer_data_size)` + * * @note Once the block that contains the proposal becomes irreversible, the schedule is promoted to "pending" automatically. Once the block that promotes the schedule is irreversible, the schedule will become "active" * @param producer_data - packed data of produce_keys in the appropriate producer schedule order * @param producer_data_size - size of the data buffer @@ -44,6 +46,24 @@ void set_resource_limits( capi_name account, int64_t ram_bytes, int64_t net_weig __attribute__((eosio_wasm_import)) int64_t set_proposed_producers( char *producer_data, uint32_t producer_data_size ); +/** + * Proposes a schedule change with extended features + * + * Valid formats: + * 0 : serialized array of producer_key's. using this format is exactly equivalent to `set_proposed_producers(producer_data, producer_data_size)` + * 1 : serialized array of producer_authority's + * + * @note Once the block that contains the proposal becomes irreversible, the schedule is promoted to "pending" automatically. Once the block that promotes the schedule is irreversible, the schedule will become "active" + * @param producer_data_format - format of the producer data blob + * @param producer_data - packed data of representing the producer schedule in the format indicated. + * @param producer_data_size - size of the data buffer + * + * @return -1 if proposing a new producer schedule was unsuccessful, otherwise returns the version of the new proposed schedule + */ +__attribute__((eosio_wasm_import)) +int64_t set_proposed_producers_ex( uint64_t producer_data_format, char *producer_data, uint32_t producer_data_size ); + + /** * Check if an account is privileged * @@ -85,7 +105,14 @@ void set_blockchain_parameters_packed( char* data, uint32_t datalen ); __attribute__((eosio_wasm_import)) uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ); +/** + * Pre-activate protocol feature + * + * @param feature_digest - digest of the protocol feature to pre-activate + */ +__attribute__((eosio_wasm_import)) +void preactivate_feature( const capi_checksum256* feature_digest ); + #ifdef __cplusplus } #endif - diff --git a/libraries/eosiolib/capi/eosio/system.h b/libraries/eosiolib/capi/eosio/system.h index 95186027dc..b7b7cb63a1 100644 --- a/libraries/eosiolib/capi/eosio/system.h +++ b/libraries/eosiolib/capi/eosio/system.h @@ -76,6 +76,23 @@ void eosio_exit( int32_t code ); __attribute__((eosio_wasm_import)) uint64_t current_time(); +/** + * Check if specified protocol feature has been activated + * + * @param feature_digest - digest of the protocol feature + * @return true if the specified protocol feature has been activated, false otherwise + */ +__attribute__((eosio_wasm_import)) +bool is_feature_activated( const capi_checksum256* feature_digest ); + +/** + * Return name of account that sent current inline action + * + * @return name of account that sent the current inline action (empty name if not called from inline action) + */ +__attribute__((eosio_wasm_import)) +capi_name get_sender(); + #ifdef __cplusplus } #endif diff --git a/libraries/eosiolib/capi/eosio/types.h b/libraries/eosiolib/capi/eosio/types.h index 2337427065..9350b9b4d1 100644 --- a/libraries/eosiolib/capi/eosio/types.h +++ b/libraries/eosiolib/capi/eosio/types.h @@ -30,16 +30,18 @@ typedef uint64_t capi_name; /** - * EOSIO Public Key. It is 34 bytes. + * EOSIO Public Key. K1 and R1 keys are 34 bytes. Newer keys can be variable-sized */ -struct capi_public_key { +struct __attribute__((deprecated("newer public key types cannot be represented as a fixed size structure", "char[]"))) +capi_public_key { char data[34]; }; /** - * EOSIO Signature. It is 66 bytes. + * EOSIO Signature. K1 and R1 signatures are 66 bytes. Newer signatures can be variable-sized */ -struct capi_signature { +struct __attribute__((deprecated("newer signature types cannot be represented as a fixed size structure", "char[]"))) +capi_signature { uint8_t data[66]; }; diff --git a/libraries/eosiolib/chain.h b/libraries/eosiolib/chain.h deleted file mode 100644 index 0647814ab6..0000000000 --- a/libraries/eosiolib/chain.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "types.h" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" -/** - * @addtogroup chain - * @ingroup c_api - * @brief Defines %C API for querying internal chain state - * @{ - */ - -extern "C" { - /** - * Gets the set of active producers. - * - * @param producers - Pointer to a buffer of account names - * @param datalen - Byte length of buffer, when passed 0 will return the size required to store full output. - * - * @return uint32_t - Number of bytes actually populated - * @pre `producers` is a pointer to a range of memory at least `datalen` bytes long - * @post the passed in `producers` pointer gets the array of active producers. - * - * Example: - * - * @code - * capi_name producers[21]; - * uint32_t bytes_populated = get_active_producers(producers, sizeof(capi_name)*21); - * @endcode - */ - __attribute__((eosio_wasm_import)) - uint32_t get_active_producers( capi_name* producers, uint32_t datalen ); -} - -/// @} diff --git a/libraries/eosiolib/contract.hpp b/libraries/eosiolib/contract.hpp deleted file mode 100644 index 611e1c7d35..0000000000 --- a/libraries/eosiolib/contract.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include "name.hpp" -#include "datastream.hpp" - - -#warning " is deprecated use " - -/** - * @defgroup contract Contract - * @ingroup types - * @brief Defines contract type which is %base class for every EOSIO contract - * @{ - */ -namespace eosio { - -/** - * @brief %Base class for EOSIO contract. - * @details %Base class for EOSIO contract. %A new contract should derive from this class, so it can make use of EOSIO_ABI macro. - */ -class contract { - public: - /** - * Construct a new contract given the contract name - * - * @param receiver - The name of this contract - * @param code - The code name of the action this contract is processing. - * @param ds - The datastream used - */ - contract( name receiver, name code, datastream ds ):_self(receiver),_code(code),_ds(ds) {} - - /** - * - * Get this contract name - * - * @return name - The name of this contract - */ - inline name get_self()const { return _self; } - - /** - * The code name of the action this contract is processing. - * - * @return name - The code name of the action this contract is processing. - */ - inline name get_code()const { return _code; } - - /** - * Get the datastream for this contract - * - * @return datastream - The datastream for this contract - */ - inline datastream get_datastream()const { return _ds; } - - protected: - /** - * The name of this contract - */ - name _self; - - /** - * The code name of the action this contract is processing. - */ - name _code; - - /** - * The datastream for this contract - */ - datastream _ds = datastream(nullptr, 0); -}; -} diff --git a/libraries/eosiolib/contracts/eosio/action.hpp b/libraries/eosiolib/contracts/eosio/action.hpp index 755a6c2121..85ca78edb4 100644 --- a/libraries/eosiolib/contracts/eosio/action.hpp +++ b/libraries/eosiolib/contracts/eosio/action.hpp @@ -213,6 +213,18 @@ namespace eosio { return std::tie( a.actor, a.permission ) == std::tie( b.actor, b.permission ); } + /** + * Lexicographically compares two permissions + * + * @param a - first permission to compare + * @param b - second permission to compare + * @return true if a < b + * @return false if a >= b + */ + friend constexpr bool operator < ( const permission_level& a, const permission_level& b ) { + return std::tie( a.actor, a.permission ) < std::tie( b.actor, b.permission ); + } + EOSLIB_SERIALIZE( permission_level, (actor)(permission) ) }; diff --git a/libraries/eosiolib/contracts/eosio/contract.hpp b/libraries/eosiolib/contracts/eosio/contract.hpp index ea3b7c7517..d60d47241c 100644 --- a/libraries/eosiolib/contracts/eosio/contract.hpp +++ b/libraries/eosiolib/contracts/eosio/contract.hpp @@ -25,7 +25,7 @@ namespace eosio { * %Base class for EOSIO contract. * * @ingroup contract - * @details %Base class for EOSIO contract. %A new contract should derive from this class, so it can make use of EOSIO_ABI macro. + * @details %A new contract should derive from this class, so it can make use of EOSIO_ABI macro. */ class contract { public: diff --git a/libraries/eosiolib/contracts/eosio/permission.hpp b/libraries/eosiolib/contracts/eosio/permission.hpp index 8660b19d91..0d98a18708 100644 --- a/libraries/eosiolib/contracts/eosio/permission.hpp +++ b/libraries/eosiolib/contracts/eosio/permission.hpp @@ -49,7 +49,7 @@ namespace eosio { check_transaction_authorization( const char* trx_data, uint32_t trx_size, const char* pubkeys_data, uint32_t pubkeys_size, const char* perms_data, uint32_t perms_size ) { - return internal_use_do_not_use::check_transaction_authorization( trx_data, trx_size, pubkeys_data, pubkeys_size, perms_data, perms_size ); + return internal_use_do_not_use::check_transaction_authorization( trx_data, trx_size, pubkeys_data, pubkeys_size, perms_data, perms_size ); } /** @@ -74,7 +74,7 @@ namespace eosio { microseconds delay ) { int64_t delay_us = delay.count(); check(delay_us >= 0, "negative delay is not allowed"); - return internal_use_do_not_use::check_permission_authorization( account.value, permission.value, pubkeys_data, pubkeys_size, perms_data, perms_size, static_cast(delay_us) ); + return internal_use_do_not_use::check_permission_authorization( account.value, permission.value, pubkeys_data, pubkeys_size, perms_data, perms_size, static_cast(delay_us) ); } diff --git a/libraries/eosiolib/contracts/eosio/privileged.hpp b/libraries/eosiolib/contracts/eosio/privileged.hpp index 1fd97f3ddc..53f194ef09 100644 --- a/libraries/eosiolib/contracts/eosio/privileged.hpp +++ b/libraries/eosiolib/contracts/eosio/privileged.hpp @@ -1,5 +1,6 @@ #pragma once #include "producer_schedule.hpp" +#include "system.hpp" #include "../../core/eosio/crypto.hpp" #include "../../core/eosio/name.hpp" #include "../../core/eosio/serialize.hpp" @@ -11,23 +12,29 @@ namespace eosio { __attribute__((eosio_wasm_import)) bool is_privileged( uint64_t account ); - __attribute__((eosio_wasm_import)) - void get_resource_limits( uint64_t account, int64_t* ram_bytes, int64_t* net_weight, int64_t* cpu_weight ); + __attribute__((eosio_wasm_import)) + void get_resource_limits( uint64_t account, int64_t* ram_bytes, int64_t* net_weight, int64_t* cpu_weight ); + + __attribute__((eosio_wasm_import)) + void set_resource_limits( uint64_t account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ); - __attribute__((eosio_wasm_import)) - void set_resource_limits( uint64_t account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ); + __attribute__((eosio_wasm_import)) + void set_privileged( uint64_t account, bool is_priv ); + + __attribute__((eosio_wasm_import)) + void set_blockchain_parameters_packed( char* data, uint32_t datalen ); - __attribute__((eosio_wasm_import)) - void set_privileged( uint64_t account, bool is_priv ); + __attribute__((eosio_wasm_import)) + uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ); - __attribute__((eosio_wasm_import)) - void set_blockchain_parameters_packed( char* data, uint32_t datalen ); + __attribute((eosio_wasm_import)) + int64_t set_proposed_producers( char*, uint32_t ); - __attribute__((eosio_wasm_import)) - uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ); + __attribute__((eosio_wasm_import)) + void preactivate_feature( const capi_checksum256* feature_digest ); - __attribute((eosio_wasm_import)) - int64_t set_proposed_producers( char*, uint32_t ); + __attribute__((eosio_wasm_import)) + int64_t set_proposed_producers_ex( uint64_t producer_data_format, char *producer_data, uint32_t producer_data_size ); } } @@ -202,7 +209,7 @@ namespace eosio { } /** - * Proposes a schedule change + * Proposes a schedule change using the legacy producer key format * * @ingroup privileged * @note Once the block that contains the proposal becomes irreversible, the schedule is promoted to "pending" automatically. Once the block that promotes the schedule is irreversible, the schedule will become "active" @@ -212,6 +219,23 @@ namespace eosio { */ std::optional set_proposed_producers( const std::vector& prods ); + /** + * Proposes a schedule change using the more flexible key format + * + * @ingroup privileged + * @note Once the block that contains the proposal becomes irreversible, the schedule is promoted to "pending" automatically. Once the block that promotes the schedule is irreversible, the schedule will become "active" + * @param producers - vector of producer authorities + * + * @return an optional value of the version of the new proposed schedule if successful + */ + inline std::optional set_proposed_producers( const std::vector& prods ) { + auto packed_prods = eosio::pack( prods ); + int64_t ret = internal_use_do_not_use::set_proposed_producers_ex(1, (char*)packed_prods.data(), packed_prods.size()); + if (ret >= 0) + return static_cast(ret); + return {}; + } + /** * Check if an account is privileged * @@ -235,4 +259,17 @@ namespace eosio { internal_use_do_not_use::set_privileged( account.value, is_priv ); } + /** + * Pre-activate protocol feature + * + * @ingroup privileged + * @param feature_digest - digest of the protocol feature to pre-activate + */ + inline void preactivate_feature( const checksum256& feature_digest ) { + auto feature_digest_data = feature_digest.extract_as_byte_array(); + internal_use_do_not_use::preactivate_feature( + reinterpret_cast( feature_digest_data.data() ) + ); + } + } diff --git a/libraries/eosiolib/contracts/eosio/producer_schedule.hpp b/libraries/eosiolib/contracts/eosio/producer_schedule.hpp index c2d35fce36..0c1c800fc4 100644 --- a/libraries/eosiolib/contracts/eosio/producer_schedule.hpp +++ b/libraries/eosiolib/contracts/eosio/producer_schedule.hpp @@ -68,6 +68,99 @@ namespace eosio { std::vector producers; }; + /** + * @defgroup producer_authority Producer Authority + * @ingroup contracts + * @ingroup types + * @brief Maps producer with its a flexible authority structure, used for producer schedule + */ + + /** + * pairs a public key with an integer weight + * + * @ingroup producer_authority + */ + struct key_weight { + /** + * public key used in a weighted threshold multi-sig authority + * + * @brief public key used in a weighted threshold multi-sig authority + */ + public_key key; + + /** + * weight associated with a signature from the private key associated with the accompanying public key + * + * @brief weight of the public key + */ + uint16_t weight; + + EOSLIB_SERIALIZE( key_weight, (key)(weight) ) + }; + + /** + * block signing authority version 0 + * this authority allows for a weighted threshold multi-sig per-producer + * + * @ingroup producer_authority + * + * @brief weighted threshold multi-sig authority + */ + struct block_signing_authority_v0 { + /** + * minimum threshold of accumulated weights from component keys that satisfies this authority + * + * @brief minimum threshold of accumulated weights from component keys that satisfies this authority + */ + uint32_t threshold; + + /** + * component keys and their associated weights + * + * @brief component keys and their associated weights + */ + std::vector keys; + + bool is_valid()const; + + EOSLIB_SERIALIZE( block_signing_authority_v0, (threshold)(keys) ) + }; + + /** + * variant of all possible block signing authorities + * + * @ingroup producer_authority + */ + using block_signing_authority = std::variant; + + /** + * Maps producer with its signing key, used for producer schedule + * + * @ingroup producer_authority + * + * @brief Maps producer with its signing key + */ + struct producer_authority { + + /** + * Name of the producer + * + * @brief Name of the producer + */ + name producer_name; + + /** + * The block signing authority used by this producer + */ + block_signing_authority authority; + + friend constexpr bool operator < ( const producer_authority& a, const producer_authority& b ) { + return a.producer_name < b.producer_name; + } + + EOSLIB_SERIALIZE( producer_authority, (producer_name)(authority) ) + }; + /** * Returns back the list of active producer names. * diff --git a/libraries/eosiolib/contracts/eosio/system.hpp b/libraries/eosiolib/contracts/eosio/system.hpp index a65f924319..5c5c21926b 100644 --- a/libraries/eosiolib/contracts/eosio/system.hpp +++ b/libraries/eosiolib/contracts/eosio/system.hpp @@ -5,12 +5,24 @@ #pragma once #include "../../core/eosio/time.hpp" #include "../../core/eosio/check.hpp" +#include "../../core/eosio/fixed_bytes.hpp" +#include "../../core/eosio/name.hpp" namespace eosio { namespace internal_use_do_not_use { extern "C" { __attribute__((eosio_wasm_import, noreturn)) void eosio_exit( int32_t code ); + + struct __attribute__((aligned (16))) capi_checksum256 { + uint8_t hash[32]; + }; + + __attribute__((eosio_wasm_import)) + bool is_feature_activated( const capi_checksum256* feature_digest ); + + __attribute__((eosio_wasm_import)) + uint64_t get_sender(); } } @@ -53,4 +65,29 @@ namespace eosio { * @return time in microseconds from 1970 of the current block as a block_timestamp */ block_timestamp current_block_time(); + + + /** + * Check if specified protocol feature has been activated + * + * @ingroup system + * @param feature_digest - digest of the protocol feature + * @return true if the specified protocol feature has been activated, false otherwise + */ + inline bool is_feature_activated( const checksum256& feature_digest ) { + auto feature_digest_data = feature_digest.extract_as_byte_array(); + return internal_use_do_not_use::is_feature_activated( + reinterpret_cast( feature_digest_data.data() ) + ); + } + + /** + * Return name of account that sent current inline action + * + * @ingroup system + * @return name of account that sent the current inline action (empty name if not called from inline action) + */ + inline name get_sender() { + return name( internal_use_do_not_use::get_sender() ); + } } diff --git a/libraries/eosiolib/core/eosio/binary_extension.hpp b/libraries/eosiolib/core/eosio/binary_extension.hpp index d44ed3276a..ac59569e43 100644 --- a/libraries/eosiolib/core/eosio/binary_extension.hpp +++ b/libraries/eosiolib/core/eosio/binary_extension.hpp @@ -103,12 +103,12 @@ namespace eosio { } constexpr T value_or()& { if (!_has_value) - return {}; + return T(); return _get(); } constexpr T value_or()const& { if (!_has_value) - return {}; + return T(); return _get(); } diff --git a/libraries/eosiolib/core/eosio/crypto.hpp b/libraries/eosiolib/core/eosio/crypto.hpp index fdbf79c846..b7ca46a980 100644 --- a/libraries/eosiolib/core/eosio/crypto.hpp +++ b/libraries/eosiolib/core/eosio/crypto.hpp @@ -20,37 +20,88 @@ namespace eosio { */ /** - * EOSIO Public Key + * EOSIO ECC public key data * + * Fixed size representation of either a K1 or R1 compressed public key + * @ingroup public_key */ - struct public_key { + using ecc_public_key = std::array; + + /** + * EOSIO WebAuthN public key + * + * @ingroup public_key + */ + struct webauthn_public_key { /** - * Type of the public key, could be either K1 or R1 + * Enumeration of the various results of a Test of User Presence + * @see https://w3c.github.io/webauthn/#test-of-user-presence */ - unsigned_int type; + enum class user_presence_t : uint8_t { + USER_PRESENCE_NONE, + USER_PRESENCE_PRESENT, + USER_PRESENCE_VERIFIED + }; /** - * Bytes of the public key + * The ECC key material */ - std::array data; + ecc_public_key key; + + /** + * expected result of the test of user presence for a valid signature + * @see https://w3c.github.io/webauthn/#test-of-user-presence + */ + user_presence_t user_presence; + + /** + * the Relying Party Identifier for WebAuthN + * @see https://w3c.github.io/webauthn/#relying-party-identifier + */ + std::string rpid; /// @cond OPERATORS - friend bool operator == ( const public_key& a, const public_key& b ) { - return std::tie(a.type,a.data) == std::tie(b.type,b.data); + friend bool operator == ( const webauthn_public_key& a, const webauthn_public_key& b ) { + return std::tie(a.key,a.user_presence,a.rpid) == std::tie(b.key,b.user_presence,b.rpid); + } + friend bool operator != ( const webauthn_public_key& a, const webauthn_public_key& b ) { + return std::tie(a.key,a.user_presence,a.rpid) != std::tie(b.key,b.user_presence,b.rpid); + } + friend bool operator < ( const webauthn_public_key& a, const webauthn_public_key& b ) { + return std::tie(a.key,a.user_presence,a.rpid) < std::tie(b.key,b.user_presence,b.rpid); + } + friend bool operator <= ( const webauthn_public_key& a, const webauthn_public_key& b ) { + return std::tie(a.key,a.user_presence,a.rpid) <= std::tie(b.key,b.user_presence,b.rpid); } - friend bool operator != ( const public_key& a, const public_key& b ) { - return std::tie(a.type,a.data) != std::tie(b.type,b.data); + friend bool operator > ( const webauthn_public_key& a, const webauthn_public_key& b ) { + return std::tie(a.key,a.user_presence,a.rpid) > std::tie(b.key,b.user_presence,b.rpid); + } + friend bool operator >= ( const webauthn_public_key& a, const webauthn_public_key& b ) { + return std::tie(a.key,a.user_presence,a.rpid) >= std::tie(b.key,b.user_presence,b.rpid); } /// @cond }; + /** + * EOSIO Public Key + * + * A public key is a variant of + * 0 : a ECC K1 public key + * 1 : a ECC R1 public key + * 2 : a WebAuthN public key (requires the host chain to activate the WEBAUTHN_KEY consensus upgrade) + * + * @ingroup public_key + */ + using public_key = std::variant; + + /// @cond IMPLEMENTATIONS /** - * Serialize an eosio::public_key into a stream + * Serialize an eosio::webauthn_public_key into a stream * * @ingroup public_key * @param ds - The stream to write @@ -59,14 +110,13 @@ namespace eosio { * @return DataStream& - Reference to the datastream */ template - inline DataStream& operator<<(DataStream& ds, const eosio::public_key& pubkey) { - ds << pubkey.type; - ds.write( pubkey.data.data(), pubkey.data.size() ); + inline DataStream& operator<<(DataStream& ds, const eosio::webauthn_public_key& pubkey) { + ds << pubkey.key << pubkey.user_presence << pubkey.rpid; return ds; } /** - * Deserialize an eosio::public_key from a stream + * Deserialize an eosio::webauthn_public_key from a stream * * @ingroup public_key * @param ds - The stream to read @@ -75,9 +125,8 @@ namespace eosio { * @return DataStream& - Reference to the datastream */ template - inline DataStream& operator>>(DataStream& ds, eosio::public_key& pubkey) { - ds >> pubkey.type; - ds.read( pubkey.data.data(), pubkey.data.size() ); + inline DataStream& operator>>(DataStream& ds, eosio::webauthn_public_key& pubkey) { + ds >> pubkey.key >> pubkey.user_presence >> pubkey.rpid; return ds; } @@ -91,38 +140,65 @@ namespace eosio { */ /** - * EOSIO Signature + * EOSIO ECC signature data * + * Fixed size representation of either a K1 or R1 ECC compact signature + * @ingroup signature */ - struct signature { + using ecc_signature = std::array; + /** + * EOSIO WebAuthN signature + * + * @ingroup signature + */ + struct webauthn_signature { /** - * Type of the signature, could be either K1 or R1 + * The ECC signature data */ - unsigned_int type; + ecc_signature compact_signature; /** - * Bytes of the signature + * The Encoded Authenticator Data returned from WebAuthN ceremony + * @see https://w3c.github.io/webauthn/#sctn-authenticator-data */ - std::array data; + std::vector auth_data; + + /** + * the JSON encoded Collected Client Data from a WebAuthN ceremony + * @see https://w3c.github.io/webauthn/#dictdef-collectedclientdata + */ + std::string client_json; /// @cond OPERATORS - friend bool operator == ( const signature& a, const signature& b ) { - return std::tie(a.type,a.data) == std::tie(b.type,b.data); + friend bool operator == ( const webauthn_signature& a, const webauthn_signature& b ) { + return std::tie(a.compact_signature,a.auth_data,a.client_json) == std::tie(b.compact_signature,b.auth_data,b.client_json); } - friend bool operator != ( const signature& a, const signature& b ) { - return std::tie(a.type,a.data) != std::tie(b.type,b.data); + friend bool operator != ( const webauthn_signature& a, const webauthn_signature& b ) { + return std::tie(a.compact_signature,a.auth_data,a.client_json) != std::tie(b.compact_signature,b.auth_data,b.client_json); } - /// @endcond + /// @cond }; + /** + * EOSIO Signature + * + * A signature is a variant of + * 0 : a ECC K1 signature + * 1 : a ECC R1 signatre + * 2 : a WebAuthN signature (requires the host chain to activate the WEBAUTHN_KEY consensus upgrade) + * + * @ingroup signature + */ + using signature = std::variant; + /// @cond IMPLEMENTATIONS /** - * Serialize an eosio::signature into a stream + * Serialize an eosio::webauthn_signature into a stream * * @param ds - The stream to write * @param sig - The value to serialize @@ -130,14 +206,13 @@ namespace eosio { * @return DataStream& - Reference to the datastream */ template - inline DataStream& operator<<(DataStream& ds, const eosio::signature& sig) { - ds << sig.type; - ds.write( sig.data.data(), sig.data.size() ); + inline DataStream& operator<<(DataStream& ds, const eosio::webauthn_signature& sig) { + ds << sig.compact_signature << sig.auth_data << sig.client_json; return ds; } /** - * Deserialize an eosio::signature from a stream + * Deserialize an eosio::webauthn_signature from a stream * * @param ds - The stream to read * @param sig - The destination for deserialized value @@ -145,9 +220,8 @@ namespace eosio { * @return DataStream& - Reference to the datastream */ template - inline DataStream& operator>>(DataStream& ds, eosio::signature& sig) { - ds >> sig.type; - ds.read( sig.data.data(), sig.data.size() ); + inline DataStream& operator>>(DataStream& ds, eosio::webauthn_signature& sig) { + ds >> sig.compact_signature >> sig.auth_data >> sig.client_json; return ds; } diff --git a/libraries/eosiolib/core/eosio/datastream.hpp b/libraries/eosiolib/core/eosio/datastream.hpp index be01fa40a5..5526d2e6bf 100644 --- a/libraries/eosiolib/core/eosio/datastream.hpp +++ b/libraries/eosiolib/core/eosio/datastream.hpp @@ -340,7 +340,7 @@ void deserialize(datastream& ds, std::variant& var, int i) { if (i == I) { std::variant_alternative_t> tmp; ds >> tmp; - var = std::move(tmp); + var.template emplace(std::move(tmp)); } else { deserialize(ds,var,i); } diff --git a/libraries/eosiolib/core/eosio/string.hpp b/libraries/eosiolib/core/eosio/string.hpp new file mode 100644 index 0000000000..cbb5c8e5c2 --- /dev/null +++ b/libraries/eosiolib/core/eosio/string.hpp @@ -0,0 +1,483 @@ +/** + * @file + * @copyright defined in eosio.cdt/LICENSE.txt + */ + +#pragma once + +#include // memcpy, memset, strlen +#include // std::swap +#include // std::unique_ptr +#include // std::variant +#include // std::vector + +#include "datastream.hpp" // eosio::datastream +#include "varint.hpp" // eosio::unsigned_int + +namespace eosio { + + class string { + public: + static constexpr size_t npos = -1; + + template + constexpr string(const char (&str)[N]) + : _size{N-1} + , _capacity{_size} + , _begin{str} + { + } + + constexpr string() + : _size{0} + , _capacity{0} + , _begin{""} + { + } + + constexpr string(const char* str, const size_t n) + : _size{n} + , _capacity{_size*2} + { + char* begin{new char[_capacity]}; + memcpy(begin, str, _size); + _begin = begin; + } + + constexpr string(const size_t n, const char c) + : _size{n} + , _capacity{_size*2} + { + char* begin{new char[_capacity]}; + memset(begin, c, _size); + _begin = begin; + } + + constexpr string(const string& str, const size_t pos, const size_t n) + : _size{n} + , _capacity{_size*2} + { + if (n == string::npos || str._size < pos+n) { + _size = str._size; + _capacity = _size*2; + } + + clone(_size, _capacity, str.data()+pos); + } + + constexpr string(const string& str) + : _size{str._size} + , _capacity{str._capacity} + { + if (str.is_literal()) + _begin = std::get(str._begin); + else + clone(str._size, str._capacity, str.data()); + } + + constexpr string(string&& str) + : _size{str._size} + , _capacity{str._capacity} + { + if (str.is_literal()) + _begin = std::get(str._begin); + else + _begin = std::move(std::get(str._begin)); + } + + string& operator=(const string& str) { + if (&str == this) + return *this; + + _size = str._size; + _capacity = str._capacity; + + if (str.is_literal()) + _begin = std::get(str._begin); + else + clone(_size, _capacity, str.data()); + + return *this; + } + + string& operator=(string&& str) { + if (&str == this) + return *this; + + _size = str._size; + _capacity = str._capacity; + + if (str.is_literal()) + _begin = std::get(str._begin); + else + _begin = std::move(std::get(str._begin)); + + return *this; + } + + string& operator=(const char* str) { + _size = strlen(str); + _capacity = _size; + _begin = str; + + return *this; + } + + char& operator[](const size_t n) { + if (is_literal()) + clone(_size, _capacity, std::get(_begin)); + return std::get(_begin).get()[n]; + } + + const char operator[](const size_t n) const { + return (is_literal()) ? std::get(_begin)[n] : std::get(_begin).get()[n]; + } + + char& at(const size_t n) { + eosio::check(0 <= n && n < _size, "eosio::string::at"); + return operator[](n); + } + + const char at(const size_t n) const { + eosio::check(0 <= n && n < _size, "eosio::string::at const"); + return operator[](n); + } + + char& front() { + return at(0); + } + + const char front() const { + return at(0); + } + + char& back() { + return at(_size-1); + } + + const char back() const { + return at(_size-1); + } + + char* data() { + return begin(); + } + + const char* data() const { + return cbegin(); + } + + const char* c_str() const { + static size_t prev_size{0}; + char* raw_ptr{nullptr}; + + if (is_literal()) + return std::get(_begin); + + if (_size == prev_size) + return std::get(_begin).get(); + else if (_size < prev_size) + raw_ptr = std::get(_begin).get(); + else { + uptr tmp = std::make_unique(_size+1); + raw_ptr = tmp.get(); + prev_size = _size; + memcpy(raw_ptr, std::get(_begin).get(), _size); + } + + raw_ptr[_size+1] = '\0'; + return raw_ptr; + } + + char* begin() { + if (is_literal()) { + _capacity *= 2; + clone(_size, _capacity, std::get(_begin)); + } + + return std::get(_begin).get(); + } + + const char* cbegin() const { + return (is_literal()) ? std::get(_begin) : std::get(_begin).get(); + } + + char* end() { + return begin()+_size; + } + + const char* cend() const { + return cbegin()+_size; + } + + bool empty() const { + return !_size; + } + + size_t size() const { + return _size; + } + + size_t length() const { + return _size; + } + + size_t capacity() const { + return _capacity; + } + + size_t max_size() const { + return npos; + } + + void reserve(const size_t n) { + if (_capacity < n) { + _capacity = n; + + const char* tmp{(is_literal()) ? std::get(_begin) : std::get(_begin).get()}; + clone(_size, _capacity, tmp); + } + else + return; + } + + void shrink_to_fit() { + _capacity = _size; + } + + void clear() { + _size = 0; + + if (is_literal()) + clone(_size, _capacity, std::get(_begin)); + std::get(_begin).get()[0] = '\0'; + } + + void resize(const size_t n) { + if (is_literal()) + clone(n, _capacity, std::get(_begin)); + else { + _size = n; + if (n <= _capacity) + memset(std::get(_begin).get()+_size, '\0', _capacity-_size); + else { + _capacity = _size*2; + clone(_size, _capacity, std::get(_begin).get()); + } + } + } + + void swap(string& str) { + std::swap(*this, str); + } + + void push_back(const char c) { + *this += c; + } + + void pop_back() { + if (_size == 0) + return; + resize(--_size); + } + + string substr(size_t pos = 0, size_t len = npos) const { + return string(*this, pos, len); + } + + size_t copy(char* s, size_t len, size_t pos = 0) const { + eosio::check(pos <= _size, "eosio::string::copy"); + len = (_size < pos+len) ? _size : len; + + const char* tmp{(is_literal()) ? std::get(_begin) : std::get(_begin).get()}; + memcpy(s, tmp+pos, len); + + return (_size < pos+len) ? _size-pos : len; + } + + string& insert(const size_t pos, const char* str) { + return insert(pos, str, strlen(str)); + } + + string& insert(const size_t pos, const char* str, const size_t len) { + eosio::check((str != nullptr) && (0 <= pos && pos <= _size), "eosio::string::insert"); + + if (_capacity < (_size+len)) { + _size += len; + _capacity = _size*2; + + uptr begin{std::make_unique(_capacity)}; + const char* tmp{(is_literal()) ? std::get(_begin) : std::get(_begin).get()}; + + memcpy(begin.get(), tmp, pos); + memcpy(begin.get()+pos, str, len); + memcpy(begin.get()+len+pos, tmp+pos, _size-len-pos); + + _begin = std::move(begin); + } + else { + if(is_literal()) + clone(_size, _capacity, std::get(_begin)); + _size += len; + memmove(std::get(_begin).get()+pos+len, std::get(_begin).get()+pos, _size-pos); + memcpy(std::get(_begin).get()+pos, str, len); + } + + return *this; + } + + string& insert(const size_t pos, const string& str) { + insert(pos, str.c_str()); + return *this; + } + + string& erase(size_t pos = 0, size_t len = npos) { + eosio::check(0 <= pos && pos <= _size, "eosio::string::erase"); + + if (len == string::npos) + len = _size-pos; + + _size -= len; + + if (is_literal()) + clone(_size, _capacity, std::get(_begin)); + memmove(std::get(_begin).get()+pos+len, std::get(_begin).get(), len); + resize(_size); + + return *this; + } + + string& append(const char* str) { + eosio::check(str != nullptr, "eosio::string::append"); + insert(_size, str); + + return *this; + } + + string& append(const string& str) { + insert(_size, str); + return *this; + } + + string& operator+=(const char c) { + if (_capacity == 0) { + _size = 1; + _capacity = 2; + clone(1, _capacity, &c); + } + else if (_size == _capacity) { + _capacity = ++_size*2; + + const char* tmp{(is_literal()) ? std::get(_begin) : std::get(_begin).get()}; + clone(_size, _capacity, tmp); + std::get(_begin).get()[_size-1] = c; + } + else + std::get(_begin).get()[_size++] = c; + + return *this; + } + + string& operator+=(const char* rhs) { + append(rhs); + return *this; + } + + string& operator+=(const string& rhs) { + append(rhs); + return *this; + } + + inline void print() const { + const char* tmp{(is_literal()) ? std::get(_begin) : std::get(_begin).get()}; + internal_use_do_not_use::prints_l(tmp, _size); + } + + friend bool operator< (const string& lhs, const string& rhs); + friend bool operator> (const string& lhs, const string& rhs); + friend bool operator<=(const string& lhs, const string& rhs); + friend bool operator>=(const string& lhs, const string& rhs); + friend bool operator==(const string& lhs, const string& rhs); + friend bool operator!=(const string& lhs, const string& rhs); + + friend string operator+ (const string& lhs, const string& rhs); + + private: + using uptr = std::unique_ptr; + using sso_str = std::variant; + + size_t _size = 0; + size_t _capacity = 0; + sso_str _begin = nullptr; + + void clone(size_t size, size_t capacity, const char* str) { + _size = size; + _capacity = capacity; + + uptr begin{std::make_unique(capacity)}; + memcpy(begin.get(), str, size); + _begin = std::move(begin); + } + + constexpr bool is_literal() const { + return (std::holds_alternative(_begin)) ? true : false; + } + }; + + bool operator< (const string& lhs, const string& rhs) { + const char* beg_lhs{lhs.cbegin()}; const char* end_lhs{lhs.cend()}; + const char* beg_rhs{rhs.cbegin()}; const char* end_rhs{rhs.cend()}; + + for(; beg_lhs != end_lhs && beg_rhs != end_rhs; ++beg_lhs, ++beg_rhs) { + if (*beg_lhs < *beg_rhs) + return true; + if (*beg_rhs < *beg_lhs) + return false; + } + + return beg_lhs == end_lhs && beg_rhs != end_rhs; + } + + bool operator> (const string& lhs, const string& rhs) { + return (rhs < lhs); + } + + bool operator<=(const string& lhs, const string& rhs) { + return !(rhs < lhs); + } + + bool operator>=(const string& lhs, const string& rhs) { + return !(lhs < rhs); + } + + bool operator==(const string& lhs, const string& rhs) { + return !(lhs < rhs) && !(rhs < lhs); + } + + bool operator!=(const string& lhs, const string& rhs) { + return !(lhs == rhs); + } + + string operator+(const string& lhs, const string& rhs) { + string res{lhs}; + res += rhs; + return res; + } + + template + DataStream& operator<<(DataStream& ds, const string& str) { + ds << unsigned_int(str.size()); + if (str.size()) + ds.write(str.data(), str.size()); + return ds; + } + + template + DataStream& operator>>(DataStream& ds, string& str) { + std::vector tmp; + ds >> tmp; + str = (tmp.size()) ? string(tmp.data(), tmp.size()) : string(); + return ds; + } + +} // namespace eosio diff --git a/libraries/eosiolib/core/eosio/symbol.hpp b/libraries/eosiolib/core/eosio/symbol.hpp index 631a9272f1..e02c86ad07 100644 --- a/libraries/eosiolib/core/eosio/symbol.hpp +++ b/libraries/eosiolib/core/eosio/symbol.hpp @@ -393,14 +393,14 @@ namespace eosio { * @param sym - The symbol * @param con - The name of the contract */ - constexpr extended_symbol( symbol sym, name con ) : symbol(sym), contract(con) {} + constexpr extended_symbol( symbol s, name con ) : sym(s), contract(con) {} /** * Returns the symbol in the extended_contract * * @return symbol */ - constexpr symbol get_symbol() const { return symbol; } + constexpr symbol get_symbol() const { return sym; } /** * Returns the name of the contract in the extended_symbol @@ -415,7 +415,7 @@ namespace eosio { * @brief %Print the extended symbol */ void print( bool show_precision = true )const { - symbol.print( show_precision ); + sym.print( show_precision ); ::eosio::print("@", contract); } @@ -425,7 +425,7 @@ namespace eosio { * @return boolean - true if both provided extended_symbols are the same */ friend constexpr bool operator == ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) == std::tie( b.symbol, b.contract ); + return std::tie( a.sym, a.contract ) == std::tie( b.sym, b.contract ); } /** @@ -434,7 +434,7 @@ namespace eosio { * @return boolean - true if both provided extended_symbols are not the same */ friend constexpr bool operator != ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) != std::tie( b.symbol, b.contract ); + return std::tie( a.sym, a.contract ) != std::tie( b.sym, b.contract ); } /** @@ -443,13 +443,13 @@ namespace eosio { * @return boolean - true if extended_symbol `a` is less than `b` */ friend constexpr bool operator < ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) < std::tie( b.symbol, b.contract ); + return std::tie( a.sym, a.contract ) < std::tie( b.sym, b.contract ); } private: - symbol symbol; ///< the symbol + symbol sym; ///< the symbol name contract; ///< the token contract hosting the symbol - EOSLIB_SERIALIZE( extended_symbol, (symbol)(contract) ) + EOSLIB_SERIALIZE( extended_symbol, (sym)(contract) ) }; } diff --git a/libraries/eosiolib/core/eosio/time.hpp b/libraries/eosiolib/core/eosio/time.hpp index 20b714fd05..9bdc0ad10d 100644 --- a/libraries/eosiolib/core/eosio/time.hpp +++ b/libraries/eosiolib/core/eosio/time.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "check.hpp" #include "serialize.hpp" namespace eosio { diff --git a/libraries/eosiolib/crypto.cpp b/libraries/eosiolib/crypto.cpp index fa6265ea42..6df7d145ae 100644 --- a/libraries/eosiolib/crypto.cpp +++ b/libraries/eosiolib/crypto.cpp @@ -14,7 +14,7 @@ extern "C" { __attribute__((eosio_wasm_import)) void assert_sha1( const char* data, uint32_t length, const capi_checksum160* hash ); - + __attribute__((eosio_wasm_import)) void assert_sha512( const char* data, uint32_t length, const capi_checksum512* hash ); @@ -34,11 +34,11 @@ extern "C" { void ripemd160( const char* data, uint32_t length, capi_checksum160* hash ); __attribute__((eosio_wasm_import)) - int recover_key( const capi_checksum256* digest, const char* sig, + int recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ); __attribute__((eosio_wasm_import)) - void assert_recover_key( const capi_checksum256* digest, const char* sig, + void assert_recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ); } @@ -92,37 +92,43 @@ namespace eosio { eosio::public_key recover_key( const eosio::checksum256& digest, const eosio::signature& sig ) { auto digest_data = digest.extract_as_byte_array(); - char sig_data[70]; - eosio::datastream sig_ds( sig_data, sizeof(sig_data) ); - auto sig_begin = sig_ds.pos(); - sig_ds << sig; + auto sig_data = eosio::pack(sig); - char pubkey_data[38]; + char optimistic_pubkey_data[256]; size_t pubkey_size = ::recover_key( reinterpret_cast(digest_data.data()), - sig_begin, (sig_ds.pos() - sig_begin), - pubkey_data, sizeof(pubkey_data) ); - eosio::datastream pubkey_ds( pubkey_data, pubkey_size ); + sig_data.data(), sig_data.size(), + optimistic_pubkey_data, sizeof(optimistic_pubkey_data) ); + eosio::public_key pubkey; - pubkey_ds >> pubkey; + if ( pubkey_size <= sizeof(optimistic_pubkey_data) ) { + eosio::datastream pubkey_ds( optimistic_pubkey_data, pubkey_size ); + pubkey_ds >> pubkey; + } else { + constexpr static size_t max_stack_buffer_size = 512; + void* pubkey_data = (max_stack_buffer_size < pubkey_size) ? malloc(pubkey_size) : alloca(pubkey_size); + + ::recover_key( reinterpret_cast(digest_data.data()), + sig_data.data(), sig_data.size(), + reinterpret_cast(pubkey_data), pubkey_size ); + eosio::datastream pubkey_ds( reinterpret_cast(pubkey_data), pubkey_size ); + pubkey_ds >> pubkey; + + if( max_stack_buffer_size < pubkey_size ) { + free(pubkey_data); + } + } return pubkey; } void assert_recover_key( const eosio::checksum256& digest, const eosio::signature& sig, const eosio::public_key& pubkey ) { auto digest_data = digest.extract_as_byte_array(); - char sig_data[70]; - eosio::datastream sig_ds( sig_data, sizeof(sig_data) ); - auto sig_begin = sig_ds.pos(); - sig_ds << sig; - - char pubkey_data[38]; - eosio::datastream pubkey_ds( pubkey_data, sizeof(pubkey_data) ); - auto pubkey_begin = pubkey_ds.pos(); - pubkey_ds << pubkey; + auto sig_data = eosio::pack(sig); + auto pubkey_data = eosio::pack(pubkey); ::assert_recover_key( reinterpret_cast(digest_data.data()), - sig_begin, (sig_ds.pos() - sig_begin), - pubkey_begin, (pubkey_ds.pos() - pubkey_begin) ); + sig_data.data(), sig_data.size(), + pubkey_data.data(), pubkey_data.size() ); } } diff --git a/libraries/eosiolib/crypto.h b/libraries/eosiolib/crypto.h deleted file mode 100644 index 30b78e12a9..0000000000 --- a/libraries/eosiolib/crypto.h +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "types.h" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -/** - * @addtogroup crypto Crypto - * @brief Defines %C API for calculating and checking hash - * @{ - */ - -extern "C" { - -/** - * Tests if the sha256 hash generated from data matches the provided checksum. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `capi_checksum256*` hash to compare to - * - * @pre **assert256 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * @note This method is optimized to a NO-OP when in fast evaluation mode. - * - * Example: - * - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_sha256( data, length, hash ) - * //If the sha256 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("sha256 hash generated from data equals provided hash"); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void assert_sha256( const char* data, uint32_t length, const capi_checksum256* hash ); - -/** - * Tests if the sha1 hash generated from data matches the provided checksum. - * - * @note This method is optimized to a NO-OP when in fast evaluation mode. - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `capi_checksum160*` hash to compare to - * - * @pre **sha1 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_sha1( data, length, hash ) - * //If the sha1 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("sha1 hash generated from data equals provided hash"); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void assert_sha1( const char* data, uint32_t length, const capi_checksum160* hash ); - -/** - * Tests if the sha512 hash generated from data matches the provided checksum. - * - * @note This method is optimized to a NO-OP when in fast evaluation mode. - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `capi_checksum512*` hash to compare to - * - * @pre **assert512 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_sha512( data, length, hash ) - * //If the sha512 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("sha512 hash generated from data equals provided hash"); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void assert_sha512( const char* data, uint32_t length, const capi_checksum512* hash ); - -/** - * Tests if the ripemod160 hash generated from data matches the provided checksum. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `capi_checksum160*` hash to compare to - * - * @pre **assert160 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_ripemod160( data, length, hash ) - * //If the ripemod160 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("ripemod160 hash generated from data equals provided hash"); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void assert_ripemd160( const char* data, uint32_t length, const capi_checksum160* hash ); - -/** - * Hashes `data` using `sha256` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * sha256( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void sha256( const char* data, uint32_t length, capi_checksum256* hash ); - -/** - * Hashes `data` using `sha1` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * sha1( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void sha1( const char* data, uint32_t length, capi_checksum160* hash ); - -/** - * Hashes `data` using `sha512` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * sha512( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void sha512( const char* data, uint32_t length, capi_checksum512* hash ); - -/** - * Hashes `data` using `ripemod160` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * ripemod160( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void ripemd160( const char* data, uint32_t length, capi_checksum160* hash ); - -/** - * Calculates the public key used for a given signature and hash used to create a message. - * - * @param digest - Hash used to create a message - * @param sig - Signature - * @param siglen - Signature length - * @param pub - Public key - * @param publen - Public key length -* @return int - number of bytes written to pub - * - * Example: -* - * @code - * @endcode - */ -__attribute__((eosio_wasm_import)) -int recover_key( const capi_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. - * - * @param digest - What the key will be generated from - * @param sig - Signature - * @param siglen - Signature length - * @param pub - Public key - * @param publen - Public key length - * - * @pre **assert recovery key** of `pub` equals the key generated from the `digest` parameter - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum digest; - * char sig; - * size_t siglen; - * char pub; - * size_t publen; - * assert_recover_key( digest, sig, siglen, pub, publen ) - * // If the given public key does not match with the generated key from digest and the signature, anything below will never fire. - * eosio::print("pub key matches the pub key generated from digest"); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void assert_recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ); - -/// @} - -} diff --git a/libraries/eosiolib/crypto.hpp b/libraries/eosiolib/crypto.hpp deleted file mode 100644 index 64f84e2d5b..0000000000 --- a/libraries/eosiolib/crypto.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "crypto.h" -#include "fixed_bytes.hpp" -#include "varint.hpp" -#include "serialize.hpp" - -#include - -#warning " is deprecated use " - -namespace eosio { - - /** - * @defgroup public_key Public Key Type - * @ingroup types - * @brief Specifies public key type - * - * @{ - */ - - /** - * EOSIO Public Key - * @brief EOSIO Public Key - */ - struct public_key { - /** - * Type of the public key, could be either K1 or R1 - * @brief Type of the public key - */ - unsigned_int type; - - /** - * Bytes of the public key - * - * @brief Bytes of the public key - */ - std::array data; - - friend bool operator == ( const public_key& a, const public_key& b ) { - return std::tie(a.type,a.data) == std::tie(b.type,b.data); - } - friend bool operator != ( const public_key& a, const public_key& b ) { - return std::tie(a.type,a.data) != std::tie(b.type,b.data); - } - EOSLIB_SERIALIZE( public_key, (type)(data) ) - }; - - /// @} publickeytype - - /** - * @defgroup signature Signature type - * @ingroup types - * @brief Specifies signature type - * - * @{ - */ - - /** - * EOSIO Signature - * @brief EOSIO Signature - */ - struct signature { - /** - * Type of the signature, could be either K1 or R1 - * @brief Type of the signature - */ - unsigned_int type; - - /** - * Bytes of the signature - * - * @brief Bytes of the signature - */ - std::array data; - - friend bool operator == ( const signature& a, const signature& b ) { - return std::tie(a.type,a.data) == std::tie(b.type,b.data); - } - friend bool operator != ( const signature& a, const signature& b ) { - return std::tie(a.type,a.data) != std::tie(b.type,b.data); - } - EOSLIB_SERIALIZE( signature, (type)(data) ) - }; - - /// @} signaturetype - - /** - * @defgroup crypto Chain API - * @ingroup core - * @brief Defines API for calculating and checking hashes - * @{ - */ - - /** - * Tests if the SHA256 hash generated from data matches the provided digest. - * This method is optimized to a NO-OP when in fast evaluation mode. - * @brief Tests if the sha256 hash generated from data matches the provided digest. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - digest to compare to - */ - void assert_sha256( const char* data, uint32_t length, const eosio::checksum256& hash ); - - /** - * Tests if the SHA1 hash generated from data matches the provided digest. - * This method is optimized to a NO-OP when in fast evaluation mode. - * @brief Tests if the sha1 hash generated from data matches the provided digest. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - digest to compare to - */ - void assert_sha1( const char* data, uint32_t length, const eosio::checksum160& hash ); - - /** - * Tests if the SHA512 hash generated from data matches the provided digest. - * This method is optimized to a NO-OP when in fast evaluation mode. - * @brief Tests if the sha512 hash generated from data matches the provided digest. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - digest to compare to - */ - void assert_sha512( const char* data, uint32_t length, const eosio::checksum512& hash ); - - /** - * Tests if the RIPEMD160 hash generated from data matches the provided digest. - * @brief Tests if the ripemd160 hash generated from data matches the provided digest. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - digest to compare to - */ - void assert_ripemd160( const char* data, uint32_t length, const eosio::checksum160& hash ); - - /** - * Hashes `data` using SHA256. - * @brief Hashes `data` using SHA256. - * - * @param data - Data you want to hash - * @param length - Data length - * @return eosio::checksum256 - Computed digest - */ - eosio::checksum256 sha256( const char* data, uint32_t length ); - - /** - * Hashes `data` using SHA1. - * @brief Hashes `data` using SHA1. - * - * @param data - Data you want to hash - * @param length - Data length - * @return eosio::checksum160 - Computed digest - */ - eosio::checksum160 sha1( const char* data, uint32_t length ); - - /** - * Hashes `data` using SHA512. - * @brief Hashes `data` using SHA512. - * - * @param data - Data you want to hash - * @param length - Data length - * @return eosio::checksum512 - Computed digest - */ - eosio::checksum512 sha512( const char* data, uint32_t length ); - - /** - * Hashes `data` using RIPEMD160. - * @brief Hashes `data` using RIPEMD160. - * - * @param data - Data you want to hash - * @param length - Data length - * @return eosio::checksum160 - Computed digest - */ - eosio::checksum160 ripemd160( const char* data, uint32_t length ); - - /** - * Calculates the public key used for a given signature on a given digest. - * @brief Calculates the public key used for a given signature on a given digest. - * - * @param digest - Digest of the message that was signed - * @param sig - Signature - * @return eosio::public_key - Recovered public key - */ - eosio::public_key recover_key( const eosio::checksum256& digest, const eosio::signature& sig ); - - /** - * Tests a given public key with the recovered public key from digest and signature. - * @brief Tests a given public key with the recovered public key from digest and signature. - * - * @param digest - Digest of the message that was signed - * @param sig - Signature - * @param pubkey - Public key - */ - void assert_recover_key( const eosio::checksum256& digest, const eosio::signature& sig, const eosio::public_key& pubkey ); - - /// }@cryptoapi -} diff --git a/libraries/eosiolib/datastream.hpp b/libraries/eosiolib/datastream.hpp deleted file mode 100644 index b49aec80fd..0000000000 --- a/libraries/eosiolib/datastream.hpp +++ /dev/null @@ -1,1421 +0,0 @@ -/** - * @file datastream.hpp - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "types.h" -#include "symbol.hpp" -#include "fixed_bytes.hpp" -#include "crypto.hpp" -#include "ignore.hpp" -#include "varint.hpp" -#include "binary_extension.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#warning " is deprecated use " - -namespace eosio { - -/** - * A data stream for reading and writing data in the form of bytes - * - * @tparam T - Type of the datastream buffer - */ -template -class datastream { - public: - /** - * @brief Construct a new datastream object - * - * @details Construct a new datastream object given the size of the buffer and start position of the buffer - * @param start - The start position of the buffer - * @param s - The size of the buffer - */ - datastream( T start, size_t s ) - :_start(start),_pos(start),_end(start+s){} - - /** - * Skips a specified number of bytes from this stream - * - * @param s - The number of bytes to skip - */ - inline void skip( size_t s ){ _pos += s; } - - /** - * Reads a specified number of bytes from the stream into a buffer - * - * @param d - The pointer to the destination buffer - * @param s - the number of bytes to read - * @return true - */ - inline bool read( char* d, size_t s ) { - eosio::check( size_t(_end - _pos) >= (size_t)s, "read" ); - memcpy( d, _pos, s ); - _pos += s; - return true; - } - - /** - * Writes a specified number of bytes into the stream from a buffer - * - * @param d - The pointer to the source buffer - * @param s - The number of bytes to write - * @return true - */ - inline bool write( const char* d, size_t s ) { - eosio::check( _end - _pos >= (int32_t)s, "write" ); - memcpy( (void*)_pos, d, s ); - _pos += s; - return true; - } - - /** - * Writes a byte into the stream - * - * @brief Writes a byte into the stream - * @param c byte to write - * @return true - */ - inline bool put(char c) { - eosio::check( _pos < _end, "put" ); - *_pos = c; - ++_pos; - return true; - } - - /** - * Reads a byte from the stream - * - * @brief Reads a byte from the stream - * @param c - The reference to destination byte - * @return true - */ - inline bool get( unsigned char& c ) { return get( *(char*)&c ); } - - /** - * Reads a byte from the stream - * - * @brief Reads a byte from the stream - * @param c - The reference to destination byte - * @return true - */ - inline bool get( char& c ) - { - eosio::check( _pos < _end, "get" ); - c = *_pos; - ++_pos; - return true; - } - - /** - * Retrieves the current position of the stream - * - * @brief Retrieves the current position of the stream - * @return T - The current position of the stream - */ - T pos()const { return _pos; } - inline bool valid()const { return _pos <= _end && _pos >= _start; } - - /** - * Sets the position within the current stream - * - * @brief Sets the position within the current stream - * @param p - The offset relative to the origin - * @return true if p is within the range - * @return false if p is not within the rawnge - */ - inline bool seekp(size_t p) { _pos = _start + p; return _pos <= _end; } - - /** - * Gets the position within the current stream - * - * @brief Gets the position within the current stream - * @return p - The position within the current stream - */ - inline size_t tellp()const { return size_t(_pos - _start); } - - /** - * Returns the number of remaining bytes that can be read/skipped - * - * @brief Returns the number of remaining bytes that can be read/skipped - * @return size_t - The number of remaining bytes - */ - inline size_t remaining()const { return _end - _pos; } - private: - /** - * The start position of the buffer - * - * @brief The start position of the buffer - */ - T _start; - /** - * The current position of the buffer - * - * @brief The current position of the buffer - */ - T _pos; - /** - * The end position of the buffer - * - * @brief The end position of the buffer - */ - T _end; -}; - -/** - * @brief Specialization of datastream used to help determine the final size of a serialized value. - * Specialization of datastream used to help determine the final size of a serialized value - */ -template<> -class datastream { - public: - /** - * Construct a new specialized datastream object given the initial size - * - * @brief Construct a new specialized datastream object - * @param init_size - The initial size - */ - datastream( size_t init_size = 0):_size(init_size){} - - /** - * Increment the size by s. This behaves the same as write( const char* ,size_t s ). - * - * @brief Increase the size by s - * @param s - The amount of size to increase - * @return true - */ - inline bool skip( size_t s ) { _size += s; return true; } - - /** - * Increment the size by s. This behaves the same as skip( size_t s ) - * - * @brief Increase the size by s - * @param s - The amount of size to increase - * @return true - */ - inline bool write( const char* ,size_t s ) { _size += s; return true; } - - /** - * Increment the size by one - * - * @brief Increase the size by one - * @return true - */ - inline bool put(char ) { ++_size; return true; } - - /** - * Check validity. It's always valid - * - * @brief Check validity - * @return true - */ - inline bool valid()const { return true; } - - /** - * Set new size - * - * @brief Set new size - * @param p - The new size - * @return true - */ - inline bool seekp(size_t p) { _size = p; return true; } - - /** - * Get the size - * - * @brief Get the size - * @return size_t - The size - */ - inline size_t tellp()const { return _size; } - - /** - * Always returns 0 - * - * @brief Always returns 0 - * @return size_t - 0 - */ - inline size_t remaining()const { return 0; } - private: - /** - * The size used to determine the final size of a serialized value. - * - * @brief The size used to determine the final size of a serialized value. - */ - size_t _size; -}; - -/** - * Serialize an std::list into a stream - * - * @brief Serialize an std::list - * @param ds - The stream to write - * @param opt - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const std::list& l) { - ds << unsigned_int( l.size() ); - for ( auto elem : l ) - ds << elem; - return ds; -} - -/** - * Deserialize an std::list from a stream - * - * @brief Deserialize an std::list - * @param ds - The stream to read - * @param opt - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, std::list& l) { - unsigned_int s; - ds >> s; - l.resize(s.value); - for( auto& i : l ) - ds >> i; - return ds; -} - -/** - * Serialize an std::deque into a stream - * - * @brief Serialize an std::queue - * @param ds - The stream to write - * @param opt - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const std::deque& d) { - ds << unsigned_int( d.size() ); - for ( auto elem : d ) - ds << elem; - return ds; -} - -/** - * Deserialize an std::deque from a stream - * - * @brief Deserialize an std::deque - * @param ds - The stream to read - * @param opt - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, std::deque& d) { - unsigned_int s; - ds >> s; - d.resize(s.value); - for( auto& i : d ) - ds >> i; - return ds; -} - -/** - * Serialize an std::variant into a stream - * - * @brief Serialize an std::variant - * @param ds - The stream to write - * @param opt - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const std::variant& var) { - unsigned_int index = var.index(); - ds << index; - std::visit([&ds](auto& val){ ds << val; }, var); - return ds; -} - -template -void deserialize(datastream& ds, std::variant& var, int i) { - if constexpr (I < std::variant_size_v>) { - if (i == I) { - std::variant_alternative_t> tmp; - ds >> tmp; - var = std::move(tmp); - } else { - deserialize(ds,var,i); - } - } else { - eosio::check(false, "invalid variant index"); - } -} - -/** - * Deserialize an std::variant from a stream - * - * @brief Deserialize an std::variant - * @param ds - The stream to read - * @param opt - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, std::variant& var) { - unsigned_int index; - ds >> index; - deserialize<0>(ds,var,index); - return ds; -} - -/** - * Serialize an std::pair - * - * @brief Serialize an std::pair - * @param ds - The stream to write - * @param t - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator<<( DataStream& ds, const std::pair& t ) { - ds << std::get<0>(t); - ds << std::get<1>(t); - return ds; -} - -/** - * Deserialize an std::pair - * - * @brief Deserialize an std::pair - * @param ds - The stream to read - * @param t - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator>>( DataStream& ds, std::pair& t ) { - T1 t1; - T2 t2; - ds >> t1; - ds >> t2; - t = std::pair{t1, t2}; - return ds; -} - -/** - * Serialize an optional into a stream - * - * @brief Serialize an optional - * @param ds - The stream to write - * @param opt - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const std::optional& opt) { - char valid = opt.has_value(); - ds << valid; - if (valid) - ds << *opt; - return ds; -} - -/** - * Deserialize an optional from a stream - * - * @brief Deserialize an optional - * @param ds - The stream to read - * @param opt - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, std::optional& opt) { - char valid = 0; - ds >> valid; - if (valid) { - T val; - ds >> val; - opt = val; - } - return ds; -} - -/** - * Serialize a symbol into a stream - * - * @brief Serialize a symbol - * @param ds - The stream to write - * @param sym - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const eosio::symbol sym) { - uint64_t raw = sym.raw(); - ds.write( (const char*)&raw, sizeof(raw)); - return ds; -} - -/** - * Deserialize a symbol from a stream - * - * @brief Deserialize a symbol - * @param ds - The stream to read - * @param symbol - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, eosio::symbol& sym) { - uint64_t raw = 0; - ds.read((char*)&raw, sizeof(raw)); - sym = symbol(raw); - return ds; -} - -/** - * Serialize an ignored_wrapper type into a stream - * - * @brief Serialize ignored_wrapper's T value - * @param ds - The stream to write - * @param val - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const ::eosio::ignore_wrapper& val) { - ds << val.value; - return ds; -} - -/** - * Serialize an ignored type into a stream - * - * @brief Serialize an ignored type - * @param ds - The stream to write - * @param ignore - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const ::eosio::ignore& val) { - return ds; -} - -/** - * Deserialize an ignored type from a stream - * - * @brief Deserialize an ignored type - * @param ds - The stream to read - * @param ignored - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, ::eosio::ignore) { - return ds; -} - -/** - * Serialize a public_key into a stream - * - * @brief Serialize a public_key - * @param ds - The stream to write - * @param pubkey - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const capi_public_key& pubkey) { - ds.write( (const char*)&pubkey, sizeof(pubkey)); - return ds; -} - -/** - * Deserialize a public_key from a stream - * - * @brief Deserialize a public_key - * @param ds - The stream to read - * @param pubkey - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, capi_public_key& pubkey) { - ds.read((char*)&pubkey, sizeof(pubkey)); - return ds; -} - -/** - * Serialize an eosio::public_key into a stream - * - * @brief Serialize an eosio::public_key - * @param ds - The stream to write - * @param pubkey - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const eosio::public_key& pubkey) { - ds << pubkey.type; - ds.write( pubkey.data.data(), pubkey.data.size() ); - return ds; -} - -/** - * Deserialize an eosio::public_key from a stream - * - * @brief Deserialize an eosio::public_key - * @param ds - The stream to read - * @param pubkey - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, eosio::public_key& pubkey) { - ds >> pubkey.type; - ds.read( pubkey.data.data(), pubkey.data.size() ); - return ds; -} - -/** - * Serialize an eosio::signature into a stream - * - * @brief Serialize an eosio::signature - * @param ds - The stream to write - * @param sig - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const eosio::signature& sig) { - ds << sig.type; - ds.write( sig.data.data(), sig.data.size() ); - return ds; -} - -/** - * Deserialize an eosio::signature from a stream - * - * @brief Deserialize an eosio::signature - * @param ds - The stream to read - * @param sig - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, eosio::signature& sig) { - ds >> sig.type; - ds.read( sig.data.data(), sig.data.size() ); - return ds; -} - -/** - * Serialize a fixed_bytes into a stream - * - * @brief Serialize a fixed_bytes - * @param ds - The stream to write - * @param d - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const fixed_bytes& d) { - auto arr = d.extract_as_byte_array(); - ds.write( (const char*)arr.data(), arr.size() ); - return ds; -} - -/** - * Deserialize a fixed_bytes from a stream - * - * @brief Deserialize a fixed_bytes - * @param ds - The stream to read - * @param d - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, fixed_bytes& d) { - std::array arr; - ds.read( (char*)arr.data(), arr.size() ); - d = fixed_bytes( arr ); - return ds; -} - -/** - * Serialize a bool into a stream - * - * @brief Serialize a bool into a stream - * @param ds - The stream to read - * @param d - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const bool& d) { - return ds << uint8_t(d); -} - -/** - * Deserialize a bool from a stream - * - * @brief Deserialize a bool - * @param ds - The stream to read - * @param d - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, bool& d) { - uint8_t t; - ds >> t; - d = t; - return ds; -} - -/** - * Serialize a checksum256 into a stream - * - * @brief Serialize a checksum256 - * @param ds - The stream to write - * @param d - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const capi_checksum256& d) { - ds.write( (const char*)&d.hash[0], sizeof(d.hash) ); - return ds; -} - -/** - * Deserialize a checksum256 from a stream - * - * @brief Deserialize a checksum256 - * @param ds - The stream to read - * @param d - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, capi_checksum256& d) { - ds.read((char*)&d.hash[0], sizeof(d.hash) ); - return ds; -} - -/** - * Serialize a string into a stream - * - * @brief Serialize a string - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::string& v ) { - ds << unsigned_int( v.size() ); - if (v.size()) - ds.write(v.data(), v.size()); - return ds; -} - -/** - * Deserialize a string from a stream - * - * @brief Deserialize a string - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::string& v ) { - std::vector tmp; - ds >> tmp; - if( tmp.size() ) - v = std::string(tmp.data(),tmp.data()+tmp.size()); - else - v = std::string(); - return ds; -} - -/** - * Serialize a fixed size std::array - * - * @brief Serialize a fixed size std::array - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::array& v ) { - for( const auto& i : v ) - ds << i; - return ds; -} - - -/** - * Deserialize a fixed size std::array - * - * @brief Deserialize a fixed size std::array - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::array& v ) { - for( auto& i : v ) - ds >> i; - return ds; -} - -namespace _datastream_detail { - /** - * Check if type T is a pointer - * - * @brief Check if type T is a pointer - * @tparam T - The type to be checked - * @return true if T is a pointer - * @return false otherwise - */ - template - constexpr bool is_pointer() { - return std::is_pointer::value || - std::is_null_pointer::value || - std::is_member_pointer::value; - } - - /** - * Check if type T is a primitive type - * - * @brief Check if type T is a primitive type - * @tparam T - The type to be checked - * @return true if T is a primitive type - * @return false otherwise - */ - template - constexpr bool is_primitive() { - return std::is_arithmetic::value || - std::is_enum::value; - } -} - -/** - * Pointer should not be serialized, so this function will always throws an error - * - * @brief Deserialize a a pointer - * @param ds - The stream to read - * @tparam DataStream - Type of datastream - * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream - * @post Throw an exception if it is a pointer - */ -template()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T ) { - static_assert(!_datastream_detail::is_pointer(), "Pointers should not be serialized" ); - return ds; -} - -/** - * Serialize a fixed size C array of non-primitive and non-pointer type - * - * @brief Serialize a fixed size C array of non-primitive and non-pointer type - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream - */ -template() && - !_datastream_detail::is_pointer()>* = nullptr> -DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { - ds << unsigned_int( N ); - for( uint32_t i = 0; i < N; ++i ) - ds << v[i]; - return ds; -} - -/** - * Serialize a fixed size C array of primitive type - * - * @brief Serialize a fixed size C array of primitive type - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { - ds << unsigned_int( N ); - ds.write((char*)&v[0], sizeof(v)); - return ds; -} - -/** - * Deserialize a fixed size C array of non-primitive and non-pointer type - * - * @brief Deserialize a fixed size C array of non-primitive and non-pointer type - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template() && - !_datastream_detail::is_pointer()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { - unsigned_int s; - ds >> s; - eosio::check( N == s.value, "T[] size and unpacked size don't match"); - for( uint32_t i = 0; i < N; ++i ) - ds >> v[i]; - return ds; -} - -/** - * Deserialize a fixed size C array of primitive type - * - * @brief Deserialize a fixed size C array of primitive type - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { - unsigned_int s; - ds >> s; - eosio::check( N == s.value, "T[] size and unpacked size don't match"); - ds.read((char*)&v[0], sizeof(v)); - return ds; -} - -/** - * Serialize a vector of char - * - * @brief Serialize a vector of char - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::vector& v ) { - ds << unsigned_int( v.size() ); - ds.write( v.data(), v.size() ); - return ds; -} - -/** - * Serialize a vector - * - * @brief Serialize a vector - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the vector - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::vector& v ) { - ds << unsigned_int( v.size() ); - for( const auto& i : v ) - ds << i; - return ds; -} - -/** - * Deserialize a vector of char - * - * @brief Deserialize a vector of char - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::vector& v ) { - unsigned_int s; - ds >> s; - v.resize( s.value ); - ds.read( v.data(), v.size() ); - return ds; -} - -/** - * Deserialize a vector - * - * @brief Deserialize a vector - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the vector - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::vector& v ) { - unsigned_int s; - ds >> s; - v.resize(s.value); - for( auto& i : v ) - ds >> i; - return ds; -} - -/** - * Serialize a set - * - * @brief Serialize a set - * @param ds - The stream to write - * @param s - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the set - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::set& s ) { - ds << unsigned_int( s.size() ); - for( const auto& i : s ) { - ds << i; - } - return ds; -} - - -/** - * Deserialize a set - * - * @brief Deserialize a set - * @param ds - The stream to read - * @param s - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the set - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::set& s ) { - s.clear(); - unsigned_int sz; ds >> sz; - - for( uint32_t i = 0; i < sz.value; ++i ) { - T v; - ds >> v; - s.emplace( std::move(v) ); - } - return ds; -} - -/** - * Serialize a map - * - * @brief Serialize a map - * @param ds - The stream to write - * @param m - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the map - * @tparam V - Type of the value contained in the map - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::map& m ) { - ds << unsigned_int( m.size() ); - for( const auto& i : m ) { - ds << i.first << i.second; - } - return ds; -} - -/** - * Deserialize a map - * - * @brief Deserialize a map - * @param ds - The stream to read - * @param m - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the map - * @tparam V - Type of the value contained in the map - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::map& m ) { - m.clear(); - unsigned_int s; ds >> s; - - for (uint32_t i = 0; i < s.value; ++i) { - K k; V v; - ds >> k >> v; - m.emplace( std::move(k), std::move(v) ); - } - return ds; -} - - -/** - * Serialize a flat_set - * - * @brief Serialize a flat_set - * @param ds - The stream to write - * @param s - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the value contained in the flat_set - * @return DataStream& - Reference to the datastream - */ -template -[[ deprecated ]] -DataStream& operator << ( DataStream& ds, const boost::container::flat_set& s ) { - ds << unsigned_int( s.size() ); - for( const auto& i : s ) { - ds << i; - } - return ds; -} - -/** - * Deserialize a flat_set - * - * @brief Deserialize a flat_set - * @param ds - The stream to read - * @param s - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the value contained in the flat_set - * @return DataStream& - Reference to the datastream - */ -template -[[ deprecated ]] -DataStream& operator >> ( DataStream& ds, boost::container::flat_set& s ) { - s.clear(); - unsigned_int sz; ds >> sz; - - for( uint32_t i = 0; i < sz.value; ++i ) { - T v; - ds >> v; - s.emplace( std::move(v) ); - } - return ds; -} - - -/** - * Serialize a flat map - * - * @brief Serialize a flat map - * @param ds - The stream to write - * @param m - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the flat map - * @tparam V - Type of the value contained in the flat map - * @return DataStream& - Reference to the datastream - */ -template -[[ deprecated ]] -DataStream& operator<<( DataStream& ds, const boost::container::flat_map& m ) { - ds << unsigned_int( m.size() ); - for( const auto& i : m ) - ds << i.first << i.second; - return ds; -} - -/** - * Deserialize a flat map - * - * @brief Deserialize a flat map - * @param ds - The stream to read - * @param m - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the flat map - * @tparam V - Type of the value contained in the flat map - * @return DataStream& - Reference to the datastream - */ -template -[[ deprecated ]] -DataStream& operator>>( DataStream& ds, boost::container::flat_map& m ) { - m.clear(); - unsigned_int s; ds >> s; - - for( uint32_t i = 0; i < s.value; ++i ) { - K k; V v; - ds >> k >> v; - m.emplace( std::move(k), std::move(v) ); - } - return ds; -} - -/** - * Serialize a tuple - * - * @brief Serialize a tuple - * @param ds - The stream to write - * @param t - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator<<( DataStream& ds, const std::tuple& t ) { - boost::fusion::for_each( t, [&]( const auto& i ) { - ds << i; - }); - return ds; -} - -/** - * Deserialize a tuple - * - * @brief Deserialize a tuple - * @param ds - The stream to read - * @param t - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator>>( DataStream& ds, std::tuple& t ) { - boost::fusion::for_each( t, [&]( auto& i ) { - ds >> i; - }); - return ds; -} - -/** - * Serialize a class - * - * @brief Serialize a class - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of class - * @return DataStream& - Reference to the datastream - */ -template::value>* = nullptr> -DataStream& operator<<( DataStream& ds, const T& v ) { - boost::pfr::for_each_field(v, [&](const auto& field) { - ds << field; - }); - return ds; -} - -/** - * Deserialize a class - * - * @brief Deserialize a class - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of class - * @return DataStream& - Reference to the datastream - */ -template::value>* = nullptr> -DataStream& operator>>( DataStream& ds, T& v ) { - boost::pfr::for_each_field(v, [&](auto& field) { - ds >> field; - }); - return ds; -} - -/** - * Serialize a primitive type - * - * @brief Serialize a primitive type - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the primitive type - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator<<( DataStream& ds, const T& v ) { - ds.write( (const char*)&v, sizeof(T) ); - return ds; -} - -/** - * Deserialize a primitive type - * - * @brief Deserialize a primitive type - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the primitive type - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator>>( DataStream& ds, T& v ) { - ds.read( (char*)&v, sizeof(T) ); - return ds; -} - -/** - * Defines data stream for reading and writing data in the form of bytes - * - * @addtogroup datastream Data Stream - * @ingroup core - * @{ - */ - -/** - * Unpack data inside a fixed size buffer as T - * - * @brief Unpack data inside a fixed size buffer as T - * @tparam T - Type of the unpacked data - * @param buffer - Pointer to the buffer - * @param len - Length of the buffer - * @return T - The unpacked data - */ -template -T unpack( const char* buffer, size_t len ) { - T result; - datastream ds(buffer,len); - ds >> result; - return result; -} - -/** - * Unpack data inside a variable size buffer as T - * - * @brief Unpack data inside a variable size buffer as T - * @tparam T - Type of the unpacked data - * @param bytes - Buffer - * @return T - The unpacked data - */ -template -T unpack( const std::vector& bytes ) { - return unpack( bytes.data(), bytes.size() ); -} - -/** - * Get the size of the packed data - * - * @brief Get the size of the packed data - * @tparam T - Type of the data to be packed - * @param value - Data to be packed - * @return size_t - Size of the packed data - */ -template -size_t pack_size( const T& value ) { - datastream ps; - ps << value; - return ps.tellp(); -} - -/** - * Get packed data - * - * @brief Get packed data - * @tparam T - Type of the data to be packed - * @param value - Data to be packed - * @return bytes - The packed data - */ -template -std::vector pack( const T& value ) { - std::vector result; - result.resize(pack_size(value)); - - datastream ds( result.data(), result.size() ); - ds << value; - return result; -} - -///@} - -/** - * Serialize a capi_checksum160 type - * - * @brief Serializea capi_checksum160 type - * @param ds - The stream to write - * @param cs - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const capi_checksum160& cs) { - ds.write((const char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -/** - * Deserialize a capi_checksum160 type - * - * @brief Deserialize a capi_checksum160 type - * @param ds - The stream to read - * @param cs - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, capi_checksum160& cs) { - ds.read((char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -/** - * Serialize a capi_checksum512 type - * - * @brief Serialize a capi_checksum512 type - * @param ds - The stream to write - * @param cs - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const capi_checksum512& cs) { - ds.write((const char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -/** - * Deserialize a capi_checksum512 type - * - * @brief Deserialize a capi_checksum512 type - * @param ds - The stream to read - * @param cs - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, capi_checksum512& cs) { - ds.read((char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -///@} - - - -} diff --git a/libraries/eosiolib/db.h b/libraries/eosiolib/db.h deleted file mode 100644 index 9e5a9f9f20..0000000000 --- a/libraries/eosiolib/db.h +++ /dev/null @@ -1,985 +0,0 @@ -/** - * @file db.h - * @copyright defined in eos/LICENSE - * @brief Defines C API for interfacing with blockchain database - */ -#pragma once -#include - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -/** - * @addtogroup database_c_api Database C API - * @ingroup c_api - * @brief Defines %C APIs for interfacing with the database. - * @details Database C API provides low level interface to EOSIO database. - * - * @section tabletypes Supported Table Types - * Following are the table types supported by the C API: - * 1. Primary Table - * - 64-bit integer key - * 2. Secondary Index Table - * - 64-bit integer key - * - 128-bit integer key - * - 256-bit integer key - * - double key - * - long double key - * @{ - */ -extern "C" { - - -/** - * - * Store a record in a primary 64-bit integer index table - * - * @brief Store a record in a primary 64-bit integer index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - ID of the entry - * @param data - Record to store - * @param len - Size of data - * @pre `data` is a valid pointer to a range of memory at least `len` bytes long - * @pre `*((uint64_t*)data)` stores the primary key - * @return iterator to the newly created table row - * @post a new entry is created in the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_store_i64(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const void* data, uint32_t len); - -/** - * - * Update a record in a primary 64-bit integer index table - * - * @brief Update a record in a primary 64-bit integer index table - * @param iterator - Iterator to the table row containing the record to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param data - New updated record - * @param len - Size of data - * @pre `data` is a valid pointer to a range of memory at least `len` bytes long - * @pre `*((uint64_t*)data)` stores the primary key - * @pre `iterator` points to an existing table row in the table - * @post the record contained in the table row pointed to by `iterator` is replaced with the new updated record - */ -__attribute__((eosio_wasm_import)) -void db_update_i64(int32_t iterator, capi_name payer, const void* data, uint32_t len); - -/** - * - * Remove a record from a primary 64-bit integer index table - * - * @brief Remove a record from a primary 64-bit integer index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - * - * Example: - * - * @code - * int32_t itr = db_find_i64(receiver, receiver, table1, "alice"_n); - * eosio_assert(itr >= 0, "Alice cannot be removed since she was already not found in the table"); - * db_remove_i64(itr); - * @endcode - */ -__attribute__((eosio_wasm_import)) -void db_remove_i64(int32_t iterator); - -/** - * - * Get a record in a primary 64-bit integer index table - * - * @brief Get a record in a primary 64-bit integer index table - * @param iterator - The iterator to the table row containing the record to retrieve - * @param data - Pointer to the buffer which will be filled with the retrieved record - * @param len - Size of the buffer - * @return size of the data copied into the buffer if `len > 0`, or size of the retrieved record if `len == 0`. - * @pre `iterator` points to an existing table row in the table - * @pre `data` is a valid pointer to a range of memory at least `len` bytes long - * @post `data` will be filled with the retrieved record (truncated to the first `len` bytes if necessary) - * - * Example: - * - * @code - * char value[50]; - * auto len = db_get_i64(itr, value, 0); - * eosio_assert(len <= 50, "buffer to small to store retrieved record"); - * db_get_i64(itr, value, len); - * @endcode - */ -__attribute__((eosio_wasm_import)) -int32_t db_get_i64(int32_t iterator, const void* data, uint32_t len); - -/** - * - * Find the table row following the referenced table row in a primary 64-bit integer index table - * - * @brief Find the table row following the referenced table row in a primary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - * - * Example: - * - * @code - * int32_t charlie_itr = db_find_i64(receiver, receiver, table1, "charlie"_n); - * // expect nothing after charlie - * uint64_t prim = 0 - * int32_t end_itr = db_next_i64(charlie_itr, &prim); - * eosio_assert(end_itr < -1, "Charlie was not the last entry in the table"); - * @endcode - */ -__attribute__((eosio_wasm_import)) -int32_t db_next_i64(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a primary 64-bit integer index table - * - * @brief Find the table row preceding the referenced table row in a primary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - * - * Example: - * - * @code - * uint64_t prim = 0; - * int32_t itr_prev = db_previous_i64(itr, &prim); - * @endcode - */ -__attribute__((eosio_wasm_import)) -int32_t db_previous_i64(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a primary 64-bit integer index table by primary key - * - * @brief Find a table row in a primary 64-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param id - The primary key of the table row to look up - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - * - * Example: - * - * @code - * int itr = db_find_i64(receiver, receiver, table1, "charlie"_n); - * @endcode - */ -__attribute__((eosio_wasm_import)) -int32_t db_find_i64(capi_name code, uint64_t scope, capi_name table, uint64_t id); - -/** - * - * Find the table row in a primary 64-bit integer index table that matches the lowerbound condition for a given primary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest primary key that is >= the given key - * - * @brief Find the table row in a primary 64-bit integer index table that matches the lowerbound condition for a given primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param id - The primary key used to determine the lowerbound - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_lowerbound_i64(capi_name code, uint64_t scope, capi_name table, uint64_t id); - -/** - * - * Find the table row in a primary 64-bit integer index table that matches the upperbound condition for a given primary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest primary key that is > the given key - * - * @brief Find the table row in a primary 64-bit integer index table that matches the upperbound condition for a given primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param id - The primary key used to determine the upperbound - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_upperbound_i64(capi_name code, uint64_t scope, capi_name table, uint64_t id); - -/** - * - * Get an iterator representing just-past-the-end of the last table row of a primary 64-bit integer index table - * - * @brief Get an iterator representing just-past-the-end of the last table row of a primary 64-bit integer index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_end_i64(capi_name code, uint64_t scope, capi_name table); - -/** - * - * Store an association of a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * - * @brief Store an association of a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary 64-bit integer index table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const uint64_t* secondary); - -/** - * - * Update an association for a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * - * @brief Update an association for a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -__attribute__((eosio_wasm_import)) -void db_idx64_update(int32_t iterator, capi_name payer, const uint64_t* secondary); - -/** - * - * Remove a table row from a secondary 64-bit integer index table - * - * @brief Remove a table row from a secondary 64-bit integer index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -__attribute__((eosio_wasm_import)) -void db_idx64_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary 64-bit integer index table - * - * @brief Find the table row following the referenced table row in a secondary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary 64-bit integer index table - * - * @brief Find the table row preceding the referenced table row in a secondary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary 64-bit integer index table by primary key - * - * @brief Find a table row in a secondary 64-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `uint64_t` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_find_primary(capi_name code, uint64_t scope, capi_name table, uint64_t* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary 64-bit integer index table by secondary key - * - * @brief Find a table row in a secondary 64-bit integer index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_find_secondary(capi_name code, uint64_t scope, capi_name table, const uint64_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 64-bit integer index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary 64-bit integer index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_lowerbound(capi_name code, uint64_t scope, capi_name table, uint64_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 64-bit integer index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary 64-bit integer index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_upperbound(capi_name code, uint64_t scope, capi_name table, uint64_t* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary 64-bit integer index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary 64-bit integer index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx64_end(capi_name code, uint64_t scope, capi_name table); - - - -/** - * - * Store an association of a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * - * @brief Store an association of a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary 128-bit integer index table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const uint128_t* secondary); - -/** - * - * Update an association for a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * - * @brief Update an association for a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -__attribute__((eosio_wasm_import)) -void db_idx128_update(int32_t iterator, capi_name payer, const uint128_t* secondary); - -/** - * - * Remove a table row from a secondary 128-bit integer index table - * - * @brief Remove a table row from a secondary 128-bit integer index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -__attribute__((eosio_wasm_import)) -void db_idx128_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary 128-bit integer index table - * - * @brief Find the table row following the referenced table row in a secondary 128-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary 128-bit integer index table - * - * @brief Find the table row preceding the referenced table row in a secondary 128-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary 128-bit integer index table by primary key - * - * @brief Find a table row in a secondary 128-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `uint128_t` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_find_primary(capi_name code, uint64_t scope, capi_name table, uint128_t* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary 128-bit integer index table by secondary key - * - * @brief Find a table row in a secondary 128-bit integer index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_find_secondary(capi_name code, uint64_t scope, capi_name table, const uint128_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 128-bit integer index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary 128-bit integer index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_lowerbound(capi_name code, uint64_t scope, capi_name table, uint128_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 128-bit integer index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary 128-bit integer index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_upperbound(capi_name code, uint64_t scope, capi_name table, uint128_t* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary 128-bit integer index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary 128-bit integer index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx128_end(capi_name code, uint64_t scope, capi_name table); - -/** - * - * Store an association of a 256-bit secondary key to a primary key in a secondary 256-bit index table - * - * @brief Store an association of a 256-bit secondary key to a primary key in a secondary 256-bit index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param data - Pointer to the secondary key data stored as an array of 2 `uint128_t` integers - * @param data_len - Must be set to 2 - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and the specified secondary key is created in the secondary 256-bit index table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const uint128_t* data, uint32_t data_len ); - -/** - * - * Update an association for a 256-bit secondary key to a primary key in a secondary 256-bit index table - * - * @brief Update an association for a 256-bit secondary key to a primary key in a secondary 256-bit index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param data - Pointer to the **new** secondary key data (which is stored as an array of 2 `uint128_t` integers) that will replace the existing one of the association - * @param data_len - Must be set to 2 - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by the specified secondary key - */ -__attribute__((eosio_wasm_import)) -void db_idx256_update(int32_t iterator, capi_name payer, const uint128_t* data, uint32_t data_len); - -/** - * - * Remove a table row from a secondary 256-bit index table - * - * @brief Remove a table row from a secondary 256-bit index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -__attribute__((eosio_wasm_import)) -void db_idx256_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary 256-bit index table - * - * @brief Find the table row following the referenced table row in a secondary 256-bit index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary 256-bit index table - * - * @brief Find the table row preceding the referenced table row in a secondary 256-bit index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary 256-bit index table by primary key - * - * @brief Find a table row in a secondary 128-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the an array of 2 `uint128_t` integers which will act as the buffer to hold the retrieved secondary key of the found table row - * @param data_len - Must be set to 2 - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, the buffer pointed to by `data` will be filled with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_find_primary(capi_name code, uint64_t scope, capi_name table, uint128_t* data, uint32_t data_len, uint64_t primary); - -/** - * - * Find a table row in a secondary 256-bit index table by secondary key - * - * @brief Find a table row in a secondary 256-bit index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the secondary key data (which is stored as an array of 2 `uint128_t` integers) used to lookup the table row - * @param data_len - Must be set to 2 - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to the specified secondary key or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_find_secondary(capi_name code, uint64_t scope, capi_name table, const uint128_t* data, uint32_t data_len, uint64_t* primary); - -/** - * - * Find the table row in a secondary 256-bit index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key (uses lexicographical ordering on the 256-bit keys) - * - * @brief Find the table row in a secondary 256-bit index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the secondary key data (which is stored as an array of 2 `uint128_t` integers) first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param data_len - Must be set to 2 - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, the buffer pointed to by `data` will be filled with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_lowerbound(capi_name code, uint64_t scope, capi_name table, uint128_t* data, uint32_t data_len, uint64_t* primary); - -/** - * - * Find the table row in a secondary 256-bit index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key (uses lexicographical ordering on the 256-bit keys) - * - * @brief Find the table row in a secondary 256-bit index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the secondary key data (which is stored as an array of 2 `uint128_t` integers) first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param data_len - Must be set to 2 - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, the buffer pointed to by `data` will be filled with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_upperbound(capi_name code, uint64_t scope, capi_name table, uint128_t* data, uint32_t data_len, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary 256-bit index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary 256-bit index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx256_end(capi_name code, uint64_t scope, capi_name table); - -/** - * - * Store an association of a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * - * @brief Store an association of a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary double-precision floating-point index table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const double* secondary); - -/** - * - * Update an association for a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * - * @brief Update an association for a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -__attribute__((eosio_wasm_import)) -void db_idx_double_update(int32_t iterator, capi_name payer, const double* secondary); - -/** - * - * Remove a table row from a secondary double-precision floating-point index table - * - * @brief Remove a table row from a secondary double-precision floating-point index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -__attribute__((eosio_wasm_import)) -void db_idx_double_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary double-precision floating-point index table - * - * @brief Find the table row following the referenced table row in a secondary double-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary double-precision floating-point index table - * - * @brief Find the table row preceding the referenced table row in a secondary double-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary double-precision floating-point index table by primary key - * - * @brief Find a table row in a secondary double-precision floating-point index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `double` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_find_primary(capi_name code, uint64_t scope, capi_name table, double* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary double-precision floating-point index table by secondary key - * - * @brief Find a table row in a secondary double-precision floating-point index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `double` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_find_secondary(capi_name code, uint64_t scope, capi_name table, const double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary double-precision floating-point index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary double-precision floating-point index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_lowerbound(capi_name code, uint64_t scope, capi_name table, double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary double-precision floating-point index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary double-precision floating-point index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_upperbound(capi_name code, uint64_t scope, capi_name table, double* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary double-precision floating-point index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary double-precision floating-point index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_double_end(capi_name code, uint64_t scope, capi_name table); - -/** - * - * Store an association of a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * - * @brief Store an association of a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary quadruple-precision floating-point index table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const long double* secondary); - -/** - * - * Update an association for a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * - * @brief Update an association for a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -__attribute__((eosio_wasm_import)) -void db_idx_long_double_update(int32_t iterator, capi_name payer, const long double* secondary); - -/** - * - * Remove a table row from a secondary quadruple-precision floating-point index table - * - * @brief Remove a table row from a secondary quadruple-precision floating-point index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -__attribute__((eosio_wasm_import)) -void db_idx_long_double_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary quadruple-precision floating-point index table - * - * @brief Find the table row following the referenced table row in a secondary quadruple-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary quadruple-precision floating-point index table - * - * @brief Find the table row preceding the referenced table row in a secondary quadruple-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary quadruple-precision floating-point index table by primary key - * - * @brief Find a table row in a secondary quadruple-precision floating-point index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `long double` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_find_primary(capi_name code, uint64_t scope, capi_name table, long double* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary quadruple-precision floating-point index table by secondary key - * - * @brief Find a table row in a secondary quadruple-precision floating-point index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `long double` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_find_secondary(capi_name code, uint64_t scope, capi_name table, const long double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary quadruple-precision floating-point index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary quadruple-precision floating-point index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_lowerbound(capi_name code, uint64_t scope, capi_name table, long double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary quadruple-precision floating-point index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary quadruple-precision floating-point index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_upperbound(capi_name code, uint64_t scope, capi_name table, long double* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary quadruple-precision floating-point index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary quadruple-precision floating-point index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -__attribute__((eosio_wasm_import)) -int32_t db_idx_long_double_end(capi_name code, uint64_t scope, capi_name table); - -///@} -} diff --git a/libraries/eosiolib/dispatcher.hpp b/libraries/eosiolib/dispatcher.hpp deleted file mode 100644 index e0edbe32de..0000000000 --- a/libraries/eosiolib/dispatcher.hpp +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once -#include -#include - -#include -#include - -#include - -#warning " is deprecated use " - -namespace eosio { - - template - bool dispatch( uint64_t code, uint64_t act ) { - if( code == FirstAction::get_account() && FirstAction::get_name() == act ) { - Contract().on( unpack_action_data() ); - return true; - } - return false; - } - - - /** - * This method will dynamically dispatch an incoming set of actions to - * - * ``` - * static Contract::on( ActionType ) - * ``` - * - * For this to work the Actions must be derived from eosio::contract - * - */ - template - bool dispatch( uint64_t code, uint64_t act ) { - if( code == FirstAction::get_account() && FirstAction::get_name() == act ) { - Contract().on( unpack_action_data() ); - return true; - } - return eosio::dispatch( code, act ); - } - - /** - * @addtogroup dispatcher Dispatcher C++ API - * @ingroup core - * @brief Defines C++ functions to dispatch action to proper action handler inside a contract - * @{ - */ - - /** - * Unpack the received action and execute the correponding action handler - * - * @tparam T - The contract class that has the correponding action handler, this contract should be derived from eosio::contract - * @tparam Q - The namespace of the action handler function - * @tparam Args - The arguments that the action handler accepts, i.e. members of the action - * @param obj - The contract object that has the correponding action handler - * @param func - The action handler - * @return true - */ - template - bool execute_action( name self, name code, void (T::*func)(Args...) ) { - size_t size = action_data_size(); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - constexpr size_t max_stack_buffer_size = 512; - void* buffer = nullptr; - if( size > 0 ) { - buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - read_action_data( buffer, size ); - } - - std::tuple...> args; - datastream ds((char*)buffer, size); - ds >> args; - - T inst(self, code, ds); - - auto f2 = [&]( auto... a ){ - ((&inst)->*func)( a... ); - }; - - boost::mp11::tuple_apply( f2, args ); - if ( max_stack_buffer_size < size ) { - free(buffer); - } - return true; - } - - /// @} - - // Helper macro for EOSIO_DISPATCH_INTERNAL - #define EOSIO_DISPATCH_INTERNAL( r, OP, elem ) \ - case eosio::name( BOOST_PP_STRINGIZE(elem) ).value: \ - eosio::execute_action( eosio::name(receiver), eosio::name(code), &OP::elem ); \ - break; - - // Helper macro for EOSIO_DISPATCH - #define EOSIO_DISPATCH_HELPER( TYPE, MEMBERS ) \ - BOOST_PP_SEQ_FOR_EACH( EOSIO_DISPATCH_INTERNAL, TYPE, MEMBERS ) - -/** - * @addtogroup dispatcher - * Convenient macro to create contract apply handler - * - * @note To be able to use this macro, the contract needs to be derived from eosio::contract - * @param TYPE - The class name of the contract - * @param MEMBERS - The sequence of available actions supported by this contract - * - * Example: - * @code - * EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(reqauth) ) - * @endcode - */ -#define EOSIO_DISPATCH( TYPE, MEMBERS ) \ -extern "C" { \ - [[eosio::wasm_entry]] \ - void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \ - if( code == receiver ) { \ - switch( action ) { \ - EOSIO_DISPATCH_HELPER( TYPE, MEMBERS ) \ - } \ - /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \ - } \ - } \ -} \ - -} diff --git a/libraries/eosiolib/eosio.hpp b/libraries/eosiolib/eosio.hpp deleted file mode 100644 index 4738eb735b..0000000000 --- a/libraries/eosiolib/eosio.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "action.hpp" -#include "print.hpp" -#include "multi_index.hpp" -#include "dispatcher.hpp" -#include "contract.hpp" - -#warning " is deprecated use " - -#ifndef EOSIO_NATIVE -static_assert( sizeof(long) == sizeof(int), "unexpected size difference" ); -#endif - -/** - * Helper macros to reduce the verbosity for common contracts - */ -#define CONTRACT class [[eosio::contract]] -#define ACTION [[eosio::action]] void -#define TABLE struct [[eosio::table]] - -/** - * @defgroup core Core API - * @brief C++ Core API for chain-agnostic smart-contract functionality - */ - - /** - * @defgroup contracts Contracts API - * @brief C++ Chain API for chain-dependent smart-contract functionality - */ - -/** - * @defgroup types Types - * @brief TODO - */ diff --git a/libraries/eosiolib/eosiolib.cpp b/libraries/eosiolib/eosiolib.cpp index f97f67237a..12eac10a0d 100644 --- a/libraries/eosiolib/eosiolib.cpp +++ b/libraries/eosiolib/eosiolib.cpp @@ -19,6 +19,33 @@ namespace eosio { uint32_t get_active_producers(uint64_t*, uint32_t); } + // producer_schedule.hpp + bool block_signing_authority_v0::is_valid()const { + uint32_t sum_weights = 0; + std::set unique_keys; + + for (const auto& kw: keys ) { + if( std::numeric_limits::max() - sum_weights <= kw.weight ) { + sum_weights = std::numeric_limits::max(); + } else { + sum_weights += kw.weight; + } + + unique_keys.insert(kw.key); + } + + if( keys.size() != unique_keys.size() ) + return false; // producer authority includes a duplicated key + + if( threshold == 0 ) + return false; // producer authority has a threshold of 0 + + if( sum_weights < threshold ) + return false; // producer authority is unsatisfiable + + return true; + } + // privileged.hpp void set_blockchain_parameters(const eosio::blockchain_parameters& params) { char buf[sizeof(eosio::blockchain_parameters)]; diff --git a/libraries/eosiolib/fixed_bytes.hpp b/libraries/eosiolib/fixed_bytes.hpp deleted file mode 100644 index 823a2726e9..0000000000 --- a/libraries/eosiolib/fixed_bytes.hpp +++ /dev/null @@ -1,353 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "system.hpp" - -#include -#include -#include - -#warning " is deprecated use " - -namespace eosio { - - template - class fixed_bytes; - - template - bool operator ==(const fixed_bytes &c1, const fixed_bytes &c2); - - template - bool operator !=(const fixed_bytes &c1, const fixed_bytes &c2); - - template - bool operator >(const fixed_bytes &c1, const fixed_bytes &c2); - - template - bool operator <(const fixed_bytes &c1, const fixed_bytes &c2); - - template - bool operator >=(const fixed_bytes &c1, const fixed_bytes &c2); - - template - bool operator <=(const fixed_bytes &c1, const fixed_bytes &c2); - - /** - * @defgroup fixed_bytes Fixed Size Byte Array - * @ingroup types - * @brief Fixed size array of bytes sorted lexicographically - * @{ - */ - - /** - * Fixed size byte array sorted lexicographically - * - * @brief Fixed size array of bytes sorted lexicographically - * @tparam Size - Size of the fixed_bytes object - * @ingroup types - */ - template - class fixed_bytes { - private: - - template struct bool_pack; - template - using all_true = std::is_same< bool_pack, bool_pack >; - - template - static void set_from_word_sequence(const Word* arr_begin, const Word* arr_end, fixed_bytes& key) - { - auto itr = key._data.begin(); - word_t temp_word = 0; - const size_t sub_word_shift = 8 * sizeof(Word); - const size_t num_sub_words = sizeof(word_t) / sizeof(Word); - auto sub_words_left = num_sub_words; - for( auto w_itr = arr_begin; w_itr != arr_end; ++w_itr ) { - if( sub_words_left > 1 ) { - temp_word |= static_cast(*w_itr); - temp_word <<= sub_word_shift; - --sub_words_left; - continue; - } - - eosio::check( sub_words_left == 1, "unexpected error in fixed_bytes constructor" ); - temp_word |= static_cast(*w_itr); - sub_words_left = num_sub_words; - - *itr = temp_word; - temp_word = 0; - ++itr; - } - if( sub_words_left != num_sub_words ) { - if( sub_words_left > 1 ) - temp_word <<= 8 * (sub_words_left-1); - *itr = temp_word; - } - } - - public: - - typedef uint128_t word_t; - - /** - * Get number of words contained in this fixed_bytes object. A word is defined to be 16 bytes in size - * - * @brief Get number of words contained in this fixed_bytes object - */ - - static constexpr size_t num_words() { return (Size + sizeof(word_t) - 1) / sizeof(word_t); } - - /** - * Get number of padded bytes contained in this fixed_bytes object. Padded bytes are the remaining bytes - * inside the fixed_bytes object after all the words are allocated - * - * @brief Get number of padded bytes contained in this fixed_bytes object - */ - static constexpr size_t padded_bytes() { return num_words() * sizeof(word_t) - Size; } - - /** - * @brief Default constructor to fixed_bytes object - * - * @details Default constructor to fixed_bytes object which initializes all bytes to zero - */ - constexpr fixed_bytes() : _data() {} - - /** - * @brief Constructor to fixed_bytes object from std::array of num_words() word_t types - * - * @details Constructor to fixed_bytes object from std::array of num_words() word_t types - * @param arr data - */ - fixed_bytes(const std::array& arr) - { - std::copy(arr.begin(), arr.end(), _data.begin()); - } - - /** - * @brief Constructor to fixed_bytes object from std::array of Word types smaller in size than word_t - * - * @details Constructor to fixed_bytes object from std::array of Word types smaller in size than word_t - * @param arr - Source data - */ - template::value && - !std::is_same::value && - std::less{}( sizeof(Word), sizeof(word_t))>::type > - fixed_bytes(const std::array& arr) - { - static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(Word)) * sizeof(Word), - "size of the backing word size is not divisible by the size of the array element" ); - static_assert( sizeof(Word) * NumWords <= Size, "too many words supplied to fixed_bytes constructor" ); - - set_from_word_sequence(arr.data(), arr.data() + arr.size(), *this); - } - - /** - * @brief Constructor to fixed_bytes object from fixed-sized C array of Word types smaller in size than word_t - * - * @details Constructor to fixed_bytes object from fixed-sized C array of Word types smaller in size than word_t - * @param arr - Source data - */ - template::value && - !std::is_same::value && - std::less{}( sizeof(Word), sizeof(word_t))>::type > - fixed_bytes(const Word(&arr)[NumWords]) - { - static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(Word)) * sizeof(Word), - "size of the backing word size is not divisible by the size of the array element" ); - static_assert( sizeof(Word) * NumWords <= Size, "too many words supplied to fixed_bytes constructor" ); - - set_from_word_sequence(arr, arr + NumWords, *this); - } - - /** - * @brief Create a new fixed_bytes object from a sequence of words - * - * @details Create a new fixed_bytes object from a sequence of words - * @tparam FirstWord - The type of the first word in the sequence - * @tparam Rest - The type of the remaining words in the sequence - * @param first_word - The first word in the sequence - * @param rest - The remaining words in the sequence - */ - template - static - fixed_bytes - make_from_word_sequence(typename std::enable_if::value && - !std::is_same::value && - sizeof(FirstWord) <= sizeof(word_t) && - all_true<(std::is_same::value)...>::value, - FirstWord>::type first_word, - Rest... rest) - { - static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(FirstWord)) * sizeof(FirstWord), - "size of the backing word size is not divisible by the size of the words supplied as arguments" ); - static_assert( sizeof(FirstWord) * (1 + sizeof...(Rest)) <= Size, "too many words supplied to make_from_word_sequence" ); - - fixed_bytes key; - std::array arr{{ first_word, rest... }}; - set_from_word_sequence(arr.data(), arr.data() + arr.size(), key); - return key; - } - - /** - * Get the contained std::array - * @brief Get the contained std::array - */ - const auto& get_array()const { return _data; } - - /** - * Get the underlying data of the contained std::array - * @brief Get the underlying data of the contained std::array - */ - auto data() { return _data.data(); } - - /** - * Get the underlying data of the contained std::array - * @brief Get the underlying data of the contained std::array - */ - auto data()const { return _data.data(); } - - /** - * Get the size of the contained std::array - * @brief Get the size of the contained std::array - */ - auto size()const { return _data.size(); } - - - /** - * Extract the contained data as an array of bytes - * @brief Extract the contained data as an array of bytes - * @return - the extracted data as array of bytes - */ - std::array extract_as_byte_array()const { - std::array arr; - - const size_t num_sub_words = sizeof(word_t); - - auto arr_itr = arr.begin(); - auto data_itr = _data.begin(); - - for( size_t counter = _data.size(); counter > 0; --counter, ++data_itr ) { - size_t sub_words_left = num_sub_words; - - auto temp_word = *data_itr; - if( counter == 1 ) { // If last word in _data array... - sub_words_left -= padded_bytes(); - temp_word >>= 8*padded_bytes(); - } - for( ; sub_words_left > 0; --sub_words_left ) { - *(arr_itr + sub_words_left - 1) = static_cast(temp_word & 0xFF); - temp_word >>= 8; - } - arr_itr += num_sub_words; - } - - return arr; - } - - // Comparison operators - friend bool operator == <>(const fixed_bytes &c1, const fixed_bytes &c2); - - friend bool operator != <>(const fixed_bytes &c1, const fixed_bytes &c2); - - friend bool operator > <>(const fixed_bytes &c1, const fixed_bytes &c2); - - friend bool operator < <>(const fixed_bytes &c1, const fixed_bytes &c2); - - friend bool operator >= <>(const fixed_bytes &c1, const fixed_bytes &c2); - - friend bool operator <= <>(const fixed_bytes &c1, const fixed_bytes &c2); - - private: - - std::array _data; - }; - - /** - * @brief Compares two fixed_bytes variables c1 and c2 - * - * @details Lexicographically compares two fixed_bytes variables c1 and c2 - * @param c1 - First fixed_bytes object to compare - * @param c2 - Second fixed_bytes object to compare - * @return if c1 == c2, return true, otherwise false - */ - template - bool operator ==(const fixed_bytes &c1, const fixed_bytes &c2) { - return c1._data == c2._data; - } - - /** - * @brief Compares two fixed_bytes variables c1 and c2 - * - * @details Lexicographically compares two fixed_bytes variables c1 and c2 - * @param c1 - First fixed_bytes object to compare - * @param c2 - Second fixed_bytes object to compare - * @return if c1 != c2, return true, otherwise false - */ - template - bool operator !=(const fixed_bytes &c1, const fixed_bytes &c2) { - return c1._data != c2._data; - } - - /** - * @brief Compares two fixed_bytes variables c1 and c2 - * - * @details Lexicographically compares two fixed_bytes variables c1 and c2 - * @param c1 - First fixed_bytes object to compare - * @param c2 - Second fixed_bytes object to compare - * @return if c1 > c2, return true, otherwise false - */ - template - bool operator >(const fixed_bytes& c1, const fixed_bytes& c2) { - return c1._data > c2._data; - } - - /** - * @brief Compares two fixed_bytes variables c1 and c2 - * - * @details Lexicographically compares two fixed_bytes variables c1 and c2 - * @param c1 - First fixed_bytes object to compare - * @param c2 - Second fixed_bytes object to compare - * @return if c1 < c2, return true, otherwise false - */ - template - bool operator <(const fixed_bytes &c1, const fixed_bytes &c2) { - return c1._data < c2._data; - } - - /** - * @brief Compares two fixed_bytes variables c1 and c2 - * - * @details Lexicographically compares two fixed_bytes variables c1 and c2 - * @param c1 - First fixed_bytes object to compare - * @param c2 - Second fixed_bytes object to compare - * @return if c1 >= c2, return true, otherwise false - */ - template - bool operator >=(const fixed_bytes& c1, const fixed_bytes& c2) { - return c1._data >= c2._data; - } - - /** - * @brief Compares two fixed_bytes variables c1 and c2 - * - * @details Lexicographically compares two fixed_bytes variables c1 and c2 - * @param c1 - First fixed_bytes object to compare - * @param c2 - Second fixed_bytes object to compare - * @return if c1 <= c2, return true, otherwise false - */ - template - bool operator <=(const fixed_bytes &c1, const fixed_bytes &c2) { - return c1._data <= c2._data; - } - - /// @} fixed_bytes - - using checksum160 = fixed_bytes<20>; - using checksum256 = fixed_bytes<32>; - using checksum512 = fixed_bytes<64>; -} diff --git a/libraries/eosiolib/ignore.hpp b/libraries/eosiolib/ignore.hpp deleted file mode 100644 index 2d47ba55ec..0000000000 --- a/libraries/eosiolib/ignore.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#warning " is deprecated use " - -namespace eosio { - /** - * @brief Tells the datastream to ignore this type, but allows the abi generator to add the correct type. - * - * @details Currently non-ignore types can not succeed an ignore type in a method definition, i.e. void foo(float, ignore) is allowed and void foo(float, ignore, int) is not allowed. - * @note This restriction will be relaxed in a later release. - * Currently non-ignore types can not succeed an ignore type in a method definition, i.e. void foo(float, ignore) is allowed and void foo(float, ignore, int) is not allowed. - * This restriction will be relaxed in a later release. - */ - template - struct [[eosio::ignore]] ignore {}; - - /** - * Wrapper class to allow sending inline actions with the correct payload - */ - template - struct ignore_wrapper { - constexpr ignore_wrapper() {} - constexpr ignore_wrapper(T val) : value(val) {} - constexpr ignore_wrapper(ignore val) {} - constexpr inline T get() { return value; } - constexpr operator T() { return value; } - constexpr operator ignore() { return {}; } - T value; - }; -} //ns eosio diff --git a/libraries/eosiolib/multi_index.hpp b/libraries/eosiolib/multi_index.hpp deleted file mode 100644 index a55ea8f5b7..0000000000 --- a/libraries/eosiolib/multi_index.hpp +++ /dev/null @@ -1,1714 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "action.h" -#include "name.hpp" -#include "serialize.hpp" -#include "datastream.hpp" -#include "db.h" -#include "fixed_bytes.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#warning " is deprecated use " - -namespace eosio { - -constexpr static inline name same_payer{}; - -template -struct const_mem_fun -{ - typedef typename std::remove_reference::type result_type; - - template - - auto operator()(const ChainedPtr& x)const -> std::enable_if_t::value, Type> - { - return operator()(*x); - } - - Type operator()(const Class& x)const - { - return (x.*PtrToMemberFunction)(); - } - - Type operator()(const std::reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type operator()(const std::reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -#define WRAP_SECONDARY_SIMPLE_TYPE(IDX, TYPE)\ -template<>\ -struct secondary_index_db_functions {\ - static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return db_##IDX##_next( iterator, primary ); }\ - static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return db_##IDX##_previous( iterator, primary ); }\ - static void db_idx_remove( int32_t iterator ) { db_##IDX##_remove( iterator ); }\ - static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return db_##IDX##_end( code, scope, table ); }\ - static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\ - return db_##IDX##_store( scope, table, payer, id, &secondary );\ - }\ - static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\ - db_##IDX##_update( iterator, payer, &secondary );\ - }\ - static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\ - return db_##IDX##_find_primary( code, scope, table, &secondary, primary );\ - }\ - static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_find_secondary( code, scope, table, &secondary, &primary );\ - }\ - static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_lowerbound( code, scope, table, &secondary, &primary );\ - }\ - static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_upperbound( code, scope, table, &secondary, &primary );\ - }\ -}; - -#define WRAP_SECONDARY_ARRAY_TYPE(IDX, TYPE)\ -template<>\ -struct secondary_index_db_functions {\ - static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return db_##IDX##_next( iterator, primary ); }\ - static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return db_##IDX##_previous( iterator, primary ); }\ - static void db_idx_remove( int32_t iterator ) { db_##IDX##_remove( iterator ); }\ - static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return db_##IDX##_end( code, scope, table ); }\ - static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\ - return db_##IDX##_store( scope, table, payer, id, secondary.data(), TYPE::num_words() );\ - }\ - static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\ - db_##IDX##_update( iterator, payer, secondary.data(), TYPE::num_words() );\ - }\ - static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\ - return db_##IDX##_find_primary( code, scope, table, secondary.data(), TYPE::num_words(), primary );\ - }\ - static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_find_secondary( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ - static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_lowerbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ - static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_upperbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ -}; - -#define MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(TYPE)\ -template<>\ -struct secondary_key_traits {\ - static_assert( std::numeric_limits::is_specialized, "TYPE does not have specialized numeric_limits" );\ - static constexpr TYPE true_lowest() { return std::numeric_limits::lowest(); }\ -}; - -namespace _multi_index_detail { - - namespace hana = boost::hana; - - template - struct secondary_index_db_functions; - - template - struct secondary_key_traits; - - WRAP_SECONDARY_SIMPLE_TYPE(idx64, uint64_t) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(uint64_t) - - WRAP_SECONDARY_SIMPLE_TYPE(idx128, uint128_t) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(uint128_t) - - WRAP_SECONDARY_SIMPLE_TYPE(idx_double, double) - template<> - struct secondary_key_traits { - static constexpr double true_lowest() { return -std::numeric_limits::infinity(); } - }; - - WRAP_SECONDARY_SIMPLE_TYPE(idx_long_double, long double) - template<> - struct secondary_key_traits { - static constexpr long double true_lowest() { return -std::numeric_limits::infinity(); } - }; - - WRAP_SECONDARY_ARRAY_TYPE(idx256, eosio::fixed_bytes<32>) - template<> - struct secondary_key_traits> { - static constexpr eosio::fixed_bytes<32> true_lowest() { return eosio::fixed_bytes<32>(); } - }; - -} - -/** - * The indexed_by struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices can be specified. - * @brief The indexed_by struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices can be specified. - * - * @tparam IndexName - is the name of the index. The name must be provided as an EOSIO base32 encoded 64-bit integer and must conform to the EOSIO naming requirements of a maximum of 13 characters, the first twelve from the lowercase characters a-z, digits 1-5, and ".", and if there is a 13th character, it is restricted to lowercase characters a-p and ".". - * @tparam Extractor - is a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type. It is recommended to use the `eosio::const_mem_fun` template, which is a type alias to the `boost::multi_index::const_mem_fun`. See the documentation for the Boost `const_mem_fun` key extractor for more details. - * - * Example: - * -* - * @code - * #include - * using namespace eosio; - * class mycontract: eosio::contract { - * struct record { - * uint64_t primary; - * uint128_t secondary; - * uint64_t primary_key() const { return primary; } - * uint64_t get_secondary() const { return secondary; } - * }; - * public: - * mycontract(name receiver, name code, datastream ds):contract(receiver, code, ds){} - * void myaction() { - * auto code = _self; - * auto scope = _self; - * multi_index<"mytable"_n, record, - * indexed_by< "bysecondary"_n, const_mem_fun > > table( code, scope); - * } - * } - * EOSIO_DISPATCH( mycontract, (myaction) ) - * @endcode - */ -template -struct indexed_by { - enum constants { index_name = static_cast(IndexName) }; - typedef Extractor secondary_extractor_type; -}; - -/** - * @defgroup multi_index Multi Index Table - * @brief Defines EOSIO Multi Index Table - * @ingroup contracts - * - * @details EOSIO Multi-Index API provides a C++ interface to the EOSIO database. It is patterned after Boost Multi Index Container. - * EOSIO Multi-Index table requires exactly a uint64_t primary key. For the table to be able to retrieve the primary key, - * the object stored inside the table is required to have a const member function called primary_key() that returns uint64_t. - * EOSIO Multi-Index table also supports up to 16 secondary indices. The type of the secondary indices could be any of: - * - uint64_t - * - uint128_t - * - double - * - long double - * - eosio::checksum256 - * - * @tparam TableName - name of the table - * @tparam T - type of the data stored inside the table - * @tparam Indices - secondary indices for the table, up to 16 indices is supported here - * - * Example: - * - * @code - * #include - * using namespace eosio; - * class mycontract: contract { - * struct record { - * uint64_t primary; - * uint64_t secondary_1; - * uint128_t secondary_2; - * checksum256 secondary_3; - * double secondary_4; - * long double secondary_5; - * uint64_t primary_key() const { return primary; } - * uint64_t get_secondary_1() const { return secondary_1; } - * uint128_t get_secondary_2() const { return secondary_2; } - * checksum256 get_secondary_3() const { return secondary_3; } - * double get_secondary_4() const { return secondary_4; } - * long double get_secondary_5() const { return secondary_5; } - * }; - * public: - * mycontract(name receiver, name code, datastream ds):contract(receiver, code, ds){} - * void myaction() { - * auto code = _self; - * auto scope = _self; - * multi_index<"mytable"_n, record, - * indexed_by< "bysecondary1"_n, const_mem_fun >, - * indexed_by< "bysecondary2"_n, const_mem_fun >, - * indexed_by< "bysecondary3"_n, const_mem_fun >, - * indexed_by< "bysecondary4"_n, const_mem_fun >, - * indexed_by< "bysecondary5"_n, const_mem_fun > - * > table( code, scope); - * } - * } - * EOSIO_DISPATCH( mycontract, (myaction) ) - * @endcode - * @{ - */ - -template -class multi_index -{ - private: - - static_assert( sizeof...(Indices) <= 16, "multi_index only supports a maximum of 16 secondary indices" ); - - constexpr static bool validate_table_name( name n ) { - // Limit table names to 12 characters so that the last character (4 bits) can be used to distinguish between the secondary indices. - return n.length() < 13; //(n & 0x000000000000000FULL) == 0; - } - - constexpr static size_t max_stack_buffer_size = 512; - - static_assert( validate_table_name( name(TableName) ), "multi_index does not support table names with a length greater than 12"); - - name _code; - uint64_t _scope; - - mutable uint64_t _next_primary_key; - - enum next_primary_key_tags : uint64_t { - no_available_primary_key = static_cast(-2), // Must be the smallest uint64_t value compared to all other tags - unset_next_primary_key = static_cast(-1) - }; - - struct item : public T - { - template - item( const multi_index* idx, Constructor&& c ) - :__idx(idx){ - c(*this); - } - - const multi_index* __idx; - int32_t __primary_itr; - int32_t __iters[sizeof...(Indices)+(sizeof...(Indices)==0)]; - }; - - struct item_ptr - { - item_ptr(std::unique_ptr&& i, uint64_t pk, int32_t pitr) - : _item(std::move(i)), _primary_key(pk), _primary_itr(pitr) {} - - std::unique_ptr _item; - uint64_t _primary_key; - int32_t _primary_itr; - }; - - mutable std::vector _items_vector; - - template - struct index { - public: - typedef Extractor secondary_extractor_type; - typedef typename std::decay::type secondary_key_type; - - constexpr static bool validate_index_name( eosio::name n ) { - return n.value != 0 && n != eosio::name("primary"); // Primary is a reserve index name. - } - - static_assert( validate_index_name( name(IndexName) ), "invalid index name used in multi_index" ); - - enum constants { - table_name = static_cast(TableName), - index_name = static_cast(IndexName), - index_number = Number, - index_table_name = (static_cast(TableName) & 0xFFFFFFFFFFFFFFF0ULL) - | (Number & 0x000000000000000FULL) // Assuming no more than 16 secondary indices are allowed - }; - - constexpr static uint64_t name() { return index_table_name; } - constexpr static uint64_t number() { return Number; } - - struct const_iterator : public std::iterator { - public: - friend bool operator == ( const const_iterator& a, const const_iterator& b ) { - return a._item == b._item; - } - friend bool operator != ( const const_iterator& a, const const_iterator& b ) { - return a._item != b._item; - } - - const T& operator*()const { return *static_cast(_item); } - const T* operator->()const { return static_cast(_item); } - - const_iterator operator++(int){ - const_iterator result(*this); - ++(*this); - return result; - } - - const_iterator operator--(int){ - const_iterator result(*this); - --(*this); - return result; - } - - const_iterator& operator++() { - using namespace _multi_index_detail; - - eosio::check( _item != nullptr, "cannot increment end iterator" ); - - if( _item->__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(_idx->get_code().value, _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key); - auto& mi = const_cast( *_item ); - mi.__iters[Number] = idxitr; - } - - uint64_t next_pk = 0; - auto next_itr = secondary_index_db_functions::db_idx_next( _item->__iters[Number], &next_pk ); - if( next_itr < 0 ) { - _item = nullptr; - return *this; - } - - const T& obj = *_idx->_multidx->find( next_pk ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = next_itr; - _item = &mi; - - return *this; - } - - const_iterator& operator--() { - using namespace _multi_index_detail; - - uint64_t prev_pk = 0; - int32_t prev_itr = -1; - - if( !_item ) { - auto ei = secondary_index_db_functions::db_idx_end(_idx->get_code().value, _idx->get_scope(), _idx->name()); - eosio::check( ei != -1, "cannot decrement end iterator when the index is empty" ); - prev_itr = secondary_index_db_functions::db_idx_previous( ei , &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement end iterator when the index is empty" ); - } else { - if( _item->__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(_idx->get_code().value, _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key); - auto& mi = const_cast( *_item ); - mi.__iters[Number] = idxitr; - } - prev_itr = secondary_index_db_functions::db_idx_previous( _item->__iters[Number], &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement iterator at beginning of index" ); - } - - const T& obj = *_idx->_multidx->find( prev_pk ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = prev_itr; - _item = &mi; - - return *this; - } - - const_iterator():_item(nullptr){} - private: - friend struct index; - const_iterator( const index* idx, const item* i = nullptr ) - : _idx(idx), _item(i) {} - - const index* _idx; - const item* _item; - }; /// struct multi_index::index::const_iterator - - typedef std::reverse_iterator const_reverse_iterator; - - const_iterator cbegin()const { - using namespace _multi_index_detail; - return lower_bound( secondary_key_traits::true_lowest() ); - } - const_iterator begin()const { return cbegin(); } - - const_iterator cend()const { return const_iterator( this ); } - const_iterator end()const { return cend(); } - - const_reverse_iterator crbegin()const { return std::make_reverse_iterator(cend()); } - const_reverse_iterator rbegin()const { return crbegin(); } - - const_reverse_iterator crend()const { return std::make_reverse_iterator(cbegin()); } - const_reverse_iterator rend()const { return crend(); } - - const_iterator find( secondary_key_type&& secondary )const { - return find( secondary ); - } - - const_iterator find( const secondary_key_type& secondary )const { - auto lb = lower_bound( secondary ); - auto e = cend(); - if( lb == e ) return e; - - if( secondary != secondary_extractor_type()(*lb) ) - return e; - return lb; - } - - const_iterator require_find( secondary_key_type&& secondary, const char* error_msg = "unable to find secondary key" )const { - return require_find( secondary, error_msg ); - } - - const_iterator require_find( const secondary_key_type& secondary, const char* error_msg = "unable to find secondary key" )const { - auto lb = lower_bound( secondary ); - eosio::check( lb != cend(), error_msg ); - eosio::check( secondary == secondary_extractor_type()(*lb), error_msg ); - return lb; - } - - const T& get( secondary_key_type&& secondary, const char* error_msg = "unable to find secondary key" )const { - return get( secondary, error_msg ); - } - - // Gets the object with the smallest primary key in the case where the secondary key is not unique. - const T& get( const secondary_key_type& secondary, const char* error_msg = "unable to find secondary key" )const { - auto result = find( secondary ); - eosio::check( result != cend(), error_msg ); - return *result; - } - - const_iterator lower_bound( secondary_key_type&& secondary )const { - return lower_bound( secondary ); - } - const_iterator lower_bound( const secondary_key_type& secondary )const { - using namespace _multi_index_detail; - - uint64_t primary = 0; - secondary_key_type secondary_copy(secondary); - auto itr = secondary_index_db_functions::db_idx_lowerbound( get_code().value, get_scope(), name(), secondary_copy, primary ); - if( itr < 0 ) return cend(); - - const T& obj = *_multidx->find( primary ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = itr; - - return {this, &mi}; - } - - const_iterator upper_bound( secondary_key_type&& secondary )const { - return upper_bound( secondary ); - } - const_iterator upper_bound( const secondary_key_type& secondary )const { - using namespace _multi_index_detail; - - uint64_t primary = 0; - secondary_key_type secondary_copy(secondary); - auto itr = secondary_index_db_functions::db_idx_upperbound( get_code().value, get_scope(), name(), secondary_copy, primary ); - if( itr < 0 ) return cend(); - - const T& obj = *_multidx->find( primary ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = itr; - - return {this, &mi}; - } - - const_iterator iterator_to( const T& obj ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == _multidx, "object passed to iterator_to is not in multi_index" ); - - if( objitem.__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(get_code().value, get_scope(), name(), objitem.primary_key(), temp_secondary_key); - auto& mi = const_cast( objitem ); - mi.__iters[Number] = idxitr; - } - - return {this, &objitem}; - } - - template - void modify( const_iterator itr, eosio::name payer, Lambda&& updater ) { - eosio::check( itr != cend(), "cannot pass end iterator to modify" ); - - _multidx->modify( *itr, payer, std::forward(updater) ); - } - - const_iterator erase( const_iterator itr ) { - eosio::check( itr != cend(), "cannot pass end iterator to erase" ); - - const auto& obj = *itr; - ++itr; - - _multidx->erase(obj); - - return itr; - } - - eosio::name get_code()const { return _multidx->get_code(); } - uint64_t get_scope()const { return _multidx->get_scope(); } - - static auto extract_secondary_key(const T& obj) { return secondary_extractor_type()(obj); } - - private: - friend class multi_index; - - index( typename std::conditional::type midx ) - :_multidx(midx){} - - typename std::conditional::type _multidx; - }; /// struct multi_index::index - - template - struct intc { enum e{ value = I }; operator uint64_t()const{ return I; } }; - - static constexpr auto transform_indices( ) { - using namespace _multi_index_detail; - - typedef decltype( hana::zip_shortest( - hana::make_tuple( intc<0>(), intc<1>(), intc<2>(), intc<3>(), intc<4>(), intc<5>(), - intc<6>(), intc<7>(), intc<8>(), intc<9>(), intc<10>(), intc<11>(), - intc<12>(), intc<13>(), intc<14>(), intc<15>() ), - hana::tuple() ) ) indices_input_type; - - return hana::transform( indices_input_type(), [&]( auto&& idx ){ - typedef typename std::decay(idx))>::type num_type; - typedef typename std::decay(idx))>::type idx_type; - return hana::make_tuple( hana::type_c(idx_type::index_name)), - typename idx_type::secondary_extractor_type, - num_type::e::value, false> >, - hana::type_c(idx_type::index_name)), - typename idx_type::secondary_extractor_type, - num_type::e::value, true> > ); - - }); - } - - typedef decltype( multi_index::transform_indices() ) indices_type; - - indices_type _indices; - - const item& load_object_by_primary_iterator( int32_t itr )const { - using namespace _multi_index_detail; - - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._primary_itr == itr; - }); - if( itr2 != _items_vector.rend() ) - return *itr2->_item; - - auto size = db_get_i64( itr, nullptr, 0 ); - eosio::check( size >= 0, "error reading iterator" ); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size_t(size) ? malloc(size_t(size)) : alloca(size_t(size)); - - db_get_i64( itr, buffer, uint32_t(size) ); - - datastream ds( (char*)buffer, uint32_t(size) ); - - auto itm = std::make_unique( this, [&]( auto& i ) { - T& val = static_cast(i); - ds >> val; - - i.__primary_itr = itr; - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<1>(idx))::type index_type; - - i.__iters[ index_type::number() ] = -1; - }); - }); - - const item* ptr = itm.get(); - auto pk = itm->primary_key(); - auto pitr = itm->__primary_itr; - - _items_vector.emplace_back( std::move(itm), pk, pitr ); - - if ( max_stack_buffer_size < size_t(size) ) { - free(buffer); - } - - return *ptr; - } /// load_object_by_primary_iterator - - public: - /** - * Constructs an instance of a Multi-Index table. - * @brief Constructs an instance of a Multi-Index table. - * - * @param code - Account that owns table - * @param scope - Scope identifier within the code hierarchy - * - * @pre code and scope member properties are initialized - * @post each secondary index table initialized - * @post Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. - * @post The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. - * - * Notes - * The `eosio::multi_index` template has template parameters ``, where: - * - `TableName` is the name of the table, maximum 12 characters long, characters in the name from the set of lowercase letters, digits 1 to 5, and the "." (period) character and is converted to a eosio::raw - which wraps uint64_t; - * - `T` is the object type (i.e., row definition); - * - `Indices` is a list of up to 16 secondary indices. - * - Each must be a default constructable class or struct - * - Each must have a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type - * - It is recommended to use the eosio::const_mem_fun template, which is a type alias to the boost::multi_index::const_mem_fun. See the documentation for the Boost const_mem_fun key extractor for more details. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * }; - * public: - * addressbook(name self):contract(self) {} - * typedef eosio::multi_index< "address"_n, address > address_index; - * void myaction() { - * address_index addresses(_self, _self.value); // code, scope - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - multi_index( name code, uint64_t scope ) - :_code(code),_scope(scope),_next_primary_key(unset_next_primary_key) - {} - - /** - * Returns the `code` member property. - * - * @return Account name of the Code that owns the Primary Table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses("dan"_n, "dan"_n); // code, scope - * eosio::check(addresses.get_code() == "dan"_n, "Codes don't match."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - name get_code()const { return _code; } - - /** - * Returns the `scope` member property. - * - * @return Scope id of the Scope within the Code of the Current Receiver under which the desired Primary Table instance can be found. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses("dan"_n, "dan"_n); // code, scope - * eosio::check(addresses.get_code() == "dan"_n, "Scopes don't match"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - uint64_t get_scope()const { return _scope; } - - struct const_iterator : public std::iterator { - friend bool operator == ( const const_iterator& a, const const_iterator& b ) { - return a._item == b._item; - } - friend bool operator != ( const const_iterator& a, const const_iterator& b ) { - return a._item != b._item; - } - - const T& operator*()const { return *static_cast(_item); } - const T* operator->()const { return static_cast(_item); } - - const_iterator operator++(int) { - const_iterator result(*this); - ++(*this); - return result; - } - - const_iterator operator--(int) { - const_iterator result(*this); - --(*this); - return result; - } - - const_iterator& operator++() { - eosio::check( _item != nullptr, "cannot increment end iterator" ); - - uint64_t next_pk; - auto next_itr = db_next_i64( _item->__primary_itr, &next_pk ); - if( next_itr < 0 ) - _item = nullptr; - else - _item = &_multidx->load_object_by_primary_iterator( next_itr ); - return *this; - } - const_iterator& operator--() { - uint64_t prev_pk; - int32_t prev_itr = -1; - - if( !_item ) { - auto ei = db_end_i64(_multidx->get_code().value, _multidx->get_scope(), static_cast(TableName)); - eosio::check( ei != -1, "cannot decrement end iterator when the table is empty" ); - prev_itr = db_previous_i64( ei , &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement end iterator when the table is empty" ); - } else { - prev_itr = db_previous_i64( _item->__primary_itr, &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement iterator at beginning of table" ); - } - - _item = &_multidx->load_object_by_primary_iterator( prev_itr ); - return *this; - } - - private: - const_iterator( const multi_index* mi, const item* i = nullptr ) - :_multidx(mi),_item(i){} - - const multi_index* _multidx; - const item* _item; - friend class multi_index; - }; /// struct multi_index::const_iterator - - typedef std::reverse_iterator const_reverse_iterator; - - /** - * Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr == addresses.cbegin(), "Only address is not at front."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator cbegin()const { - return lower_bound(std::numeric_limits::lowest()); - } - - /** - * Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr == addresses.begin(), "Only address is not at front."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator begin()const { return cbegin(); } - - /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.cend(), "Address for account doesn't exist"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator cend()const { return const_iterator( this ); } - - /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account doesn't exist"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator end()const { return cend(); } - - /** - * Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return A reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.crbegin(); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Last Record "); - * itr++; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect Second Last Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator crbegin()const { return std::make_reverse_iterator(cend()); } - - /** - * Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return A reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.rbegin(); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Last Record "); - * itr++; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect Second Last Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator rbegin()const { return crbegin(); } - - /** - * Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.crend(); - * itr--; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect First Record "); - * itr--; - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Second Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator crend()const { return std::make_reverse_iterator(cbegin()); } - - /** - * Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.rend(); - * itr--; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect First Record "); - * itr--; - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Second Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator rend()const { return crend(); } - - /** - * Searches for the `object_type` with the lowest primary key that is greater than or equal to a given primary key. - * - * @param primary - Primary key that establishes the target value for the lower bound search. - * @return An iterator pointing to the `object_type` that has the lowest primary key that is greater than or equal to `primary`. If an object could not be found, it will return the `end` iterator. If the table does not exist** it will return `-1`. - * - * Example: - * - * @code - * // This assumes the code from the get_index() example below. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.lower_bound(zipnumb); - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect First Lower Bound Record "); - * itr++; - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Second Lower Bound Record"); - * itr++; - * eosio::check(itr == zip_index.end(), "Lock arf, Incorrect End of Iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator lower_bound( uint64_t primary )const { - auto itr = db_lowerbound_i64( _code.value, _scope, static_cast(TableName), primary ); - if( itr < 0 ) return end(); - const auto& obj = load_object_by_primary_iterator( itr ); - return {this, &obj}; - } - - /** - * Searches for the `object_type` with the lowest primary key that is greater than a given primary key. - * - * @param primary - Primary key that establishes the target value for the upper bound search - * @return An iterator pointing to the `object_type` that has the highest primary key that is less than or equal to `primary`. If an object could not be found, it will return the `end` iterator. If the table does not exist** it will return `-1`. - * - * Example: - * - * @code - * // This assumes the code from the get_index() example below. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.upper_bound(zipnumb); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect First Upper Bound Record "); - * itr++; - * eosio::check(itr == zip_index.end(), "Lock arf, Incorrect End of Iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator upper_bound( uint64_t primary )const { - auto itr = db_upperbound_i64( _code.value, _scope, static_cast(TableName), primary ); - if( itr < 0 ) return end(); - const auto& obj = load_object_by_primary_iterator( itr ); - return {this, &obj}; - } - - /** - * Returns an available primary key. - * - * @return An available (unused) primary key value. - * - * Notes: - * Intended to be used in tables in which the primary keys of the table are strictly intended to be auto-incrementing, and thus will never be set to custom values by the contract. Violating this expectation could result in the table appearing to be full due to inability to allocate an available primary key. - * Ideally this method would only be used to determine the appropriate primary key to use within new objects added to a table in which the primary keys of the table are strictly intended from the beginning to be autoincrementing and thus will not ever be set to custom arbitrary values by the contract. Violating this agreement could result in the table appearing full when in reality there is plenty of space left. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses(_self, _self.value); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.key = addresses.available_primary_key(); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - uint64_t available_primary_key()const { - if( _next_primary_key == unset_next_primary_key ) { - // This is the first time available_primary_key() is called for this multi_index instance. - if( begin() == end() ) { // empty table - _next_primary_key = 0; - } else { - auto itr = --end(); // last row of table sorted by primary key - auto pk = itr->primary_key(); // largest primary key currently in table - if( pk >= no_available_primary_key ) // Reserve the tags - _next_primary_key = no_available_primary_key; - else - _next_primary_key = pk + 1; - } - } - - eosio::check( _next_primary_key < no_available_primary_key, "next primary key in table is at autoincrement limit"); - return _next_primary_key; - } - - /** - * Returns an appropriately typed Secondary Index. - * - * @tparam IndexName - the ID of the desired secondary index - * - * @return An index of the appropriate type: Primitive 64-bit unsigned integer key (idx64), Primitive 128-bit unsigned integer key (idx128), 128-bit fixed-size lexicographical key (idx128), 256-bit fixed-size lexicographical key (idx256), Floating point key, Double precision floating point key, Long Double (quadruple) precision floating point key - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * }; - * public: - * addressbook(name receiver, name code, datastream ds):contract(receiver, code, ds) {} - * typedef eosio::multi_index< name("address"), address, indexed_by< name("zip"), const_mem_fun > address_index; - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * uint32_t zipnumb = 93446; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.find(zipnumb); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Record "); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - auto get_index() { - using namespace _multi_index_detail; - - auto res = hana::find_if( _indices, []( auto&& in ) { - return std::integral_constant(std::decay(in))::type>::type::index_name) == static_cast(IndexName)>(); - }); - - static_assert( res != hana::nothing, "name provided is not the name of any secondary index within multi_index" ); - - return typename decltype(+hana::at_c<0>(res.value()))::type(this); - } - - /** - * Returns an appropriately typed Secondary Index. - * - * @tparam IndexName - the ID of the desired secondary index - * - * @return An index of the appropriate type: Primitive 64-bit unsigned integer key (idx64), Primitive 128-bit unsigned integer key (idx128), 128-bit fixed-size lexicographical key (idx128), 256-bit fixed-size lexicographical key (idx256), Floating point key, Double precision floating point key, Long Double (quadruple) precision floating point key - * - * Example: - * - * @code - * // This assumes the code from the get_index() example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.upper_bound(zipnumb); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect First Upper Bound Record "); - * itr++; - * eosio::check(itr == zip_index.end(), "Lock arf, Incorrect End of Iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - auto get_index()const { - using namespace _multi_index_detail; - - auto res = hana::find_if( _indices, []( auto&& in ) { - return std::integral_constant(std::decay(in))::type>::type::index_name) == static_cast(IndexName)>(); - }); - - static_assert( res != hana::nothing, "name provided is not the name of any secondary index within multi_index" ); - - return typename decltype(+hana::at_c<1>(res.value()))::type(this); - } - - /** - * Returns an iterator to the given object in a Multi-Index table. - * - * @param obj - A reference to the desired object - * - * @return An iterator to the given object - * - * Example: - * - * @code - * // This assumes the code from the get_index() example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * auto user = addresses.get("dan"_n); - * auto itr = address.find("dan"_n); - * eosio::check(iterator_to(user) == itr, "Invalid iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator iterator_to( const T& obj )const { - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == this, "object passed to iterator_to is not in multi_index" ); - return {this, &objitem}; - } - /** - * Adds a new object (i.e., row) to the table. - * - * @param payer - Account name of the payer for the Storage usage of the new object - * @param constructor - Lambda function that does an in-place initialization of the object to be created in the table - * - * @pre A multi index table has been instantiated - * @post A new object is created in the Multi-Index table, with a unique primary key (as specified in the object). The object is serialized and written to the table. If the table does not exist, it is created. - * @post Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. - * @post The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. - * - * @return A primary key iterator to the newly created object - * - * Exception - The account is not authorized to write to the table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses(_self, _self.value); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = "dan"_n; - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - const_iterator emplace( name payer, Lambda&& constructor ) { - using namespace _multi_index_detail; - - eosio::check( _code.value == current_receiver(), "cannot create objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto itm = std::make_unique( this, [&]( auto& i ){ - T& obj = static_cast(i); - constructor( obj ); - - size_t size = pack_size( obj ); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - - datastream ds( (char*)buffer, size ); - ds << obj; - - auto pk = obj.primary_key(); - - i.__primary_itr = db_store_i64( _scope, static_cast(TableName), payer.value, pk, buffer, size ); - - if ( max_stack_buffer_size < size ) { - free(buffer); - } - - if( pk >= _next_primary_key ) - _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - i.__iters[index_type::number()] = secondary_index_db_functions::db_idx_store( _scope, index_type::name(), payer.value, obj.primary_key(), index_type::extract_secondary_key(obj) ); - }); - }); - - const item* ptr = itm.get(); - auto pk = itm->primary_key(); - auto pitr = itm->__primary_itr; - - _items_vector.emplace_back( std::move(itm), pk, pitr ); - - return {this, ptr}; - } - - /** - * Modifies an existing object in a table. - * - * @param itr - an iterator pointing to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row - * @param updater - lambda function that updates the target object - * - * @pre itr points to an existing element - * @pre payer is a valid account that is authorized to execute the action and be billed for storage usage. - * - * @post The modified object is serialized, then replaces the existing object in the table. - * @post Secondary indices are updated; the primary key of the updated object is not changed. - * @post The payer is charged for the storage usage of the updated object. - * @post If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). - * @post If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. - * - * Exceptions: - * If called with an invalid precondition, execution is aborted. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account not found"); - * addresses.modify( itr, account payer, [&]( auto& address ) { - * address.city = "San Luis Obispo"; - * address.state = "CA"; - * }); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - void modify( const_iterator itr, name payer, Lambda&& updater ) { - eosio::check( itr != end(), "cannot pass end iterator to modify" ); - - modify( *itr, payer, std::forward(updater) ); - } - - /** - * Modifies an existing object in a table. - * - * @param obj - a reference to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row - * @param updater - lambda function that updates the target object - * - * @pre obj is an existing object in the table - * @pre payer is a valid account that is authorized to execute the action and be billed for storage usage. - * - * @post The modified object is serialized, then replaces the existing object in the table. - * @post Secondary indices are updated; the primary key of the updated object is not changed. - * @post The payer is charged for the storage usage of the updated object. - * @post If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). - * @post If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. - * - * Exceptions: - * If called with an invalid precondition, execution is aborted. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account not found"); - * addresses.modify( *itr, payer, [&]( auto& address ) { - * address.city = "San Luis Obispo"; - * address.state = "CA"; - * }); - * eosio::check(itr->city == "San Luis Obispo", "Lock arf, Address not modified"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - void modify( const T& obj, name payer, Lambda&& updater ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == this, "object passed to modify is not in multi_index" ); - auto& mutableitem = const_cast(objitem); - eosio::check( _code.value == current_receiver(), "cannot modify objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto secondary_keys = hana::transform( _indices, [&]( auto&& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - return index_type::extract_secondary_key( obj ); - }); - - auto pk = obj.primary_key(); - - auto& mutableobj = const_cast(obj); // Do not forget the auto& otherwise it would make a copy and thus not update at all. - updater( mutableobj ); - - eosio::check( pk == obj.primary_key(), "updater cannot change primary key when modifying an object" ); - - size_t size = pack_size( obj ); - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - - datastream ds( (char*)buffer, size ); - ds << obj; - - db_update_i64( objitem.__primary_itr, payer.value, buffer, size ); - - if ( max_stack_buffer_size < size ) { - free( buffer ); - } - - if( pk >= _next_primary_key ) - _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - auto secondary = index_type::extract_secondary_key( obj ); - if( memcmp( &hana::at_c(secondary_keys), &secondary, sizeof(secondary) ) != 0 ) { - auto indexitr = mutableitem.__iters[index_type::number()]; - - if( indexitr < 0 ) { - typename index_type::secondary_key_type temp_secondary_key; - indexitr = mutableitem.__iters[index_type::number()] - = secondary_index_db_functions::db_idx_find_primary( _code.value, _scope, index_type::name(), pk, temp_secondary_key ); - } - - secondary_index_db_functions::db_idx_update( indexitr, payer.value, secondary ); - } - }); - } - - /** - * Retrieves an existing object from a table using its primary key. - * - * @param primary - Primary key value of the object - * @return A constant reference to the object containing the specified primary key. - * - * Exception - No object matches the given key - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto user = addresses.get("dan"_n); - * eosio::check(user.first_name == "Daniel", "Couldn't get him."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const T& get( uint64_t primary, const char* error_msg = "unable to find key" )const { - auto result = find( primary ); - eosio::check( result != cend(), error_msg ); - return *result; - } - - /** - * Search for an existing object in a table using its primary key. - * - * @param primary - Primary key value of the object - * @return An iterator to the found object which has a primary key equal to `primary` OR the `end` iterator of the referenced table if an object with primary key `primary` is not found. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Couldn't get him."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator find( uint64_t primary )const { - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == primary; - }); - if( itr2 != _items_vector.rend() ) - return iterator_to(*(itr2->_item)); - - auto itr = db_find_i64( _code.value, _scope, static_cast(TableName), primary ); - if( itr < 0 ) return end(); - - const item& i = load_object_by_primary_iterator( itr ); - return iterator_to(static_cast(i)); - } - - /** - * Search for an existing object in a table using its primary key. - * - * @param primary - Primary key value of the object - * @param error_msg - error message if an object with primary key `primary` is not found. - * @return An iterator to the found object which has a primary key equal to `primary` OR throws an exception if an object with primary key `primary` is not found. - */ - - const_iterator require_find( uint64_t primary, const char* error_msg = "unable to find key" )const { - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == primary; - }); - if( itr2 != _items_vector.rend() ) - return iterator_to(*(itr2->_item)); - - auto itr = db_find_i64( _code.value, _scope, static_cast(TableName), primary ); - eosio::check( itr >= 0, error_msg ); - - const item& i = load_object_by_primary_iterator( itr ); - return iterator_to(static_cast(i)); - } - - /** - * Remove an existing object from a table using its primary key. - * - * @param itr - An iterator pointing to the object to be removed - * - * @pre itr points to an existing element - * @post The object is removed from the table and all associated storage is reclaimed. - * @post Secondary indices associated with the table are updated. - * @post The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. - * - * @return For the signature with `const_iterator`, returns a pointer to the object following the removed object. - * - * Exceptions: - * The object to be removed is not in the table. - * The action is not authorized to modify the table. - * The given iterator is invalid. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account not found"); - * addresses.erase( itr ); - * eosio::check(itr != addresses.end(), "Everting lock arf, Address not erased properly"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator erase( const_iterator itr ) { - eosio::check( itr != end(), "cannot pass end iterator to erase" ); - - const auto& obj = *itr; - ++itr; - - erase(obj); - - return itr; - } - - /** - * Remove an existing object from a table using its primary key. - * - * @param obj - Object to be removed - * - * @pre obj is an existing object in the table - * @post The object is removed from the table and all associated storage is reclaimed. - * @post Secondary indices associated with the table are updated. - * @post The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. - * - * Exceptions: - * The object to be removed is not in the table. - * The action is not authorized to modify the table. - * The given iterator is invalid. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Record is not found"); - * addresses.erase(*itr); - * itr = addresses.find("dan"_n); - * eosio::check(itr == addresses.end(), "Record is not deleted"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - void erase( const T& obj ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == this, "object passed to erase is not in multi_index" ); - eosio::check( _code.value == current_receiver(), "cannot erase objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto pk = objitem.primary_key(); - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == pk; - }); - - eosio::check( itr2 != _items_vector.rend(), "attempt to remove object that was not in multi_index" ); - - _items_vector.erase(--(itr2.base())); - - db_remove_i64( objitem.__primary_itr ); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - auto i = objitem.__iters[index_type::number()]; - if( i < 0 ) { - typename index_type::secondary_key_type secondary; - i = secondary_index_db_functions::db_idx_find_primary( _code.value, _scope, index_type::name(), objitem.primary_key(), secondary ); - } - if( i >= 0 ) - secondary_index_db_functions::db_idx_remove( i ); - }); - } - -}; - /// @} -} /// eosio diff --git a/libraries/eosiolib/name.hpp b/libraries/eosiolib/name.hpp deleted file mode 100644 index 33f0783c42..0000000000 --- a/libraries/eosiolib/name.hpp +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "system.hpp" -#include "serialize.hpp" - -#include -#include - -#warning " is deprecated use " -namespace eosio { - - /** - * @defgroup name - * @ingroup types - * @brief EOSIO Types - * @{ - - /* - * Wraps a %uint64_t to ensure it is only passed to methods that expect a %name. - * Ensures value is only passed to methods that expect a %name and that no mathematical - * operations occur. Also enables specialization of print - */ - struct name { - public: - enum class raw : uint64_t {}; - - /** - * Construct a new name - * - * @brief Construct a new name object defaulting to a value of 0 - * - */ - constexpr name() : value(0) {} - - /** - * Construct a new name given a unit64_t value - * - * @brief Construct a new name object initialising value with v - * @param v - The unit64_t value - * - */ - constexpr explicit name( uint64_t v ) - :value(v) - {} - - /** - * Construct a new name given a scoped enumerated type of raw (uint64_t). - * - * @brief Construct a new name object initialising value with r - * @param r - The raw value which is a scoped enumerated type of unit64_t - * - */ - constexpr explicit name( name::raw r ) - :value(static_cast(r)) - {} - - /** - * Construct a new name given an string. - * - * @brief Construct a new name object initialising value with str - * @param str - The string value which validated then converted to unit64_t - * - */ - constexpr explicit name( std::string_view str ) - :value(0) - { - if( str.size() > 13 ) { - eosio::check( false, "string is too long to be a valid name" ); - } - if( str.empty() ) { - return; - } - - auto n = std::min( (uint32_t)str.size(), (uint32_t)12u ); - for( decltype(n) i = 0; i < n; ++i ) { - value <<= 5; - value |= char_to_value( str[i] ); - } - value <<= ( 4 + 5*(12 - n) ); - if( str.size() == 13 ) { - uint64_t v = char_to_value( str[12] ); - if( v > 0x0Full ) { - eosio::check(false, "thirteenth character in name cannot be a letter that comes after j"); - } - value |= v; - } - } - - /** - * Converts a %name Base32 symbol into its corresponding value - * - * @param c - Character to be converted - * @return constexpr char - Converted value - */ - static constexpr uint8_t char_to_value( char c ) { - if( c == '.') - return 0; - else if( c >= '1' && c <= '5' ) - return (c - '1') + 1; - else if( c >= 'a' && c <= 'z' ) - return (c - 'a') + 6; - else - eosio::check( false, "character is not in allowed character set for names" ); - - return 0; // control flow will never reach here; just added to suppress warning - } - - /** - * Returns the length of the %name - */ - constexpr uint8_t length()const { - constexpr uint64_t mask = 0xF800000000000000ull; - - if( value == 0 ) - return 0; - - uint8_t l = 0; - uint8_t i = 0; - for( auto v = value; i < 13; ++i, v <<= 5 ) { - if( (v & mask) > 0 ) { - l = i; - } - } - - return l + 1; - } - - /** - * Returns the suffix of the %name - */ - constexpr name suffix()const { - uint32_t remaining_bits_after_last_actual_dot = 0; - uint32_t tmp = 0; - for( int32_t remaining_bits = 59; remaining_bits >= 4; remaining_bits -= 5 ) { // Note: remaining_bits must remain signed integer - // Get characters one-by-one in name in order from left to right (not including the 13th character) - auto c = (value >> remaining_bits) & 0x1Full; - if( !c ) { // if this character is a dot - tmp = static_cast(remaining_bits); - } else { // if this character is not a dot - remaining_bits_after_last_actual_dot = tmp; - } - } - - uint64_t thirteenth_character = value & 0x0Full; - if( thirteenth_character ) { // if 13th character is not a dot - remaining_bits_after_last_actual_dot = tmp; - } - - if( remaining_bits_after_last_actual_dot == 0 ) // there is no actual dot in the %name other than potentially leading dots - return name{value}; - - // At this point remaining_bits_after_last_actual_dot has to be within the range of 4 to 59 (and restricted to increments of 5). - - // Mask for remaining bits corresponding to characters after last actual dot, except for 4 least significant bits (corresponds to 13th character). - uint64_t mask = (1ull << remaining_bits_after_last_actual_dot) - 16; - uint32_t shift = 64 - remaining_bits_after_last_actual_dot; - - return name{ ((value & mask) << shift) + (thirteenth_character << (shift-1)) }; - } - - /** - * Casts a name to raw - * - * @return Returns an instance of raw based on the value of a name - */ - constexpr operator raw()const { return raw(value); } - - /** - * Explicit cast to bool of the uint64_t value of the name - * - * @return Returns true if the name is set to the default value of 0 else true. - */ - constexpr explicit operator bool()const { return value != 0; } - - /** - * Writes the %name as a string to the provided char buffer - * - * @pre The range [begin, end) must be a valid range of memory to write to. - * @param begin - The start of the char buffer - * @param end - Just past the end of the char buffer - * @param dry_run - If true, do not actually write anything into the range. - * @return char* - Just past the end of the last character that would be written assuming dry_run == false and end was large enough to provide sufficient space. (Meaning only applies if returned pointer >= begin.) - * @post If the output string fits within the range [begin, end) and dry_run == false, the range [begin, returned pointer) contains the string representation of the %name. Nothing is written if dry_run == true or returned pointer > end (insufficient space) or if returned pointer < begin (overflow in calculating desired end). - */ - char* write_as_string( char* begin, char* end, bool dry_run = false )const { - static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz"; - constexpr uint64_t mask = 0xF800000000000000ull; - - if( dry_run || (begin + 13 < begin) || (begin + 13 > end) ) { - char* actual_end = begin + length(); - if( dry_run || (actual_end < begin) || (actual_end > end) ) return actual_end; - } - - auto v = value; - for( auto i = 0; i < 13; ++i, v <<= 5 ) { - if( v == 0 ) return begin; - - auto indx = (v & mask) >> (i == 12 ? 60 : 59); - *begin = charmap[indx]; - ++begin; - } - - return begin; - } - - /** - * Returns the name as a string. - * - * @brief Returns the name value as a string by calling write_as_string() and returning the buffer produced by write_as_string() - */ - std::string to_string()const { - char buffer[13]; - auto end = write_as_string( buffer, buffer + sizeof(buffer) ); - return {buffer, end}; - } - - /** - * Equivalency operator. Returns true if a == b (are the same) - * - * @return boolean - true if both provided %name values are the same - */ - friend constexpr bool operator == ( const name& a, const name& b ) { - return a.value == b.value; - } - - /** - * Inverted equivalency operator. Returns true if a != b (are different) - * - * @return boolean - true if both provided %name values are not the same - */ - friend constexpr bool operator != ( const name& a, const name& b ) { - return a.value != b.value; - } - - /** - * Less than operator. Returns true if a < b. - * - * @return boolean - true if %name `a` is less than `b` - */ - friend constexpr bool operator < ( const name& a, const name& b ) { - return a.value < b.value; - } - - - uint64_t value = 0; - - EOSLIB_SERIALIZE( name, (value) ) - }; - - namespace detail { - template - struct to_const_char_arr { - static constexpr const char value[] = {Str...}; - }; - } /// namespace detail -} /// namespace eosio - -/** - * %name literal operator - * - * @brief "foo"_n is a shortcut for name("foo") - */ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template" -template -inline constexpr eosio::name operator""_n() { - constexpr auto x = eosio::name{std::string_view{eosio::detail::to_const_char_arr::value, sizeof...(Str)}}; - return x; -} -#pragma clang diagnostic pop diff --git a/libraries/eosiolib/permission.h b/libraries/eosiolib/permission.h deleted file mode 100644 index 21f1f8c7ee..0000000000 --- a/libraries/eosiolib/permission.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "types.h" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -extern "C" { - - /** - * @defgroup permission_c Permissions C API - * @ingroup c_api - * - * @brief Methods for testing against transactions, delays, keys and permissions - * @{ - */ - - /** - * Checks if a transaction is authorized by a provided set of keys and permissions - * - * @param trx_data - pointer to the start of the serialized transaction - * @param trx_size - size (in bytes) of the serialized transaction - * @param pubkeys_data - pointer to the start of the serialized vector of provided public keys - * @param pubkeys_size - size (in bytes) of serialized vector of provided public keys (can be 0 if no public keys are to be provided) - * @param perms_data - pointer to the start of the serialized vector of provided permissions (empty permission name acts as wildcard) - * @param perms_size - size (in bytes) of the serialized vector of provided permissions - * - * @return 1 if the transaction is authorized, 0 otherwise - */ - __attribute__((eosio_wasm_import)) - int32_t - check_transaction_authorization( const char* trx_data, uint32_t trx_size, - const char* pubkeys_data, uint32_t pubkeys_size, - const char* perms_data, uint32_t perms_size - ); - - /** - * Checks if a permission is authorized by a provided delay and a provided set of keys and permissions - * - * @param account - the account owner of the permission - * @param permission - the name of the permission to check for authorization - * @param pubkeys_data - pointer to the start of the serialized vector of provided public keys - * @param pubkeys_size - size (in bytes) of serialized vector of provided public keys (can be 0 if no public keys are to be provided) - * @param perms_data - pointer to the start of the serialized vector of provided permissions (empty permission name acts as wildcard) - * @param perms_size - size (in bytes) of the serialized vector of provided permissions - * @param delay_us - the provided delay in microseconds (cannot exceed INT64_MAX) - * - * @return 1 if the permission is authorized, 0 otherwise - */ - __attribute__((eosio_wasm_import)) - int32_t - check_permission_authorization( capi_name account, - capi_name permission, - const char* pubkeys_data, uint32_t pubkeys_size, - const char* perms_data, uint32_t perms_size, - uint64_t delay_us - ); - - /** - * Returns the last used time of a permission - * - * @param account - the account owner of the permission - * @param permission - the name of the permission - * - * @return the last used time (in microseconds since Unix epoch) of the permission - */ - __attribute__((eosio_wasm_import)) - int64_t get_permission_last_used( capi_name account, capi_name permission ); - - - /** - * Returns the creation time of an account - * - * @param account - the account - * - * @return the creation time (in microseconds since Unix epoch) of the account - */ - __attribute__((eosio_wasm_import)) - int64_t get_account_creation_time( capi_name account ); - - ///@} - -} diff --git a/libraries/eosiolib/permission.hpp b/libraries/eosiolib/permission.hpp deleted file mode 100644 index 70fa832503..0000000000 --- a/libraries/eosiolib/permission.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "permission.h" -#include "transaction.hpp" -#include "crypto.hpp" - -#include -#include - -#warning " is deprecated use " -namespace eosio { - - /** - * @addtogroup permission Permission C++ API - * @brief Defines C++ API functions for validating authorization of keys and permissions - * @ingroup types - * @{ - */ - - /** - * Checks if a transaction is authorized by a provided set of keys and permissions - * - * @param trx - the transaction for which to check authorizations - * @param provided_permissions - the set of permissions which have authorized the transaction (empty permission name acts as wildcard) - * @param provided_keys - the set of public keys which have authorized the transaction - * - * @return whether the transaction was authorized by provided keys and permissions - */ - bool - check_transaction_authorization( const transaction& trx, - const std::set& provided_permissions , - const std::set& provided_keys = std::set() - ) - { - auto packed_trx = pack(trx); - - std::vector packed_keys; - auto nkeys = provided_keys.size(); - if( nkeys > 0 ) { - packed_keys = pack(provided_keys); - } - - std::vector packed_perms; - auto nperms = provided_permissions.size(); - if( nperms > 0 ) { - packed_perms = pack(provided_permissions); - } - - auto res = ::check_transaction_authorization( packed_trx.data(), - packed_trx.size(), - (nkeys > 0) ? packed_keys.data() : (const char*)0, - (nkeys > 0) ? packed_keys.size() : 0, - (nperms > 0) ? packed_perms.data() : (const char*)0, - (nperms > 0) ? packed_perms.size() : 0 - ); - - return (res > 0); - } - - /** - * Checks if a permission is authorized by a provided delay and a provided set of keys and permissions - * - * @param account - the account owner of the permission - * @param permission - the permission name to check for authorization - * @param provided_keys - the set of public keys which have authorized the transaction - * @param provided_permissions - the set of permissions which have authorized the transaction (empty permission name acts as wildcard) - * @param provided_delay_us - the provided delay in microseconds (cannot exceed INT64_MAX) - * - * @return whether the permission was authorized by provided delay, keys, and permissions - */ - bool - check_permission_authorization( name account, - name permission, - const std::set& provided_keys, - const std::set& provided_permissions = std::set(), - uint64_t provided_delay_us = static_cast(std::numeric_limits::max()) - ) - { - std::vector packed_keys; - auto nkeys = provided_keys.size(); - if( nkeys > 0 ) { - packed_keys = pack(provided_keys); - } - - std::vector packed_perms; - auto nperms = provided_permissions.size(); - if( nperms > 0 ) { - packed_perms = pack(provided_permissions); - } - - auto res = ::check_permission_authorization( account.value, - permission.value, - (nkeys > 0) ? packed_keys.data() : (const char*)0, - (nkeys > 0) ? packed_keys.size() : 0, - (nperms > 0) ? packed_perms.data() : (const char*)0, - (nperms > 0) ? packed_perms.size() : 0, - provided_delay_us - ); - - return (res > 0); - } - - ///@} - -} diff --git a/libraries/eosiolib/print.h b/libraries/eosiolib/print.h deleted file mode 100644 index 9936cf8fff..0000000000 --- a/libraries/eosiolib/print.h +++ /dev/null @@ -1,187 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "types.h" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -/** - * @defgroup console_c Console C API - * @ingroup c_api - * @brief Defnes %C API to log/print text messages - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * Prints string - * - * @param cstr - a null terminated string - * - * Example: - * - * @code - * prints("Hello World!"); // Output: Hello World! - * @endcode - */ - __attribute__((eosio_wasm_import)) - void prints( const char* cstr ); - - /** - * Prints string up to given length - * - * @param cstr - pointer to string - * @param len - len of string to be printed - * - * Example: - * - * @code - * prints_l("Hello World!", 5); // Output: Hello - * @endcode - */ - __attribute__((eosio_wasm_import)) - void prints_l( const char* cstr, uint32_t len); - - /** - * Prints value as a 64 bit signed integer - * - * @brief Prints value as a 64 bit signed integer - * @param value of 64 bit signed integer to be printed - * - * Example: - * - * @code - * printi(-1e+18); // Output: -1000000000000000000 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printi( int64_t value ); - - /** - * Prints value as a 64 bit unsigned integer - * - * @param value of 64 bit unsigned integer to be printed - * - * Example: - * - * @code - * printui(1e+18); // Output: 1000000000000000000 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printui( uint64_t value ); - - /** - * Prints value as a 128 bit signed integer - * - * @param value is a pointer to the 128 bit signed integer to be printed - * - * Example: - * - * @code - * int128_t large_int(-87654323456); - * printi128(&large_int); // Output: -87654323456 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printi128( const int128_t* value ); - - /** - * Prints value as a 128 bit unsigned integer - * - * @param value is a pointer to the 128 bit unsigned integer to be printed - * - * Example: - * - * @code - * uint128_t large_int(87654323456); - * printui128(&large_int); // Output: 87654323456 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printui128( const uint128_t* value ); - - /** - * Prints value as single-precision floating point number - * - * @param value of float to be printed - * - * Example: - * - * @code - * float value = 5.0 / 10.0; - * printsf(value); // Output: 0.5 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printsf(float value); - - /** - * Prints value as double-precision floating point number - * - * @param value of double to be printed - * - * Example: - * - * @code - * double value = 5.0 / 10.0; - * printdf(value); // Output: 0.5 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printdf(double value); - - /** - * Prints value as quadruple-precision floating point number - * - * @param value is a pointer to the long double to be printed - * - * Example: - * - * @code - * long double value = 5.0 / 10.0; - * printqf(value); // Output: 0.5 - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printqf(const long double* value); - - /** - * Prints a 64 bit names as base32 encoded string - * - * @param name - 64 bit name to be printed - * - * Example: - * @code - * printn("abcde"_n); // Output: abcde - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printn( uint64_t name ); - - /** - * Prints hexidecimal data of length datalen - * - * @brief Prints hexidecimal data of length datalen - * @param data to be printed - * @param datalen length of the data to be printed - * - * Example - * @code - * unsigned char rawData[9] = {0x49 0x20 0x6C 0x6F 0x76 0x65 0x20 0x62 0x6D}; - * printhex(&rawData, 9); - * @endcode - */ - __attribute__((eosio_wasm_import)) - void printhex( const void* data, uint32_t datalen ); - - /// @} -#ifdef __cplusplus -} -#endif diff --git a/libraries/eosiolib/print.hpp b/libraries/eosiolib/print.hpp deleted file mode 100644 index e8b480a0f6..0000000000 --- a/libraries/eosiolib/print.hpp +++ /dev/null @@ -1,260 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "print.h" -#include "name.hpp" -#include "symbol.hpp" -#include "fixed_bytes.hpp" - -#include -#include - -#warning " is deprecated use " -/** - * @defgroup console Console C++ API - * @ingroup core - * @brief Defines C++ wrapper to log/print text messages - * - * @details This API uses C++ variadic templates and type detection to - * make it easy to print any native type. You can even overload - * the `print()` method for your own custom types. - * - * **Example:** - * ``` - * print( "hello world, this is a number: ", 5 ); - * ``` - * - * @section override Overriding Print for your Types - * - * There are two ways to overload print: - * 1. implement void print( const T& ) - * 2. implement T::print()const - * - * @{ - */ - - -namespace eosio { - - /** - * Prints string - * - * @param ptr - a null terminated string - */ - inline void print( const char* ptr ) { - prints(ptr); - } - - /** - * Prints 8-128 bit signed integer - * - * @param num to be printed - */ - template >::value && - std::is_signed>::value, int> = 0> - inline void print( T num ) { - if constexpr(std::is_same::value) - printi128(&num); - else if constexpr(std::is_same::value) - prints_l( &num, 1 ); - else - printi(num); - } - - /** - * Prints 8-128 bit unsigned integer - * - * @param num to be printed - */ - template >::value && - !std::is_signed>::value, int> = 0> - inline void print( T num ) { - if constexpr(std::is_same::value) - printui128(&num); - else if constexpr(std::is_same::value) - prints(num?"true":"false"); - else - printui(num); - } - - /** - * Prints single-precision floating point number (i.e. float) - * - * @param num to be printed - */ - inline void print( float num ) { printsf( num ); } - - /** - * Prints double-precision floating point number (i.e. double) - * - * @param num to be printed - */ - inline void print( double num ) { printdf( num ); } - - /** - * Prints quadruple-precision floating point number (i.e. long double) - * - * @param num to be printed - */ - inline void print( long double num ) { printqf( &num ); } - - /** - * Prints fixed_bytes as a hexidecimal string - * - * @brief Prints fixed_bytes as a hexidecimal string - * @param val to be printed - */ - template - inline void print( const fixed_bytes& val ) { - auto arr = val.extract_as_byte_array(); - printhex(static_cast(arr.data()), arr.size()); - } - - /** - * Prints fixed_bytes as a hexidecimal string - * - * @brief Prints fixed_bytes as a hexidecimal string - * @param val to be printed - */ - template - inline void print( fixed_bytes& val ) { - print(static_cast&>(val)); - } - - /** - * Prints a 64 bit names as base32 encoded string - * - * @param name 64 bit name to be printed - */ - inline void print( name name ) { - printn(name.value); - } - - /** - * Prints a symbol_code - * - * @param sym_code symbol code to be printed - */ - inline void print( eosio::symbol_code sym_code ) { - char buffer[7]; - auto end = sym_code.write_as_string( buffer, buffer + sizeof(buffer) ); - if( buffer < end ) - prints_l( buffer, (end-buffer) ); - } - - /** - * Prints class object - * - * @param t to be printed - * @pre T must implements print() function - */ - template>::value, int> = 0> - inline void print( T&& t ) { - if constexpr (std::is_same, std::string>::value) - prints_l( t.c_str(), t.size() ); - else if constexpr (std::is_same, char*>::value) - prints(t); - else - t.print(); - } - - /** - * Prints null terminated string - * - * @param s null terminated string to be printed - */ - inline void print_f( const char* s ) { - prints(s); - } - - /** - * Prints formatted string. It behaves similar to C printf/ - * - * @tparam Arg - Type of the value used to replace the format specifier - * @tparam Args - Type of the value used to replace the format specifier - * @param s - Null terminated string with to be printed (it can contains format specifier) - * @param val - The value used to replace the format specifier - * @param rest - The values used to replace the format specifier - * - * Example: - * @code - * print_f("Number of apples: %", 10); - * @endcode - */ - 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++; - } - } - - /** - * Print out value / list of values - * - * @tparam Arg - Type of the value used to replace the format specifier - * @tparam Args - Type of the value used to replace the format specifier - * @param a - The value to be printed - * @param args - The other values to be printed - * - * Example: - * - * @code - * const char *s = "Hello World!"; - * uint64_t unsigned_64_bit_int = 1e+18; - * uint128_t unsigned_128_bit_int (87654323456); - * uint64_t string_as_unsigned_64_bit = "abcde"_n; - * print(s , unsigned_64_bit_int, unsigned_128_bit_int, string_as_unsigned_64_bit); - * // Ouput: Hello World!100000000000000000087654323456abcde - * @endcode - */ - template - void print( Arg&& a, Args&&... args ) { - print(std::forward(a)); - print(std::forward(args)...); - } - - /** - * Simulate C++ style streams - */ - class iostream {}; - - /** - * Overload c++ iostream - * - * @tparam Arg - Type of the value used to replace the format specifier - * @tparam Args - Type of the value used to replace the format specifier - * @param out - Output strem - * @param v - The value to be printed - * @return iostream& - Reference to the input output stream - * - * Example: - * - * @code - * const char *s = "Hello World!"; - * uint64_t unsigned_64_bit_int = 1e+18; - * uint128_t unsigned_128_bit_int (87654323456); - * uint64_t string_as_unsigned_64_bit = "abcde"_n; - * std::out << s << " " << unsigned_64_bit_int << " " << unsigned_128_bit_int << " " << string_as_unsigned_64_bit; - * // Output: Hello World! 1000000000000000000 87654323456 abcde - * @endcode - */ - template - inline iostream& operator<<( iostream& out, const T& v ) { - print( v ); - return out; - } - - static iostream cout; - - /// @} consolecppapi - - -} diff --git a/libraries/eosiolib/privileged.h b/libraries/eosiolib/privileged.h deleted file mode 100644 index 29c8ef5dcc..0000000000 --- a/libraries/eosiolib/privileged.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * @defgroup privileged_c Privileged C API - * @ingroup c_api - * @brief Defines %C Privileged API - */ - - /** - * Get the resource limits of an account - * - * @param account - name of the account whose resource limit to get - * @param ram_bytes - pointer to `int64_t` to hold retrieved ram limit in absolute bytes - * @param net_weight - pointer to `int64_t` to hold net limit - * @param cpu_weight - pointer to `int64_t` to hold cpu limit - */ - __attribute__((eosio_wasm_import)) - void get_resource_limits( capi_name account, int64_t* ram_bytes, int64_t* net_weight, int64_t* cpu_weight ); - - /** - * Set the resource limits of an account - * - * @param account - name of the account whose resource limit to be set - * @param ram_bytes - ram limit in absolute bytes - * @param net_weight - fractionally proportionate net limit of available resources based on (weight / total_weight_of_all_accounts) - * @param cpu_weight - fractionally proportionate cpu limit of available resources based on (weight / total_weight_of_all_accounts) - */ - __attribute__((eosio_wasm_import)) - void set_resource_limits( capi_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ); - - /** - * Proposes a schedule change - * - * @note Once the block that contains the proposal becomes irreversible, the schedule is promoted to "pending" automatically. Once the block that promotes the schedule is irreversible, the schedule will become "active" - * @param producer_data - packed data of produce_keys in the appropriate producer schedule order - * @param producer_data_size - size of the data buffer - * - * @return -1 if proposing a new producer schedule was unsuccessful, otherwise returns the version of the new proposed schedule - */ - __attribute__((eosio_wasm_import)) - int64_t set_proposed_producers( char *producer_data, uint32_t producer_data_size ); - - /** - * Check if an account is privileged - * - * @param account - name of the account to be checked - * @return true if the account is privileged - * @return false if the account is not privileged - */ - __attribute__((eosio_wasm_import)) - bool is_privileged( capi_name account ); - - /** - * Set the privileged status of an account - * - * @param account - name of the account whose privileged account to be set - * @param is_priv - privileged status - */ - __attribute__((eosio_wasm_import)) - void set_privileged( capi_name account, bool is_priv ); - - /** - * Set the blockchain parameters - * - * @param data - pointer to blockchain parameters packed as bytes - * @param datalen - size of the packed blockchain parameters - * @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long that contains packed blockchain params data - */ - __attribute__((eosio_wasm_import)) - void set_blockchain_parameters_packed( char* data, uint32_t datalen ); - - /** - * Retrieve the blolckchain parameters - * - * @param data - output buffer of the blockchain parameters, only retrieved if sufficent size to hold packed data. - * @param datalen - size of the data buffer, 0 to report required size. - * @return size of the blockchain parameters - * @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long - * @post `data` is filled with packed blockchain parameters - */ - __attribute__((eosio_wasm_import)) - uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ); - -#ifdef __cplusplus -} -#endif diff --git a/libraries/eosiolib/privileged.hpp b/libraries/eosiolib/privileged.hpp deleted file mode 100644 index bcb9ee0663..0000000000 --- a/libraries/eosiolib/privileged.hpp +++ /dev/null @@ -1,190 +0,0 @@ -#pragma once -#include "privileged.h" -#include "serialize.hpp" -#include "crypto.hpp" - -#warning " is deprecated use " -namespace eosio { - - /** - * Defines C++ Privileged API - * - * @addtogroup privileged Privileged C++ API - * @ingroup contracts - * @{ - */ - - /** - * Tunable blockchain configuration that can be changed via consensus - */ - struct blockchain_parameters { - - /** - * The maxiumum net usage in instructions for a block - * @brief the maxiumum net usage in instructions for a block - */ - uint64_t max_block_net_usage; - - /** - * The target percent (1% == 100, 100%= 10,000) of maximum net usage; exceeding this triggers congestion handling - * @brief The target percent (1% == 100, 100%= 10,000) of maximum net usage; exceeding this triggers congestion handling - */ - uint32_t target_block_net_usage_pct; - - /** - * The maximum objectively measured net usage that the chain will allow regardless of account limits - * @brief The maximum objectively measured net usage that the chain will allow regardless of account limits - */ - uint32_t max_transaction_net_usage; - - /** - * The base amount of net usage billed for a transaction to cover incidentals - */ - uint32_t base_per_transaction_net_usage; - - /** - * The amount of net usage leeway available whilst executing a transaction (still checks against new limits without leeway at the end of the transaction) - * @brief The amount of net usage leeway available whilst executing a transaction (still checks against new limits without leeway at the end of the transaction) - */ - uint32_t net_usage_leeway; - - /** - * The numerator for the discount on net usage of context-free data - * @brief The numerator for the discount on net usage of context-free data - */ - uint32_t context_free_discount_net_usage_num; - - /** - * The denominator for the discount on net usage of context-free data - * @brief The denominator for the discount on net usage of context-free data - */ - uint32_t context_free_discount_net_usage_den; - - /** - * The maxiumum billable cpu usage (in microseconds) for a block - * @brief The maxiumum billable cpu usage (in microseconds) for a block - */ - uint32_t max_block_cpu_usage; - - /** - * The target percent (1% == 100, 100%= 10,000) of maximum cpu usage; exceeding this triggers congestion handling - * @brief The target percent (1% == 100, 100%= 10,000) of maximum cpu usage; exceeding this triggers congestion handling - */ - uint32_t target_block_cpu_usage_pct; - - /** - * The maximum billable cpu usage (in microseconds) that the chain will allow regardless of account limits - * @brief The maximum billable cpu usage (in microseconds) that the chain will allow regardless of account limits - */ - uint32_t max_transaction_cpu_usage; - - /** - * The minimum billable cpu usage (in microseconds) that the chain requires - * @brief The minimum billable cpu usage (in microseconds) that the chain requires - */ - uint32_t min_transaction_cpu_usage; - - /** - * Maximum lifetime of a transacton - * @brief Maximum lifetime of a transacton - */ - uint32_t max_transaction_lifetime; - - /** - * The number of seconds after the time a deferred transaction can first execute until it expires - * @brief the number of seconds after the time a deferred transaction can first execute until it expires - */ - uint32_t deferred_trx_expiration_window; - - - /** - * The maximum number of seconds that can be imposed as a delay requirement by authorization checks - * @brief The maximum number of seconds that can be imposed as a delay requirement by authorization checks - */ - uint32_t max_transaction_delay; - - /** - * Maximum size of inline action - * @brief Maximum size of inline action - */ - uint32_t max_inline_action_size; - - /** - * Maximum depth of inline action - * @brief Maximum depth of inline action - */ - uint16_t max_inline_action_depth; - - /** - * Maximum authority depth - * @brief Maximum authority depth - */ - uint16_t max_authority_depth; - - - EOSLIB_SERIALIZE( blockchain_parameters, - (max_block_net_usage)(target_block_net_usage_pct) - (max_transaction_net_usage)(base_per_transaction_net_usage)(net_usage_leeway) - (context_free_discount_net_usage_num)(context_free_discount_net_usage_den) - - (max_block_cpu_usage)(target_block_cpu_usage_pct) - (max_transaction_cpu_usage)(min_transaction_cpu_usage) - - (max_transaction_lifetime)(deferred_trx_expiration_window)(max_transaction_delay) - (max_inline_action_size)(max_inline_action_depth)(max_authority_depth) - ) - }; - - /** - * @brief Set the blockchain parameters - * Set the blockchain parameters - * @param params - New blockchain parameters to set - */ - void set_blockchain_parameters(const eosio::blockchain_parameters& params); - - /** - * @brief Retrieve the blolckchain parameters - * Retrieve the blolckchain parameters - * @param params - It will be replaced with the retrieved blockchain params - */ - void get_blockchain_parameters(eosio::blockchain_parameters& params); - - ///@} - - /** - * @ingroup core - * @{ - */ - - /** - * Maps producer with its signing key, used for producer schedule - * - * @brief Maps producer with its signing key - */ - struct producer_key { - - /** - * Name of the producer - * - * @brief Name of the producer - */ - name producer_name; - - /** - * Block signing key used by this producer - * - * @brief Block signing key used by this producer - */ - public_key block_signing_key; - - friend constexpr bool operator < ( const producer_key& a, const producer_key& b ) { - return a.producer_name < b.producer_name; - } - - EOSLIB_SERIALIZE( producer_key, (producer_name)(block_signing_key) ) - }; - - ///@} - - -} diff --git a/libraries/eosiolib/producer_schedule.hpp b/libraries/eosiolib/producer_schedule.hpp deleted file mode 100644 index 2128fb535f..0000000000 --- a/libraries/eosiolib/producer_schedule.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "privileged.hpp" - -#include - -#warning " is deprecated use " -namespace eosio { - - /** - * @defgroup producer_schedule Producer Schedule - * @ingroup contracts - * @brief Defines both the order, account name, and signing keys of the active set of producers. - * - * @{ - */ - struct producer_schedule { - /** - * Version number of the schedule. It is sequentially incrementing version number - */ - uint32_t version; - - /** - * List of producers for this schedule, including its signing key - */ - std::vector producers; - }; - - /// @} producer_schedule -} /// namespace eosio diff --git a/libraries/eosiolib/public_key.hpp b/libraries/eosiolib/public_key.hpp deleted file mode 100644 index bfd36d15dc..0000000000 --- a/libraries/eosiolib/public_key.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "crypto.hpp" - -#warning " is deprecated use " -// This file only exists so that existing contracts that include eosiolib/public_key.hpp do not break. -// Going forward contracts should instead just include eosiolib/crypto.hpp diff --git a/libraries/eosiolib/serialize.hpp b/libraries/eosiolib/serialize.hpp deleted file mode 100644 index d2f13a544a..0000000000 --- a/libraries/eosiolib/serialize.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include - -#warning " is deprecated use " -#define EOSLIB_REFLECT_MEMBER_OP( r, OP, elem ) \ - OP t.elem - -/** - * @addtogroup serialize Serialize C++ API - * @brief Defines C++ API to serialize and deserialize object - * @ingroup core - * @{ - */ - -/** - * Defines serialization and deserialization for a class - * - * @brief Defines serialization and deserialization for a class - * - * @param TYPE - the class to have its serialization and deserialization defined - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_SERIALIZE( TYPE, MEMBERS ) \ - template \ - friend DataStream& operator << ( DataStream& ds, const TYPE& t ){ \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS );\ - }\ - template \ - friend DataStream& operator >> ( DataStream& ds, TYPE& t ){ \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS );\ - } - -/** - * Defines serialization and deserialization for a class which inherits from other classes that - * have their serialization and deserialization defined - * - * @brief Defines serialization and deserialization for a class which inherits from other classes that - * have their serialization and deserialization defined - * - * @param TYPE - the class to have its serialization and deserialization defined - * @param BASE - a sequence of base class names (basea)(baseb)(basec) - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_SERIALIZE_DERIVED( TYPE, BASE, MEMBERS ) \ - template \ - friend DataStream& operator << ( DataStream& ds, const TYPE& t ){ \ - ds << static_cast(t); \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS );\ - }\ - template \ - friend DataStream& operator >> ( DataStream& ds, TYPE& t ){ \ - ds >> static_cast(t); \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS );\ - } -///@} serializecpp diff --git a/libraries/eosiolib/singleton.hpp b/libraries/eosiolib/singleton.hpp deleted file mode 100644 index 3817e1a569..0000000000 --- a/libraries/eosiolib/singleton.hpp +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once -#include "multi_index.hpp" -#include "system.hpp" - -#warning " is deprecated use " -namespace eosio { - - /** - * @defgroup singleton Singleton Table - * @ingroup contracts - * @brief Defines EOSIO Singleton Table used with %multiindex - * @{ - */ - - /** - * This wrapper uses a single table to store named objects various types. - * - * @tparam SingletonName - the name of this singleton variable - * @tparam T - the type of the singleton - */ - template - class singleton - { - /** - * Primary key of the data inside singleton table - */ - constexpr static uint64_t pk_value = static_cast(SingletonName); - - /** - * Structure of data inside the singleton table - */ - struct row { - /** - * Value to be stored inside the singleton table - */ - T value; - - /** - * Get primary key of the data - * - * @return uint64_t - Primary Key - */ - uint64_t primary_key() const { return pk_value; } - - EOSLIB_SERIALIZE( row, (value) ) - }; - - typedef eosio::multi_index table; - - public: - - /** - * Construct a new singleton object given the table's owner and the scope - * - * @param code - The table's owner - * @param scope - The scope of the table - */ - singleton( name code, uint64_t scope ) : _t( code, scope ) {} - - /** - * Check if the singleton table exists - * - * @return true - if exists - * @return false - otherwise - */ - bool exists() { - return _t.find( pk_value ) != _t.end(); - } - - /** - * Get the value stored inside the singleton table. Will throw an exception if it doesn't exist - * - * @brief Get the value stored inside the singleton table - * @return T - The value stored - */ - T get() { - auto itr = _t.find( pk_value ); - eosio::check( itr != _t.end(), "singleton does not exist" ); - return itr->value; - } - - /** - * Get the value stored inside the singleton table. If it doesn't exist, it will return the specified default value - * - * @param def - The default value to be returned in case the data doesn't exist - * @return T - The value stored - */ - T get_or_default( const T& def = T() ) { - auto itr = _t.find( pk_value ); - return itr != _t.end() ? itr->value : def; - } - - /** - * Get the value stored inside the singleton table. If it doesn't exist, it will create a new one with the specified default value - * - * @param bill_to_account - The account to bill for the newly created data if the data doesn't exist - * @param def - The default value to be created in case the data doesn't exist - * @return T - The value stored - */ - T get_or_create( name bill_to_account, const T& def = T() ) { - auto itr = _t.find( pk_value ); - return itr != _t.end() ? itr->value - : _t.emplace(bill_to_account, [&](row& r) { r.value = def; })->value; - } - - /** - * Set new value to the singleton table - * - * @param value - New value to be set - * @param bill_to_account - Account to pay for the new value - */ - void set( const T& value, name bill_to_account ) { - auto itr = _t.find( pk_value ); - if( itr != _t.end() ) { - _t.modify(itr, bill_to_account, [&](row& r) { r.value = value; }); - } else { - _t.emplace(bill_to_account, [&](row& r) { r.value = value; }); - } - } - - /** - * Remove the only data inside singleton table - */ - void remove( ) { - auto itr = _t.find( pk_value ); - if( itr != _t.end() ) { - _t.erase(itr); - } - } - - private: - table _t; - }; - -/// @} singleton -} /// namespace eosio diff --git a/libraries/eosiolib/stdlib.hpp b/libraries/eosiolib/stdlib.hpp deleted file mode 100644 index 7fd8f86d52..0000000000 --- a/libraries/eosiolib/stdlib.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include -#include -#include diff --git a/libraries/eosiolib/symbol.hpp b/libraries/eosiolib/symbol.hpp deleted file mode 100644 index 3a8d265118..0000000000 --- a/libraries/eosiolib/symbol.hpp +++ /dev/null @@ -1,439 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "system.hpp" -#include "print.h" -#include "name.hpp" -#include "serialize.hpp" - -#include -#include -#include - -#warning " is deprecated use " -namespace eosio { - - /** - * @addtogroup symbol Symbol C++ API - * @ingroup core - * @brief Defines C++ API for managing symbols - * @{ - */ - - /** - * @class Stores the symbol code - * @brief Stores the symbol code as a uint64_t value - */ - class symbol_code { - public: - - /** - * Default constructor, construct a new symbol_code - * - * @brief Construct a new symbol_code object defaulting to a value of 0 - * - */ - constexpr symbol_code() : value(0) {} - - /** - * Construct a new symbol_code given a scoped enumerated type of raw (uint64_t). - * - * @brief Construct a new symbol_code object initialising value with raw - * @param raw - The raw value which is a scoped enumerated type of unit64_t - * - */ - constexpr explicit symbol_code( uint64_t raw ) - :value(raw) - {} - - /** - * Construct a new symbol_code given an string. - * - * @brief Construct a new symbol_code object initialising value with str - * @param str - The string value which validated then converted to unit64_t - * - */ - constexpr explicit symbol_code( std::string_view str ) - :value(0) - { - if( str.size() > 7 ) { - eosio::check( false, "string is too long to be a valid symbol_code" ); - } - for( auto itr = str.rbegin(); itr != str.rend(); ++itr ) { - if( *itr < 'A' || *itr > 'Z') { - eosio::check( false, "only uppercase letters allowed in symbol_code string" ); - } - value <<= 8; - value |= *itr; - } - } - - /** - * Checks if the symbol code is valid - * @return true - if symbol is valid - */ - constexpr bool is_valid()const { - auto sym = value; - for ( int i=0; i < 7; i++ ) { - char c = (char)(sym & 0xFF); - if ( !('A' <= c && c <= 'Z') ) return false; - sym >>= 8; - if ( !(sym & 0xFF) ) { - do { - sym >>= 8; - if ( (sym & 0xFF) ) return false; - i++; - } while( i < 7 ); - } - } - return true; - } - - /** - * Returns the character length of the provided symbol - * - * @return length - character length of the provided symbol - */ - constexpr uint32_t length()const { - auto sym = value; - uint32_t len = 0; - while (sym & 0xFF && len <= 7) { - len++; - sym >>= 8; - } - return len; - } - - /** - * Casts a symbol code to raw - * - * @return Returns an instance of raw based on the value of a symbol_code - */ - constexpr uint64_t raw()const { return value; } - - /** - * Explicit cast to bool of the symbol_code - * - * @return Returns true if the symbol_code is set to the default value of 0 else true. - */ - constexpr explicit operator bool()const { return value != 0; } - - /** - * Writes the symbol_code as a string to the provided char buffer - * - * - * @brief Writes the symbol_code as a string to the provided char buffer - * @pre is_valid() == true - * @pre The range [begin, end) must be a valid range of memory to write to. - * @param begin - The start of the char buffer - * @param end - Just past the end of the char buffer - * @param dry_run - If true, do not actually write anything into the range. - * @return char* - Just past the end of the last character that would be written assuming dry_run == false and end was large enough to provide sufficient space. (Meaning only applies if returned pointer >= begin.) - * @post If the output string fits within the range [begin, end) and dry_run == false, the range [begin, returned pointer) contains the string representation of the symbol_code. Nothing is written if dry_run == true or returned pointer > end (insufficient space) or if returned pointer < begin (overflow in calculating desired end). - */ - char* write_as_string( char* begin, char* end, bool dry_run = false )const { - constexpr uint64_t mask = 0xFFull; - - if( dry_run || (begin + 7 < begin) || (begin + 7 > end) ) { - char* actual_end = begin + length(); - if( dry_run || (actual_end < begin) || (actual_end > end) ) return actual_end; - } - - auto v = value; - for( auto i = 0; i < 7; ++i, v >>= 8 ) { - if( v == 0 ) return begin; - - *begin = static_cast(v & mask); - ++begin; - } - - return begin; - } - - /** - * Returns the symbol_code as a string. - * - * @brief Returns the name value as a string by calling write_as_string() and returning the buffer produced by write_as_string() - */ - std::string to_string()const { - char buffer[7]; - auto end = write_as_string( buffer, buffer + sizeof(buffer) ); - return {buffer, end}; - } - - /** - * Equivalency operator. Returns true if a == b (are the same) - * - * @brief Equivalency operator - * @return boolean - true if both provided symbol_codes are the same - */ - friend constexpr bool operator == ( const symbol_code& a, const symbol_code& b ) { - return a.value == b.value; - } - - /** - * Inverted equivalency operator. Returns true if a != b (are different) - * - * @brief Inverted equivalency operator - * @return boolean - true if both provided symbol_codes are not the same - */ - friend constexpr bool operator != ( const symbol_code& a, const symbol_code& b ) { - return a.value != b.value; - } - - /** - * Less than operator. Returns true if a < b. - * @brief Less than operator - * @return boolean - true if symbol_code `a` is less than `b` - */ - friend constexpr bool operator < ( const symbol_code& a, const symbol_code& b ) { - return a.value < b.value; - } - /** - * Serialize a symbol_code into a stream - * - * @brief Serialize a symbol_code - * @param ds - The stream to write - * @param sym - The value to serialize - * @tparam DataStream - Type of datastream buffer - * @return DataStream& - Reference to the datastream - */ - template - friend inline DataStream& operator<<(DataStream& ds, const eosio::symbol_code sym_code) { - uint64_t raw = sym_code.raw(); - ds.write( (const char*)&raw, sizeof(raw)); - return ds; - } - - /** - * Deserialize a symbol_code from a stream - * - * @brief Deserialize a symbol_code - * @param ds - The stream to read - * @param symbol - The destination for deserialized value - * @tparam DataStream - Type of datastream buffer - * @return DataStream& - Reference to the datastream - */ - template - friend inline DataStream& operator>>(DataStream& ds, eosio::symbol_code& sym_code) { - uint64_t raw = 0; - ds.read((char*)&raw, sizeof(raw)); - sym_code = symbol_code(raw); - return ds; - } - - private: - uint64_t value = 0; - }; - - /** - * @struct Stores information about a symbol, the symbol can be 7 characters long. - * - * @brief Stores information about a symbol - */ - class symbol { - public: - /** - * Default constructor, construct a new symbol - * - * @brief Construct a new symbol object defaulting to a value of 0 - * - */ - constexpr symbol() : value(0) {} - - /** - * Construct a new symbol given a scoped enumerated type of raw (uint64_t). - * - * @brief Construct a new symbol object initialising value with raw - * @param raw - The raw value which is a scoped enumerated type of unit64_t - * - */ - constexpr explicit symbol( uint64_t raw ) : value(raw) {} - - /** - * Construct a new symbol given a symbol_code and a uint8_t precision. - * - * @brief Construct a new symbol object initialising value with a symbol maximum of 7 characters, packs the symbol and precision into the uint64_t value. - * @param sc - The symbol_code - * @param precision - The number of decimal places used for the symbol - * - */ - constexpr symbol( symbol_code sc, uint8_t precision ) - : value( (sc.raw() << 8) | static_cast(precision) ) - {} - - /** - * Construct a new symbol given a string and a uint8_t precision. - * - * @brief Construct a new symbol object initialising value with a symbol maximum of 7 characters, packs the symbol and precision into the uint64_t value. - * @param ss - The string containing the symbol - * @param precision - The number of decimal places used for the symbol - * - */ - constexpr symbol( std::string_view ss, uint8_t precision ) - : value( (symbol_code(ss).raw() << 8) | static_cast(precision) ) - {} - - /** - * Is this symbol valid - */ - constexpr bool is_valid()const { return code().is_valid(); } - - /** - * This symbol's precision - */ - constexpr uint8_t precision()const { return static_cast( value & 0xFFull ); } - - /** - * Returns representation of symbol name - */ - constexpr symbol_code code()const { return symbol_code{value >> 8}; } - - /** - * Returns uint64_t repreresentation of the symbol - */ - constexpr uint64_t raw()const { return value; } - - constexpr explicit operator bool()const { return value != 0; } - - /** - * %Print the symbol - * - * @brief %Print the symbol - */ - void print( bool show_precision = true )const { - if( show_precision ){ - printui( static_cast(precision()) ); - prints(","); - } - char buffer[7]; - auto end = code().write_as_string( buffer, buffer + sizeof(buffer) ); - if( buffer < end ) - prints_l( buffer, (end-buffer) ); - } - - /** - * Equivalency operator. Returns true if a == b (are the same) - * - * @brief Equivalency operator - * @return boolean - true if both provided symbols are the same - */ - friend constexpr bool operator == ( const symbol& a, const symbol& b ) { - return a.value == b.value; - } - - /** - * Inverted equivalency operator. Returns true if a != b (are different) - * - * @brief Inverted equivalency operator - * @return boolean - true if both provided symbols are not the same - */ - friend constexpr bool operator != ( const symbol& a, const symbol& b ) { - return a.value != b.value; - } - - /** - * Less than operator. Returns true if a < b. - * @brief Less than operator - * @return boolean - true if symbol `a` is less than `b` - */ - friend constexpr bool operator < ( const symbol& a, const symbol& b ) { - return a.value < b.value; - } - - private: - uint64_t value = 0; - }; - - /** - * @struct Extended asset which stores the information of the owner of the symbol - * - */ - class extended_symbol - { - public: - - /** - * Default constructor, construct a new extended_symbol - * - * @brief Construct a new empty extended_symbol object - * - */ - constexpr extended_symbol() {} - - /** - * Construct a new symbol_code given a symbol and a name. - * - * @brief Construct a new symbol_code object initialising symbol and contract with the passed in symbol and name - * @param sym - The symbol - * @param con - The name of the contract - * - */ - constexpr extended_symbol( symbol sym, name con ) : symbol(sym), contract(con) {} - - /** - * Returns the symbol in the extended_contract - * - * @return symbol - */ - constexpr symbol get_symbol() const { return symbol; } - - /** - * Returns the name of the contract in the extended_symbol - * - * @return name - */ - constexpr name get_contract() const { return contract; } - - /** - * %Print the extended symbol - * - * @brief %Print the extended symbol - */ - void print( bool show_precision = true )const { - symbol.print( show_precision ); - prints("@"); - printn( contract.value ); - } - - /** - * Equivalency operator. Returns true if a == b (are the same) - * - * @brief Equivalency operator - * @return boolean - true if both provided extended_symbols are the same - */ - friend constexpr bool operator == ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) == std::tie( b.symbol, b.contract ); - } - - /** - * Inverted equivalency operator. Returns true if a != b (are different) - * - * @brief Inverted equivalency operator - * @return boolean - true if both provided extended_symbols are not the same - */ - friend constexpr bool operator != ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) != std::tie( b.symbol, b.contract ); - } - - /** - * Less than operator. Returns true if a < b. - * @brief Less than operator - * @return boolean - true if extended_symbol `a` is less than `b` - */ - friend constexpr bool operator < ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) < std::tie( b.symbol, b.contract ); - } - - private: - symbol symbol; ///< the symbol - name contract; ///< the token contract hosting the symbol - - EOSLIB_SERIALIZE( extended_symbol, (symbol)(contract) ) - }; - - /// @} -} diff --git a/libraries/eosiolib/system.h b/libraries/eosiolib/system.h deleted file mode 100644 index b66a4397d9..0000000000 --- a/libraries/eosiolib/system.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "types.h" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" -#ifdef __cplusplus -extern "C" { -#endif - - /** - * @addtogroup system - * @ingroup c_api - * @brief Defines API for interacting with system level intrinsics - * @{ - */ - - /** - * Aborts processing of this action and unwinds all pending changes if the test condition is true - * - * @param test - 0 to abort, 1 to ignore - * - * Example: - * - * @code - * eosio_assert(1 == 2, "One is not equal to two."); - * eosio_assert(1 == 1, "One is not equal to one."); - * @endcode - * - * @param msg - a null terminated string explaining the reason for failure - */ - __attribute__((eosio_wasm_import)) - void eosio_assert( uint32_t test, const char* msg ); - - /** - * Aborts processing of this action and unwinds all pending changes if the test condition is true - * - * @param test - 0 to abort, 1 to ignore - * @param msg - a pointer to the start of string explaining the reason for failure - * @param msg_len - length of the string - */ - __attribute__((eosio_wasm_import)) - void eosio_assert_message( uint32_t test, const char* msg, uint32_t msg_len ); - - /** - * Aborts processing of this action and unwinds all pending changes if the test condition is true - * - * @brief Aborts processing of this action and unwinds all pending changes - * @param test - 0 to abort, 1 to ignore - * @param code - the error code - */ - __attribute__((eosio_wasm_import)) - void eosio_assert_code( uint32_t test, uint64_t code ); - - /** - * This method will abort execution of wasm without failing the contract. This is used to bypass all cleanup / destructors that would normally be called. - * - * @param code - the exit code - * Example: - * - * @code - * eosio_exit(0); - * eosio_exit(1); - * eosio_exit(2); - * eosio_exit(3); - * @endcode - */ - __attribute__((eosio_wasm_import, noreturn)) - void eosio_exit( int32_t code ); - - /** - * Returns the time in microseconds from 1970 of the current block - * - * @return time in microseconds from 1970 of the current block - */ - __attribute__((eosio_wasm_import)) - uint64_t current_time(); - - /** - * Get time (rounded down to the nearest second) of the current block (i.e. the block including this action) - * - * @return time in seconds from 1970 of the current block - */ - __attribute__((eosio_wasm_import)) - inline uint32_t now() { - return (uint32_t)( current_time() / 1000000 ); - } - -#ifdef __cplusplus -} -#endif - ///@} - diff --git a/libraries/eosiolib/system.hpp b/libraries/eosiolib/system.hpp deleted file mode 100644 index 5afb1b1235..0000000000 --- a/libraries/eosiolib/system.hpp +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "system.h" -#include -#include - -#warning " is deprecated use " -namespace eosio { - - /** - * @addtogroup system System C++ API - * @ingroup core - * @brief Defines wrappers over eosio_assert - * - * @{ - */ - - /** - * - * @brief Assert if the predicate fails and use the supplied message. - * - * Example: - * - * @code - * eosio::check(a == b, "a does not equal b"); - * @endcode - */ - inline void check(bool pred, const char* msg) { - if (!pred) { - eosio_assert(false, msg); - } - } - - /** - * - * @brief Assert if the predicate fails and use the supplied message. - * - * Example: - * - * @code - * eosio::check(a == b, "a does not equal b"); - * @endcode - */ - inline void check(bool pred, const std::string& msg) { - if (!pred) { - eosio_assert(false, msg.c_str()); - } - } - - /** - * - * @brief Assert if the predicate fails and use the supplied message. - * - * Example: - * - * @code - * eosio::check(a == b, "a does not equal b"); - * @endcode - */ - inline void check(bool pred, std::string&& msg) { - if (!pred) { - eosio_assert(false, msg.c_str()); - } - } - - /** - * - * @brief Assert if the predicate fails and use a subset of the supplied message. - * - * Example: - * - * @code - * const char* msg = "a does not equal b b does not equal a"; - * eosio::check(a == b, "a does not equal b", 18); - * @endcode - */ - inline void check(bool pred, const char* msg, size_t n) { - if (!pred) { - eosio_assert_message(false, msg, n); - } - } - - /** - * - * @brief Assert if the predicate fails and use a subset of the supplied message. - * - * Example: - * - * @code - * std::string msg = "a does not equal b b does not equal a"; - * eosio::check(a == b, msg, 18); - * @endcode - */ - inline void check(bool pred, const std::string& msg, size_t n) { - if (!pred) { - eosio_assert_message(false, msg.c_str(), n); - } - } - - /** - * - * @brief Assert if the predicate fails and use the supplied error code. - * - * Example: - * - * @code - * eosio::check(a == b, 13); - * @endcode - */ - inline void check(bool pred, uint64_t code) { - if (!pred) { - eosio_assert_code(false, code); - } - } -} // namespace eosio - /// @} diff --git a/libraries/eosiolib/time.hpp b/libraries/eosiolib/time.hpp deleted file mode 100644 index cc1032d6d4..0000000000 --- a/libraries/eosiolib/time.hpp +++ /dev/null @@ -1,189 +0,0 @@ -#pragma once -#include "eosio.hpp" - -#include -#include - -#warning " is deprecated use " -namespace eosio { - /** - * @addtogroup time - * @ingroup contracts - * @{ - */ - class microseconds { - public: - explicit microseconds( int64_t c = 0) :_count(c){} - static microseconds maximum() { return microseconds(0x7fffffffffffffffll); } - friend microseconds operator + (const microseconds& l, const microseconds& r ) { return microseconds(l._count+r._count); } - friend microseconds operator - (const microseconds& l, const microseconds& r ) { return microseconds(l._count-r._count); } - - - bool operator==(const microseconds& c)const { return _count == c._count; } - bool operator!=(const microseconds& c)const { return _count != c._count; } - friend bool operator>(const microseconds& a, const microseconds& b){ return a._count > b._count; } - friend bool operator>=(const microseconds& a, const microseconds& b){ return a._count >= b._count; } - friend bool operator<(const microseconds& a, const microseconds& b){ return a._count < b._count; } - friend bool operator<=(const microseconds& a, const microseconds& b){ return a._count <= b._count; } - microseconds& operator+=(const microseconds& c) { _count += c._count; return *this; } - microseconds& operator-=(const microseconds& c) { _count -= c._count; return *this; } - int64_t count()const { return _count; } - int64_t to_seconds()const { return _count/1000000; } - - int64_t _count; - EOSLIB_SERIALIZE( microseconds, (_count) ) - private: - friend class time_point; - }; - - inline microseconds seconds( int64_t s ) { return microseconds( s * 1000000 ); } - inline microseconds milliseconds( int64_t s ) { return microseconds( s * 1000 ); } - inline microseconds minutes(int64_t m) { return seconds(60*m); } - inline microseconds hours(int64_t h) { return minutes(60*h); } - inline microseconds days(int64_t d) { return hours(24*d); } - - class time_point { - public: - explicit time_point( microseconds e = microseconds() ) :elapsed(e){} - const microseconds& time_since_epoch()const { return elapsed; } - uint32_t sec_since_epoch()const { return uint32_t(elapsed.count() / 1000000); } - bool operator > ( const time_point& t )const { return elapsed._count > t.elapsed._count; } - bool operator >=( const time_point& t )const { return elapsed._count >=t.elapsed._count; } - bool operator < ( const time_point& t )const { return elapsed._count < t.elapsed._count; } - bool operator <=( const time_point& t )const { return elapsed._count <=t.elapsed._count; } - bool operator ==( const time_point& t )const { return elapsed._count ==t.elapsed._count; } - bool operator !=( const time_point& t )const { return elapsed._count !=t.elapsed._count; } - time_point& operator += ( const microseconds& m) { elapsed+=m; return *this; } - time_point& operator -= ( const microseconds& m) { elapsed-=m; return *this; } - time_point operator + (const microseconds& m) const { return time_point(elapsed+m); } - time_point operator + (const time_point& m) const { return time_point(elapsed+m.elapsed); } - time_point operator - (const microseconds& m) const { return time_point(elapsed-m); } - microseconds operator - (const time_point& m) const { return microseconds(elapsed.count() - m.elapsed.count()); } - microseconds elapsed; - EOSLIB_SERIALIZE( time_point, (elapsed) ) - }; - - /** - * A lower resolution time_point accurate only to seconds from 1970 - */ - class time_point_sec - { - public: - time_point_sec() - :utc_seconds(0){} - - explicit time_point_sec(uint32_t seconds ) - :utc_seconds(seconds){} - - time_point_sec( const time_point& t ) - :utc_seconds( uint32_t(t.time_since_epoch().count() / 1000000ll) ){} - - static time_point_sec maximum() { return time_point_sec(0xffffffff); } - static time_point_sec min() { return time_point_sec(0); } - - operator time_point()const { return time_point( eosio::seconds( utc_seconds) ); } - uint32_t sec_since_epoch()const { return utc_seconds; } - - time_point_sec operator = ( const eosio::time_point& t ) - { - utc_seconds = uint32_t(t.time_since_epoch().count() / 1000000ll); - return *this; - } - friend bool operator < ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds < b.utc_seconds; } - friend bool operator > ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds > b.utc_seconds; } - friend bool operator <= ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds <= b.utc_seconds; } - friend bool operator >= ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds >= b.utc_seconds; } - friend bool operator == ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds == b.utc_seconds; } - friend bool operator != ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds != b.utc_seconds; } - time_point_sec& operator += ( uint32_t m ) { utc_seconds+=m; return *this; } - time_point_sec& operator += ( microseconds m ) { utc_seconds+=m.to_seconds(); return *this; } - time_point_sec& operator += ( time_point_sec m ) { utc_seconds+=m.utc_seconds; return *this; } - time_point_sec& operator -= ( uint32_t m ) { utc_seconds-=m; return *this; } - time_point_sec& operator -= ( microseconds m ) { utc_seconds-=m.to_seconds(); return *this; } - time_point_sec& operator -= ( time_point_sec m ) { utc_seconds-=m.utc_seconds; return *this; } - time_point_sec operator +( uint32_t offset )const { return time_point_sec(utc_seconds + offset); } - time_point_sec operator -( uint32_t offset )const { return time_point_sec(utc_seconds - offset); } - - friend time_point operator + ( const time_point_sec& t, const microseconds& m ) { return time_point(t) + m; } - friend time_point operator - ( const time_point_sec& t, const microseconds& m ) { return time_point(t) - m; } - friend microseconds operator - ( const time_point_sec& t, const time_point_sec& m ) { return time_point(t) - time_point(m); } - friend microseconds operator - ( const time_point& t, const time_point_sec& m ) { return time_point(t) - time_point(m); } - uint32_t utc_seconds; - - EOSLIB_SERIALIZE( time_point_sec, (utc_seconds) ) - }; - - /** - * This class is used in the block headers to represent the block time - * It is a parameterised class that takes an Epoch in milliseconds and - * and an interval in milliseconds and computes the number of slots. - **/ - class block_timestamp { - public: - explicit block_timestamp( uint32_t s=0 ) :slot(s){} - - block_timestamp(const time_point& t) { - set_time_point(t); - } - - block_timestamp(const time_point_sec& t) { - set_time_point(t); - } - - static block_timestamp maximum() { return block_timestamp( 0xffff ); } - static block_timestamp min() { return block_timestamp(0); } - - block_timestamp next() const { - eosio::check( std::numeric_limits::max() - slot >= 1, "block timestamp overflow" ); - auto result = block_timestamp(*this); - result.slot += 1; - return result; - } - - time_point to_time_point() const { - return (time_point)(*this); - } - - operator time_point() const { - int64_t msec = slot * (int64_t)block_interval_ms; - msec += block_timestamp_epoch; - return time_point(milliseconds(msec)); - } - - void operator = (const time_point& t ) { - set_time_point(t); - } - - bool operator > ( const block_timestamp& t )const { return slot > t.slot; } - bool operator >=( const block_timestamp& t )const { return slot >= t.slot; } - bool operator < ( const block_timestamp& t )const { return slot < t.slot; } - bool operator <=( const block_timestamp& t )const { return slot <= t.slot; } - bool operator ==( const block_timestamp& t )const { return slot == t.slot; } - bool operator !=( const block_timestamp& t )const { return slot != t.slot; } - uint32_t slot; - static constexpr int32_t block_interval_ms = 500; - static constexpr int64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000 - - EOSLIB_SERIALIZE( block_timestamp, (slot) ) - private: - - - void set_time_point(const time_point& t) { - int64_t micro_since_epoch = t.time_since_epoch().count(); - int64_t msec_since_epoch = micro_since_epoch / 1000; - slot = uint32_t(( msec_since_epoch - block_timestamp_epoch ) / int64_t(block_interval_ms)); - } - - void set_time_point(const time_point_sec& t) { - int64_t sec_since_epoch = t.sec_since_epoch(); - slot = uint32_t((sec_since_epoch * 1000 - block_timestamp_epoch) / block_interval_ms); - } - }; // block_timestamp - - - typedef block_timestamp block_timestamp_type; - - /// @} - - -} // namespace eosio diff --git a/libraries/eosiolib/transaction.h b/libraries/eosiolib/transaction.h deleted file mode 100644 index 85ce529b00..0000000000 --- a/libraries/eosiolib/transaction.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "types.h" - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" -extern "C" { - /** - * @addtogroup transaction_c Transaction API - * @ingroup c_api - * @brief Defines C API for sending transactions and inline actions - * - * @details Deferred transactions will not be processed until a future block. They - * can therefore have no effect on the success of failure of their parent - * transaction so long as they appear well formed. If any other condition - * causes the parent transaction to be marked as failing, then the deferred - * transaction will never be processed. - * - * Deferred transactions must adhere to the permissions available to the - * parent transaction or, in the future, delegated to the contract account - * for future use. - * - * An inline message allows one contract to send another contract a message - * which is processed immediately after the current message's processing - * ends such that the success or failure of the parent transaction is - * dependent on the success of the message. If an inline message fails in - * processing then the whole tree of transactions and actions rooted in the - * block will me marked as failing and none of effects on the database will - * persist. - * - * Inline actions and Deferred transactions must adhere to the permissions - * available to the parent transaction or, in the future, delegated to the - * contract account for future use. - * @{ - */ - - /** - * Sends a deferred transaction. - * - * @param sender_id - ID of sender - * @param payer - Account paying for RAM - * @param serialized_transaction - Pointer of serialized transaction to be deferred - * @param size - Size to reserve - * @param replace_existing - f this is `0` then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction - */ - __attribute__((eosio_wasm_import)) - void send_deferred(const uint128_t& sender_id, capi_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing = 0); - - /** - * Cancels a deferred transaction. - * - * @brief Cancels a deferred transaction. - * @param sender_id - The id of the sender - * - * @pre The deferred transaction ID exists. - * @pre The deferred transaction ID has not yet been published. - * @post Deferred transaction canceled. - * - * @return 1 if transaction was canceled, 0 if transaction was not found - * - * Example: -* - * @code - * id = 0xffffffffffffffff - * cancel_deferred( id ); - * @endcode - */ - __attribute__((eosio_wasm_import)) - int cancel_deferred(const uint128_t& sender_id); - - /** - * Access a copy of the currently executing transaction. - * - * @brief Access a copy of the currently executing transaction. - * @param buffer - a buffer to write the current transaction to - * @param size - the size of the buffer, 0 to return required size - * @return the size of the transaction written to the buffer, or number of bytes that can be copied if size==0 passed - */ - __attribute__((eosio_wasm_import)) - size_t read_transaction(char *buffer, size_t size); - - /** - * Gets the size of the currently executing transaction. - * - * @brief Gets the size of the currently executing transaction. - * @return size of the currently executing transaction - */ - __attribute__((eosio_wasm_import)) - size_t transaction_size(); - - /** - * Gets the block number used for TAPOS on the currently executing transaction. - * - * @brief Gets the block number used for TAPOS on the currently executing transaction. - * @return block number used for TAPOS on the currently executing transaction - * Example: - * @code - * int tbn = tapos_block_num(); - * @endcode - */ - __attribute__((eosio_wasm_import)) - int tapos_block_num(); - - /** - * Gets the block prefix used for TAPOS on the currently executing transaction. - * - * @brief Gets the block prefix used for TAPOS on the currently executing transaction. - * @return block prefix used for TAPOS on the currently executing transaction - * Example: - * @code - * int tbp = tapos_block_prefix(); - * @endcode - */ - __attribute__((eosio_wasm_import)) - int tapos_block_prefix(); - - /** - * Gets the expiration of the currently executing transaction. - * - * @brief Gets the expiration of the currently executing transaction. - * @return expiration of the currently executing transaction in seconds since Unix epoch - * Example: - * @code - * uint32_t tm = expiration(); - * eosio_print(tm); - * @endcode - */ - __attribute__((eosio_wasm_import)) - uint32_t expiration(); - - /** - * Retrieves the indicated action from the active transaction. - * - * @brief Retrieves the indicated action from the active transaction. - * @param type - 0 for context free action, 1 for action - * @param index - the index of the requested action - * @param buff - output packed buff of the action - * @param size - amount of buff read, pass 0 to have size returned - * @return the size of the action, -1 on failure - */ - __attribute__((eosio_wasm_import)) - int get_action( uint32_t type, uint32_t index, char* buff, size_t size ); - - /** - * Retrieve the signed_transaction.context_free_data[index]. - * - * @brief Retrieve the signed_transaction.context_free_data[index]. - * @param index - the index of the context_free_data entry to retrieve - * @param buff - output buff of the context_free_data entry - * @param size - amount of context_free_data[index] to retrieve into buff, 0 to report required size - * @return size copied, or context_free_data[index].size() if 0 passed for size, or -1 if index not valid - */ - __attribute__((eosio_wasm_import)) - int get_context_free_data( uint32_t index, char* buff, size_t size ); - - ///}@ -} diff --git a/libraries/eosiolib/transaction.hpp b/libraries/eosiolib/transaction.hpp deleted file mode 100644 index 54427cf170..0000000000 --- a/libraries/eosiolib/transaction.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include "transaction.h" -#include "action.hpp" -#include "time.hpp" -#include "serialize.hpp" -#include "system.hpp" - -#include - -#warning " is deprecated use " -namespace eosio { - - /** - * @defgroup transaction Transaction C++ API - * @ingroup contracts - * @brief Type-safe C++ wrappers for transaction C API - * - * @details An inline message allows one contract to send another contract a message - * which is processed immediately after the current message's processing - * ends such that the success or failure of the parent transaction is - * dependent on the success of the message. If an inline message fails in - * processing then the whole tree of transactions and actions rooted in the - * block will me marked as failing and none of effects on the database will - * persist. - * - * Inline actions and Deferred transactions must adhere to the permissions - * available to the parent transaction or, in the future, delegated to the - * contract account for future use. - - * @note There are some methods from the @ref transactioncapi that can be used directly from C++ - * @{ - */ - typedef std::tuple> extension; - typedef std::vector extensions_type; - - /** - * Class transaction_header contains details about the transaction - * @brief Contains details about the transaction - */ - - class transaction_header { - public: - - /** - * Construct a new transaction_header with an expiration of now + 60 seconds. - * - * @brief Construct a new transaction_header object initialising the transaction header expiration to now + 60 seconds - */ - transaction_header( time_point_sec exp = time_point_sec(now() + 60) ) - :expiration(exp) - {} - - time_point_sec expiration; - uint16_t ref_block_num; - uint32_t ref_block_prefix; - unsigned_int max_net_usage_words = 0UL; /// number of 8 byte words this transaction can serialize into after compressions - uint8_t max_cpu_usage_ms = 0UL; /// number of CPU usage units to bill transaction for - unsigned_int delay_sec = 0UL; /// number of seconds to delay transaction, default: 0 - - EOSLIB_SERIALIZE( transaction_header, (expiration)(ref_block_num)(ref_block_prefix)(max_net_usage_words)(max_cpu_usage_ms)(delay_sec) ) - }; - - /** - * Class transaction contains the actions, context_free_actions and extensions type for a transaction - * @brief Contains the actions, context_free_actions and extensions type for a transaction - */ - class transaction : public transaction_header { - public: - - /** - * Construct a new transaction with an expiration of now + 60 seconds. - * - * @brief Construct a new transaction object initialising the transaction header expiration to now + 60 seconds - */ - transaction(time_point_sec exp = time_point_sec(now() + 60)) : transaction_header( exp ) {} - - /** - * Sends this transaction, packs the transaction then sends it as a deferred transaction - * - * @brief Writes the symbol_code as a string to the provided char buffer - * @param sender_id - ID of sender - * @param payer - Account paying for RAM - * @param replace_existing - Defaults to false, if this is `0`/false then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction - */ - void send(const uint128_t& sender_id, name payer, bool replace_existing = false) const { - auto serialize = pack(*this); - send_deferred(sender_id, payer.value, serialize.data(), serialize.size(), replace_existing); - } - - std::vector context_free_actions; - std::vector actions; - extensions_type transaction_extensions; - - EOSLIB_SERIALIZE_DERIVED( transaction, transaction_header, (context_free_actions)(actions)(transaction_extensions) ) - }; - - /** - * Struct onerror contains and sender id and packed transaction - * @brief Contains and sender id and packed transaction - */ - struct onerror { - uint128_t sender_id; - std::vector sent_trx; - - /** - * from_current_action unpacks and returns a onerror struct - * @brief Unpacks and returns a onerror struct - */ - static onerror from_current_action() { - return unpack_action_data(); - } - - /** - * unpack_sent_trx unpacks and returns a transaction - * @brief Unpacks and returns a transaction - */ - transaction unpack_sent_trx() const { - return unpack(sent_trx); - } - - EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) ) - }; - - /** - * Retrieve the indicated action from the active transaction. - * - * @param type - 0 for context free action, 1 for action - * @param index - the index of the requested action - * @return the indicated action - */ - inline action get_action( uint32_t type, uint32_t index ) { - constexpr size_t max_stack_buffer_size = 512; - int s = ::get_action( type, index, nullptr, 0 ); - eosio::check( s > 0, "get_action size failed" ); - size_t size = static_cast(s); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - auto size2 = ::get_action( type, index, buffer, size ); - eosio::check( size == static_cast(size2), "get_action failed" ); - return eosio::unpack( buffer, size ); - } - - ///}@ -} diff --git a/libraries/eosiolib/types.h b/libraries/eosiolib/types.h deleted file mode 100644 index 28e8d38f4b..0000000000 --- a/libraries/eosiolib/types.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include - -#warning " is deprecated use . If you are using C++ the .h header files will be removed from inclusion entirely in v1.7.0" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @addtogroup c_types - * @brief Specifies builtin types, typedefs and aliases - * @{ - */ - -/** - * Macro to align/overalign a type to ensure calls to intrinsics with pointers/references are properly aligned - */ - -/* macro to align/overalign a type to ensure calls to intrinsics with pointers/references are properly aligned */ -#define ALIGNED(X) __attribute__ ((aligned (16))) X - -typedef uint64_t capi_name; - -/** - * EOSIO Public Key. It is 34 bytes. - */ -struct capi_public_key { - char data[34]; -}; - -/** - * EOSIO Signature. It is 66 bytes. - */ -struct capi_signature { - uint8_t data[66]; -}; - -/** - * 256-bit hash - */ -struct ALIGNED(capi_checksum256) { - uint8_t hash[32]; -}; - -/** - * 160-bit hash - */ -struct ALIGNED(capi_checksum160) { - uint8_t hash[20]; -}; - -/** - * 512-bit hash - */ -struct ALIGNED(capi_checksum512) { - uint8_t hash[64]; -}; - -/// @} - -#ifdef __cplusplus -} /// extern "C" -#endif diff --git a/libraries/eosiolib/varint.hpp b/libraries/eosiolib/varint.hpp deleted file mode 100644 index 5316f41c0e..0000000000 --- a/libraries/eosiolib/varint.hpp +++ /dev/null @@ -1,440 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#warning " is deprecated use " -/** - * @defgroup varint Variable Length Integer Type - * @brief Defines variable length integer type which provides more efficient serialization - * @ingroup types - * @{ - */ -/** - * Variable Length Unsigned Integer. This provides more efficient serialization of 32-bit unsigned int. - * It serialuzes a 32-bit unsigned integer in as few bytes as possible - * `varuint32` is unsigned and uses [VLQ or Base-128 encoding](https://en.wikipedia.org/wiki/Variable-length_quantity) - * - * @brief Variable Length Unsigned Integer - */ -struct unsigned_int { - /** - * Construct a new unsigned int object - * - * @param v - Source - */ - unsigned_int( uint32_t v = 0 ):value(v){} - - /** - * Construct a new unsigned int object from a type that is convertible to uint32_t - * - * @tparam T - Type of the source - * @param v - Source - * @pre T must be convertible to uint32_t - */ - template - unsigned_int( T v ):value(v){} - - //operator uint32_t()const { return value; } - //operator uint64_t()const { return value; } - - /** - * Convert unsigned_int as T - * - * @tparam T - Target type of conversion - * @return T - Converted target - */ - template - operator T()const { return static_cast(value); } - - /** - * Assign 32-bit unsigned integer - * - * @param v - Soruce - * @return unsigned_int& - Reference to this object - */ - unsigned_int& operator=( uint32_t v ) { value = v; return *this; } - - /** - * Contained value - */ - uint32_t value; - - /** - * Check equality between a unsigned_int object and 32-bit unsigned integer - * - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const unsigned_int& i, const uint32_t& v ) { return i.value == v; } - - /** - * Check equality between 32-bit unsigned integer and a unsigned_int object - * - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const uint32_t& i, const unsigned_int& v ) { return i == v.value; } - - /** - * Check equality between two unsigned_int objects - * - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const unsigned_int& i, const unsigned_int& v ) { return i.value == v.value; } - - /** - * Check inequality between a unsigned_int object and 32-bit unsigned integer - * - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const unsigned_int& i, const uint32_t& v ) { return i.value != v; } - - /** - * Check inequality between 32-bit unsigned integer and a unsigned_int object - * - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if unequal - * @return false - otherwise - */ - friend bool operator!=( const uint32_t& i, const unsigned_int& v ) { return i != v.value; } - - /** - * Check inequality between two unsigned_int objects - * - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const unsigned_int& i, const unsigned_int& v ) { return i.value != v.value; } - - /** - * Check if the given unsigned_int object is less than the given 32-bit unsigned integer - * - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const unsigned_int& i, const uint32_t& v ) { return i.value < v; } - - /** - * Check if the given 32-bit unsigned integer is less than the given unsigned_int object - * - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const uint32_t& i, const unsigned_int& v ) { return i < v.value; } - - /** - * Check if the first given unsigned_int is less than the second given unsigned_int object - * - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const unsigned_int& i, const unsigned_int& v ) { return i.value < v.value; } - - /** - * Check if the given unsigned_int object is greater or equal to the given 32-bit unsigned integer - * - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const unsigned_int& i, const uint32_t& v ) { return i.value >= v; } - - /** - * Check if the given 32-bit unsigned integer is greater or equal to the given unsigned_int object - * - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const uint32_t& i, const unsigned_int& v ) { return i >= v.value; } - - /** - * Check if the first given unsigned_int is greater or equal to the second given unsigned_int object - * - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const unsigned_int& i, const unsigned_int& v ) { return i.value >= v.value; } - - /** - * Serialize an unsigned_int object with as few bytes as possible - * - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator << ( DataStream& ds, const unsigned_int& v ){ - uint64_t val = v.value; - do { - uint8_t b = uint8_t(val) & 0x7f; - val >>= 7; - b |= ((val > 0) << 7); - ds.write((char*)&b,1);//.put(b); - } while( val ); - return ds; - } - - /** - * Deserialize an unsigned_int object - * - * @param ds - The stream to read - * @param vi - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator >> ( DataStream& ds, unsigned_int& vi ){ - uint64_t v = 0; char b = 0; uint8_t by = 0; - do { - ds.get(b); - v |= uint32_t(uint8_t(b) & 0x7f) << by; - by += 7; - } while( uint8_t(b) & 0x80 ); - vi.value = static_cast(v); - return ds; - } -}; - -/** - * Variable Length Signed Integer. This provides more efficient serialization of 32-bit signed int. - * It serializes a 32-bit signed integer in as few bytes as possible. - * - * @note `varint32' is signed and uses [Zig-Zag encoding](https://developers.google.com/protocol-buffers/docs/encoding#signed-integers) - */ -struct signed_int { - /** - * Construct a new signed int object - * - * @param v - Source - */ - signed_int( int32_t v = 0 ):value(v){} - - /** - * Convert signed_int to primitive 32-bit signed integer - * - * @return int32_t - The converted result - */ - operator int32_t()const { return value; } - - - /** - * Assign an object that is convertible to int32_t - * - * @tparam T - Type of the assignment object - * @param v - Source - * @return unsigned_int& - Reference to this object - */ - template - signed_int& operator=( const T& v ) { value = v; return *this; } - - /** - * Increment operator - * - * @return signed_int - New signed_int with value incremented from the current object's value - */ - signed_int operator++(int) { return value++; } - - /** - * Increment operator - * - * @return signed_int - Reference to current object - */ - signed_int& operator++(){ ++value; return *this; } - - /** - * Contained value - */ - int32_t value; - - /** - * Check equality between a signed_int object and 32-bit integer - * - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const signed_int& i, const int32_t& v ) { return i.value == v; } - - /** - * Check equality between 32-bit integer and a signed_int object - * - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const int32_t& i, const signed_int& v ) { return i == v.value; } - - /** - * Check equality between two signed_int objects - * - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const signed_int& i, const signed_int& v ) { return i.value == v.value; } - - - /** - * Check inequality between a signed_int object and 32-bit integer - * - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const signed_int& i, const int32_t& v ) { return i.value != v; } - - /** - * Check inequality between 32-bit integer and a signed_int object - * - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if unequal - * @return false - otherwise - */ - friend bool operator!=( const int32_t& i, const signed_int& v ) { return i != v.value; } - - /** - * Check inequality between two signed_int objects - * - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const signed_int& i, const signed_int& v ) { return i.value != v.value; } - - /** - * Check if the given signed_int object is less than the given 32-bit integer - * - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const signed_int& i, const int32_t& v ) { return i.value < v; } - - /** - * Check if the given 32-bit integer is less than the given signed_int object - * - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const int32_t& i, const signed_int& v ) { return i < v.value; } - - /** - * Check if the first given signed_int is less than the second given signed_int object - * - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const signed_int& i, const signed_int& v ) { return i.value < v.value; } - - - /** - * Check if the given signed_int object is greater or equal to the given 32-bit integer - * - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const signed_int& i, const int32_t& v ) { return i.value >= v; } - - /** - * Check if the given 32-bit integer is greater or equal to the given signed_int object - * - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const int32_t& i, const signed_int& v ) { return i >= v.value; } - - /** - * Check if the first given signed_int is greater or equal to the second given signed_int object - * - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const signed_int& i, const signed_int& v ) { return i.value >= v.value; } - - - /** - * Serialize an signed_int object with as few bytes as possible - * - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator << ( DataStream& ds, const signed_int& v ){ - uint32_t val = uint32_t((v.value<<1) ^ (v.value>>31)); //apply zigzag encoding - do { //store 7 bit chunks - uint8_t b = uint8_t(val) & 0x7f; - val >>= 7; - b |= ((val > 0) << 7); - ds.write((char*)&b,1);//.put(b); - } while( val ); - return ds; - } - - /** - * Deserialize an signed_int object - * - * @param ds - The stream to read - * @param vi - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator >> ( DataStream& ds, signed_int& vi ){ - uint32_t v = 0; char b = 0; int by = 0; - do { //read 7 bit chunks - ds.get(b); - v |= uint32_t(uint8_t(b) & 0x7f) << by; - by += 7; - } while( uint8_t(b) & 0x80 ); - vi.value= (v>>1) ^ (~(v&1)+1ull); //reverse zigzag encoding - return ds; - } -}; - -/// @} diff --git a/libraries/native/crt.cpp b/libraries/native/crt.cpp index fb1b34d40f..112820eda0 100644 --- a/libraries/native/crt.cpp +++ b/libraries/native/crt.cpp @@ -162,7 +162,6 @@ extern "C" { if(max_stack_buffer_size < buffer_size) free(buffer); }); - jmp_ret = setjmp(env); if (jmp_ret == 0) { ret_val = main(argc, argv); diff --git a/libraries/native/crt.hpp b/libraries/native/crt.hpp deleted file mode 100644 index a6f43201f3..0000000000 --- a/libraries/native/crt.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include - -#warning " is deprecated use " -namespace eosio { namespace cdt { - enum output_stream_kind { - std_out, - std_err, - none - }; - struct output_stream { - char output[1024*2]; - size_t index = 0; - std::string to_string()const { return std::string((const char*)output, index); } - const char* get()const { return output; } - void push(char c) { output[index++] = c; } - void clear() { index = 0; } - }; -}} //ns eosio::cdt - -extern eosio::cdt::output_stream std_out; -extern eosio::cdt::output_stream std_err; -extern "C" jmp_buf* ___env_ptr; -extern "C" char* ___heap_ptr; - -extern "C" { - void __set_env_test(); - void __reset_env(); - void _prints_l(const char* cstr, uint32_t len, uint8_t which); - void _prints(const char* cstr, uint8_t which); -} diff --git a/libraries/native/intrinsics.cpp b/libraries/native/intrinsics.cpp index 1bad869f87..e023fbd736 100644 --- a/libraries/native/intrinsics.cpp +++ b/libraries/native/intrinsics.cpp @@ -25,6 +25,9 @@ extern "C" { int64_t set_proposed_producers( char *producer_data, uint32_t producer_data_size ) { return intrinsics::get().call(producer_data, producer_data_size); } + int64_t set_proposed_producers_ex( uint64_t producer_data_format, char *producer_data, uint32_t producer_data_size ) { + return intrinsics::get().call(producer_data_format, producer_data, producer_data_size); + } uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ) { return intrinsics::get().call(data, datalen); } @@ -37,6 +40,12 @@ extern "C" { void set_privileged( capi_name account, bool is_priv ) { return intrinsics::get().call(account, is_priv); } + bool is_feature_activated( const capi_checksum256* feature_digest ) { + return intrinsics::get().call(feature_digest); + } + void preactivate_feature( const capi_checksum256* feature_digest ) { + return intrinsics::get().call(feature_digest); + } uint32_t get_active_producers( capi_name* producers, uint32_t datalen ) { return intrinsics::get().call(producers, datalen); } @@ -331,6 +340,9 @@ extern "C" { int get_context_free_data( uint32_t index, char* buff, size_t size ) { return intrinsics::get().call(index, buff, size); } + capi_name get_sender() { + return intrinsics::get().call(); + } // softfloat static constexpr uint32_t inv_float_eps = 0x4B000000; @@ -785,7 +797,7 @@ extern "C" { void printui(uint64_t value) { return intrinsics::get().call(value); } - + void printi128(const int128_t* value) { return intrinsics::get().call(value); } @@ -793,7 +805,7 @@ extern "C" { void printui128(const uint128_t* value) { return intrinsics::get().call(value); } - + void printsf(float value) { return intrinsics::get().call(value); } @@ -805,11 +817,11 @@ extern "C" { void printqf(const long double* value) { return intrinsics::get().call(value); } - + void printn(uint64_t nm) { return intrinsics::get().call(nm); } - + void printhex(const void* data, uint32_t len) { return intrinsics::get().call(data, len); } @@ -841,7 +853,7 @@ extern "C" { dest[i] = tmp_buf[i]; return (void*)dest; } - + void eosio_assert(uint32_t test, const char* msg) { if (test == 0) { _prints(msg, eosio::cdt::output_stream_kind::std_err); @@ -867,9 +879,9 @@ extern "C" { longjmp(*___env_ptr, 1); } } - + #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Winvalid-noreturn" void abort() { eosio_assert(false, "abort"); } diff --git a/libraries/native/intrinsics.hpp b/libraries/native/intrinsics.hpp deleted file mode 100644 index b6f1db0aab..0000000000 --- a/libraries/native/intrinsics.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include "intrinsics_def.hpp" - -#pragma once - -#warning " is deprecated use " -namespace eosio { namespace native { - - class intrinsics { - public: - static intrinsics& get() { - static intrinsics inst; - return inst; - } - - enum intrinsic_name { - INTRINSICS(CREATE_ENUM) - INTRINSICS_SIZE - }; - - INTRINSICS(GENERATE_TYPE_MAPPING) - std::tuple< INTRINSICS(GET_TYPE) std::function > funcs { - INTRINSICS(REGISTER_INTRINSIC) - std::function{[](){}} - }; - - template - auto call(Args... args) -> decltype(std::get(intrinsics::get().funcs)(args...)) { - return std::get(intrinsics::get().funcs)(args...); - } - - template - static void set_intrinsic(F&& func) { - auto& f = std::get(intrinsics::get().funcs); - std::get(intrinsics::get().funcs) = typename std::remove_reference::type {func}; - } - - template - static auto get_intrinsic() - -> typename std::remove_reference(intrinsics::get().funcs))>::type { - return std::get(intrinsics::get().funcs); - } - }; - -}} //ns eosio::native diff --git a/libraries/native/intrinsics_def.hpp b/libraries/native/intrinsics_def.hpp deleted file mode 100644 index 5aae45c4ca..0000000000 --- a/libraries/native/intrinsics_def.hpp +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#warning " is deprecated use " -namespace eosio { namespace native { - template - auto get_args_full(std::index_sequence) { - std::tuple...> tup; - return std::tuple{std::get(tup)...}; - } - - template - auto get_args_full(R(Args...)) { - return get_args_full(std::index_sequence_for{}); - } - - template - auto get_args(R(Args...)) { - return std::tuple...>{}; - } - - template - auto create_function(std::index_sequence) { - return std::function::type ...)>{ - [](typename std::tuple_element::type ...) { - eosio_assert(false, "unsupported intrinsic"); return (R)0; - } - }; - } - -#define INTRINSICS(intrinsic_macro) \ -intrinsic_macro(get_resource_limits) \ -intrinsic_macro(set_resource_limits) \ -intrinsic_macro(set_proposed_producers) \ -intrinsic_macro(get_blockchain_parameters_packed) \ -intrinsic_macro(set_blockchain_parameters_packed) \ -intrinsic_macro(is_privileged) \ -intrinsic_macro(set_privileged) \ -intrinsic_macro(get_active_producers) \ -intrinsic_macro(db_idx64_store) \ -intrinsic_macro(db_idx64_remove) \ -intrinsic_macro(db_idx64_update) \ -intrinsic_macro(db_idx64_find_primary) \ -intrinsic_macro(db_idx64_find_secondary) \ -intrinsic_macro(db_idx64_lowerbound) \ -intrinsic_macro(db_idx64_upperbound) \ -intrinsic_macro(db_idx64_end) \ -intrinsic_macro(db_idx64_next) \ -intrinsic_macro(db_idx64_previous) \ -intrinsic_macro(db_idx128_store) \ -intrinsic_macro(db_idx128_remove) \ -intrinsic_macro(db_idx128_update) \ -intrinsic_macro(db_idx128_find_primary) \ -intrinsic_macro(db_idx128_find_secondary) \ -intrinsic_macro(db_idx128_lowerbound) \ -intrinsic_macro(db_idx128_upperbound) \ -intrinsic_macro(db_idx128_end) \ -intrinsic_macro(db_idx128_next) \ -intrinsic_macro(db_idx128_previous) \ -intrinsic_macro(db_idx256_store) \ -intrinsic_macro(db_idx256_remove) \ -intrinsic_macro(db_idx256_update) \ -intrinsic_macro(db_idx256_find_primary) \ -intrinsic_macro(db_idx256_find_secondary) \ -intrinsic_macro(db_idx256_lowerbound) \ -intrinsic_macro(db_idx256_upperbound) \ -intrinsic_macro(db_idx256_end) \ -intrinsic_macro(db_idx256_next) \ -intrinsic_macro(db_idx256_previous) \ -intrinsic_macro(db_idx_double_store) \ -intrinsic_macro(db_idx_double_remove) \ -intrinsic_macro(db_idx_double_update) \ -intrinsic_macro(db_idx_double_find_primary) \ -intrinsic_macro(db_idx_double_find_secondary) \ -intrinsic_macro(db_idx_double_lowerbound) \ -intrinsic_macro(db_idx_double_upperbound) \ -intrinsic_macro(db_idx_double_end) \ -intrinsic_macro(db_idx_double_next) \ -intrinsic_macro(db_idx_double_previous) \ -intrinsic_macro(db_idx_long_double_store) \ -intrinsic_macro(db_idx_long_double_remove) \ -intrinsic_macro(db_idx_long_double_update) \ -intrinsic_macro(db_idx_long_double_find_primary) \ -intrinsic_macro(db_idx_long_double_find_secondary) \ -intrinsic_macro(db_idx_long_double_lowerbound) \ -intrinsic_macro(db_idx_long_double_upperbound) \ -intrinsic_macro(db_idx_long_double_end) \ -intrinsic_macro(db_idx_long_double_next) \ -intrinsic_macro(db_idx_long_double_previous) \ -intrinsic_macro(db_store_i64) \ -intrinsic_macro(db_update_i64) \ -intrinsic_macro(db_remove_i64) \ -intrinsic_macro(db_get_i64) \ -intrinsic_macro(db_next_i64) \ -intrinsic_macro(db_previous_i64) \ -intrinsic_macro(db_find_i64) \ -intrinsic_macro(db_lowerbound_i64) \ -intrinsic_macro(db_upperbound_i64) \ -intrinsic_macro(db_end_i64) \ -intrinsic_macro(assert_recover_key) \ -intrinsic_macro(recover_key) \ -intrinsic_macro(assert_sha256) \ -intrinsic_macro(assert_sha1) \ -intrinsic_macro(assert_sha512) \ -intrinsic_macro(assert_ripemd160) \ -intrinsic_macro(sha1) \ -intrinsic_macro(sha256) \ -intrinsic_macro(sha512) \ -intrinsic_macro(ripemd160) \ -intrinsic_macro(check_transaction_authorization) \ -intrinsic_macro(check_permission_authorization) \ -intrinsic_macro(get_permission_last_used) \ -intrinsic_macro(get_account_creation_time) \ -intrinsic_macro(current_time) \ -intrinsic_macro(publication_time) \ -intrinsic_macro(read_action_data) \ -intrinsic_macro(action_data_size) \ -intrinsic_macro(current_receiver) \ -intrinsic_macro(require_recipient) \ -intrinsic_macro(require_auth) \ -intrinsic_macro(require_auth2) \ -intrinsic_macro(has_auth) \ -intrinsic_macro(is_account) \ -intrinsic_macro(prints) \ -intrinsic_macro(prints_l) \ -intrinsic_macro(printi) \ -intrinsic_macro(printui) \ -intrinsic_macro(printi128) \ -intrinsic_macro(printui128) \ -intrinsic_macro(printsf) \ -intrinsic_macro(printdf) \ -intrinsic_macro(printqf) \ -intrinsic_macro(printn) \ -intrinsic_macro(printhex) \ -intrinsic_macro(read_transaction) \ -intrinsic_macro(transaction_size) \ -intrinsic_macro(expiration) \ -intrinsic_macro(tapos_block_prefix) \ -intrinsic_macro(tapos_block_num) \ -intrinsic_macro(get_action) \ -intrinsic_macro(send_inline) \ -intrinsic_macro(send_context_free_inline) \ -intrinsic_macro(send_deferred) \ -intrinsic_macro(cancel_deferred) \ -intrinsic_macro(get_context_free_data) - -#define CREATE_ENUM(name) \ - name, - -#define GENERATE_TYPE_MAPPING(name) \ - struct __ ## name ## _types { \ - using deduced_full_ts = decltype(eosio::native::get_args_full(::name)); \ - using deduced_ts = decltype(eosio::native::get_args(::name)); \ - using res_t = decltype(std::apply(::name, deduced_ts{})); \ - static constexpr auto is = std::make_index_sequence::value>(); \ - }; - -#define GET_TYPE(name) \ - decltype(create_function(eosio::native::intrinsics::__ ## name ## _types::is)), - -#define REGISTER_INTRINSIC(name) \ - create_function(eosio::native::intrinsics::__ ## name ## _types::is), - -}} //ns eosio::native diff --git a/libraries/native/native/eosio/intrinsics_def.hpp b/libraries/native/native/eosio/intrinsics_def.hpp index 42da1b3b96..9166d1f2a4 100644 --- a/libraries/native/native/eosio/intrinsics_def.hpp +++ b/libraries/native/native/eosio/intrinsics_def.hpp @@ -29,24 +29,27 @@ namespace eosio { namespace native { auto get_args(R(Args...)) { return std::tuple...>{}; } - + template auto create_function(std::index_sequence) { - return std::function::type ...)>{ - [](typename std::tuple_element::type ...) { + return std::function::type ...)>{ + [](typename std::tuple_element::type ...) { eosio_assert(false, "unsupported intrinsic"); return (R)0; } }; - } + } #define INTRINSICS(intrinsic_macro) \ intrinsic_macro(get_resource_limits) \ intrinsic_macro(set_resource_limits) \ intrinsic_macro(set_proposed_producers) \ +intrinsic_macro(set_proposed_producers_ex) \ intrinsic_macro(get_blockchain_parameters_packed) \ intrinsic_macro(set_blockchain_parameters_packed) \ intrinsic_macro(is_privileged) \ intrinsic_macro(set_privileged) \ +intrinsic_macro(is_feature_activated) \ +intrinsic_macro(preactivate_feature) \ intrinsic_macro(get_active_producers) \ intrinsic_macro(db_idx64_store) \ intrinsic_macro(db_idx64_remove) \ @@ -153,7 +156,8 @@ intrinsic_macro(send_inline) \ intrinsic_macro(send_context_free_inline) \ intrinsic_macro(send_deferred) \ intrinsic_macro(cancel_deferred) \ -intrinsic_macro(get_context_free_data) +intrinsic_macro(get_context_free_data) \ +intrinsic_macro(get_sender) #define CREATE_ENUM(name) \ name, diff --git a/libraries/native/tester.hpp b/libraries/native/tester.hpp deleted file mode 100644 index 21ce01f33b..0000000000 --- a/libraries/native/tester.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once -#include -#include "crt.hpp" -#include "intrinsics.hpp" -#include -#include - -#warning " is deprecated use " - -extern "C" bool ___disable_output; -extern "C" bool ___has_failed; -extern "C" bool ___earlier_unit_test_has_failed; - -inline void silence_output(bool t) { - ___disable_output = t; -} -inline bool has_failed() { - return ___has_failed; -} - -extern "C" void apply(uint64_t, uint64_t, uint64_t); - -template -inline bool expect_assert(bool check, const std::string& li, Pred&& pred, F&& func, Args... args) { - std_err.clear(); - __set_env_test(); - int ret = setjmp(*___env_ptr); - bool disable_out = ___disable_output; - if (ret == 0) { - func(args...); - __reset_env(); - silence_output(false); - if (!check) - eosio_assert(false, std::string("error : expect_assert, no assert {"+li+"}").c_str()); - eosio::print("error : expect_assert, no assert {"+li+"}\n"); - silence_output(disable_out); - return false; - } - __reset_env(); - bool passed = pred(std_err.get()); - std_err.clear(); - silence_output(false); - if (!check) - eosio_assert(passed, std::string("error : expect_assert, wrong assert {"+li+"}").c_str()); - if (!passed) - eosio::print("error : expect_assert, wrong assert {"+li+"}\n"); - silence_output(disable_out); - - return passed; -} - -template -inline bool expect_assert(bool check, const std::string& li, const char (&expected)[N], F&& func, Args... args) { - return expect_assert(check, li, - [&](const std::string& s) { - return std_err.index == N-1 && - memcmp(expected, s.c_str(), N-1) == 0; }, func, args...); -} - -template -inline bool expect_print(bool check, const std::string& li, Pred&& pred, F&& func, Args... args) { - std_out.clear(); - func(args...); - bool passed = pred(std_out.get()); - std_out.clear(); - bool disable_out = ___disable_output; - silence_output(false); - if (!check) - eosio_assert(passed, std::string("error : wrong print message {"+li+"}").c_str()); - if (!passed) - eosio::print("error : wrong print message {"+li+"}\n"); - silence_output(disable_out); - return passed; -} - -template -inline bool expect_print(bool check, const std::string& li, const char (&expected)[N], F&& func, Args... args) { - return expect_print(check, li, - [&](const std::string& s) { - return std_out.index == N-1 && - memcmp(expected, s.c_str(), N-1) == 0; }, func, args...); - -} - -#define CHECK_ASSERT(...) \ - ___has_failed |= !expect_assert(true, std::string(__FILE__)+":"+__func__+":"+(std::to_string(__LINE__)), __VA_ARGS__); - -#define REQUIRE_ASSERT(...) \ - expect_assert(false, std::string(__FILE__)+":"+__func__+":"+(std::to_string(__LINE__)), __VA_ARGS__); - -#define CHECK_PRINT(...) \ - ___has_failed |= !expect_print(true, std::string(__FILE__)+":"+__func__+":"+(std::to_string(__LINE__)), __VA_ARGS__); - -#define REQUIRE_PRINT(...) \ - expect_print(false, std::string(__FILE__)+":"+__func__+":"+(std::to_string(__LINE__)), __VA_ARGS__); - -#define CHECK_EQUAL(X, Y) \ - if (!(X == Y)) { \ - ___has_failed = true; \ - eosio::print(std::string("CHECK_EQUAL failed (")+#X+" != "+#Y+") {"+__FILE__+":"+std::to_string(__LINE__)+"}\n"); \ - } - -#define REQUIRE_EQUAL(X, Y) \ - eosio_assert(X == Y, std::string(std::string("REQUIRE_EQUAL failed (")+#X+" != "+#Y+") {"+__FILE__+":"+std::to_string(__LINE__)+"}").c_str()); - -#define EOSIO_TEST(X) \ - int X ## _ret = setjmp(*___env_ptr); \ - if ( X ## _ret == 0 ) \ - X(); \ - else { \ - bool ___original_disable_output = ___disable_output; \ - silence_output(false); \ - eosio::print("\033[1;37m", #X, " \033[0;37munit test \033[1;31mfailed\033[0m (aborted)\n"); \ - ___has_failed = true; \ - silence_output(___original_disable_output); \ - } - -#define EOSIO_TEST_BEGIN(X) \ - void X() { \ - static constexpr const char* __test_name = #X; \ - ___earlier_unit_test_has_failed = ___has_failed; \ - ___has_failed = false; - -#define EOSIO_TEST_END \ - bool ___original_disable_output = ___disable_output; \ - silence_output(false); \ - if (___has_failed) \ - eosio::print("\033[1;37m", __test_name, " \033[0;37munit test \033[1;31mfailed\033[0m\n"); \ - else \ - eosio::print("\033[1;37m", __test_name, " \033[0;37munit test \033[1;32mpassed\033[0m\n"); \ - silence_output(___original_disable_output); \ - ___has_failed |= ___earlier_unit_test_has_failed; \ - ___earlier_unit_test_has_failed = ___has_failed; \ - } diff --git a/modules/EosioCDTMacros.cmake.in b/modules/EosioCDTMacros.cmake.in index 58eff83ed6..f4e439de8c 100644 --- a/modules/EosioCDTMacros.cmake.in +++ b/modules/EosioCDTMacros.cmake.in @@ -38,7 +38,7 @@ macro (add_native_executable TARGET) target_compile_options( ${TARGET} PUBLIC -fnative ) set_target_properties( ${TARGET} PROPERTIES LINK_FLAGS "-fnative" SUFFIX "" ) get_target_property(BINOUTPUT ${TARGET} BINARY_DIR) - if (${CMAKE_BUILD_TYPE} STREQUAL "Debug" AND APPLE) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND APPLE) target_compile_options( ${TARGET} PUBLIC -g ) find_program ( name NAMES "dsymutil" ) if ( name ) diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index eb7df5300e..de3bcfdf2f 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_PATCH=${VERSION_PATCH} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" @@ -16,3 +16,14 @@ ExternalProject_Add( BUILD_ALWAYS 1 DEPENDS EosioClang ) + +ExternalProject_Add( + toolchain-tester + SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools/toolchain-tester" + BINARY_DIR "${CMAKE_BINARY_DIR}/tools/toolchain-tester" + UPDATE_COMMAND "" + PATCH_COMMAND "" + TEST_COMMAND "" + INSTALL_COMMAND "" + BUILD_ALWAYS 1 +) diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh deleted file mode 100644 index 8a400a1533..0000000000 --- a/scripts/eosio_build_amazon.sh +++ /dev/null @@ -1,237 +0,0 @@ - OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' | cut -d'.' -f1 ) - - MEM_MEG=$( free -m | sed -n 2p | 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 ) - MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) - JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - - 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: %s\\n" "${OS_NAME}" - printf "\\tOS Version: %s\\n" "${OS_VER}" - printf "\\tCPU speed: %sMhz\\n" "${CPU_SPEED}" - printf "\\tCPU cores: %s\\n" "${CPU_CORE}" - printf "\\tPhysical Memory: %sMgb\\n" "${MEM_MEG}" - printf "\\tDisk space total: %sGb\\n" "${DISK_TOTAL}" - printf "\\tDisk space available: %sG\\n" "${DISK_AVAIL}" - - if [ "${MEM_MEG}" -lt 7000 ]; then - printf "\\tYour system must have 7 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 "${DISK_MIN}" ]; then - printf "\\tYou must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "\\texiting now.\\n" - exit 1 - fi - - printf "\\n\\tChecking Yum installation.\\n" - if ! YUM=$( command -v yum 2>/dev/null ) - then - printf "\\n\\tYum must be installed to compile EOS.IO.\\n" - printf "\\n\\tExiting now.\\n" - exit 1 - fi - - printf "\\tYum installation found at %s.\\n" "${YUM}" - printf "\\tUpdating YUM.\\n" - if ! UPDATE=$( sudo "$YUM" -y update ) - then - printf "\\n\\tYUM update failed.\\n" - printf "\\n\\tExiting now.\\n" - exit 1 - fi - printf "\\t%s\\n" "${UPDATE}" - - DEP_ARRAY=( git gcc72.x86_64 gcc72-c++.x86_64 autoconf automake libtool make bzip2 \ - bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 libstdc++72.x86_64 \ - python27.x86_64 python36-devel.x86_64 libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64) - 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 %s ${bldred} NOT ${txtrst} found.\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf "\\tPackage %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi - done - - if [ "${COUNT}" -gt 1 ]; 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" - if ! sudo "${YUM}" -y install ${DEP} - 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]* ) printf "\\nUser aborting installation of required dependencies,\\n Exiting now.\\n"; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done - else - printf "\\n\\tNo required YUM dependencies to install.\\n" - fi - - if [ "${ENABLE_COVERAGE_TESTING}" = true ]; then - printf "\\n\\tChecking perl installation.\\n" - perl_bin=$( command -v perl 2>/dev/null ) - if [ -z "${perl_bin}" ]; then - printf "\\n\\tInstalling perl.\\n" - if ! sudo "${YUM}" -y install perl - then - printf "\\n\\tUnable to install perl at this time.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - fi - else - printf "\\tPerl installation found at %s.\\n" "${perl_bin}" - fi - printf "\\n\\tChecking LCOV installation.\\n" - if [ ! -e "/usr/local/bin/lcov" ]; then - printf "\\n\\tLCOV installation not found.\\n" - printf "\\tInstalling LCOV.\\n" - if ! cd "${TEMP_DIR}" - then - printf "\\n\\tUnable to enter %s. Exiting now.\\n" "${TEMP_DIR}" - exit 1; - fi - if ! git clone "https://github.com/linux-test-project/lcov.git" - then - printf "\\n\\tUnable to clone LCOV at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/lcov" - then - printf "\\n\\tUnable to enter %s/lcov. Exiting now.\\n" "${TEMP_DIR}" - exit 1; - fi - if ! sudo make install - then - printf "\\n\\tUnable to install LCOV at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - rm -rf "${TEMP_DIR}/lcov" - printf "\\n\\tSuccessfully installed LCOV.\\n\\n" - else - printf "\\n\\tLCOV installation found @ /usr/local/bin.\\n" - fi - fi - - printf "\\n\\tChecking CMAKE installation.\\n" - if [ ! -e "${CMAKE}" ]; then - printf "\\tInstalling CMAKE.\\n" - if ! mkdir -p "${HOME}/opt/" 2>/dev/null - then - printf "\\n\\tUnable to create directory %s/opt.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${HOME}/opt" - then - printf "\\n\\tUnable to enter directory %s/opt.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - STATUS=$( curl -LO -w '%{http_code}' --connect-timeout 30 "https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz" ) - if [ "${STATUS}" -ne 200 ]; then - printf "\\tUnable to clone CMAKE repo.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! tar xf "${HOME}/opt/cmake-3.10.2.tar.gz" - then - printf "\\tUnable to unarchive file %s/opt/cmake-3.10.2.tar.gz at this time.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! rm -f "${HOME}/opt/cmake-3.10.2.tar.gz" - then - printf "\\tUnable to remove file %s/opt/cmake-3.10.2.tar.gz.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! ln -s "${HOME}/opt/cmake-3.10.2/" "${HOME}/opt/cmake" - then - printf "\\tUnable to symlink directory %s/opt/cmake-3.10.2/ to %s/opt/cmake at this time.\\n" "${HOME}" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${HOME}/opt/cmake/" - then - printf "\\n\\tUnable to change directory into %s/opt/cmake.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! ./bootstrap - then - printf "\\tRunning bootstrap for CMAKE exited with the above error.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! make -j"${JOBS}" - then - printf "\\tError compiling CMAKE.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - printf "\\tCMAKE successfully installed @ %s.\\n" "${CMAKE}" - else - printf "\\tCMAKE found @ %s.\\n" "${CMAKE}" - fi - - if [ -d "${HOME}/opt/boost_1_67_0" ]; then - if ! mv "${HOME}/opt/boost_1_67_0" "$BOOST_ROOT" - then - printf "\\n\\tUnable to move directory %s/opt/boost_1_67_0 to %s.\\n" "${HOME}" "${BOOST_ROOT}" - printf "\\n\\tExiting now.\\n" - exit 1 - fi - if [ -d "$BUILD_DIR" ]; then - if ! rm -rf "$BUILD_DIR" - then - printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "$BUILD_DIR" "${BASH_SOURCE[0]}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - fi - fi - - function print_instructions() - { - printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" - printf '\texport PATH=${HOME}/opt/mongodb/bin:$PATH \n' - printf "\\tcd %s; make test\\n\\n" "${BUILD_DIR}" - return 0 - } diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh deleted file mode 100644 index a9e264bb94..0000000000 --- a/scripts/eosio_build_centos.sh +++ /dev/null @@ -1,308 +0,0 @@ - OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' \ - | cut -d'.' -f1 ) - - MEM_MEG=$( free -m | sed -n 2p | 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 ) - MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) - JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - - DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) - DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) - DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) - DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) - DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - - printf "\\n\\tOS name: %s\\n" "${OS_NAME}" - printf "\\tOS Version: %s\\n" "${OS_VER}" - printf "\\tCPU speed: %sMhz\\n" "${CPU_SPEED}" - printf "\\tCPU cores: %s\\n" "${CPU_CORE}" - printf "\\tPhysical Memory: %s Mgb\\n" "${MEM_MEG}" - printf "\\tDisk install: %s\\n" "${DISK_INSTALL}" - printf "\\tDisk space total: %sG\\n" "${DISK_TOTAL%.*}" - printf "\\tDisk space available: %sG\\n" "${DISK_AVAIL%.*}" - - if [ "${MEM_MEG}" -lt 7000 ]; then - printf "\\n\\tYour system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - - if [ "${OS_VER}" -lt 7 ]; then - printf "\\n\\tYou must be running Centos 7 or higher to install EOSIO.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - - if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then - printf "\\n\\tYou must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - - printf "\\n\\tChecking Yum installation\\n" - if ! YUM=$( command -v yum 2>/dev/null ) - then - printf "\\n\\tYum must be installed to compile EOS.IO.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - - printf "\\tYum installation found at %s.\\n" "${YUM}" - printf "\\n\\tChecking installation of Centos Software Collections Repository.\\n" - - SCL=$( command -v scl 2>/dev/null ) - if [ -z "${SCL}" ]; then - printf "\\n\\tThe Centos Software Collections Repository, devtoolset-7 and Python3 are required to install EOSIO.\\n" - printf "\\tDo you wish to install and enable this repository, devtoolset-7 and Python3 packages?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "\\n\\n\\tInstalling SCL.\\n\\n" - if ! sudo "${YUM}" -y --enablerepo=extras install centos-release-scl 2>/dev/null - then - printf "\\n\\tCentos Software Collections Repository installation failed.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - else - printf "\\n\\tCentos Software Collections Repository installed successfully.\\n" - fi - printf "\\n\\n\\tInstalling devtoolset-7.\\n\\n" - if ! sudo "${YUM}" install -y devtoolset-7 2>/dev/null - then - printf "\\n\\tCentos devtoolset-7 installation failed.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - else - printf "\\n\\tCentos devtoolset installed successfully.\\n" - fi - printf "\\n\\n\\tInstalling Python3.\\n\\n" - if ! sudo "${YUM}" install -y python33.x86_64 2>/dev/null - then - printf "\\n\\tCentos Python3 installation failed.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - else - printf "\\n\\tCentos Python3 installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of required Centos Software Collections Repository, Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done - else - printf "\\tCentos Software Collections Repository found.\\n\\n" - fi - - printf "\\n\\tEnabling Centos devtoolset-7.\\n" -# shellcheck disable=SC1091 - if ! source "/opt/rh/devtoolset-7/enable" 2>/dev/null - then - printf "\\n\\tUnable to enable Centos devtoolset-7 at this time.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - fi - printf "\\tCentos devtoolset-7 successfully enabled.\\n\\n" - -# printf "\\n\\tEnabling Centos python3 installation.\\n" -# shellcheck disable=SC1091 -# if ! source /opt/rh/python33/enable -# then -# printf "\\n\\tUnable to enable Centos python3 at this time.\\n" -# printf "\\n\\tExiting now.\\n\\n" -# exit 1; -# fi -# printf "\\tCentos python3 successfully enabled.\\n" - - printf "\\n\\tUpdating YUM repository.\\n\\n" - - if ! sudo "${YUM}" -y update 2>/dev/null - then - printf "\\n\\tYUM update failed.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - fi - - printf "\\n\\tYUM repository successfully updated.\\n\\n" - - DEP_ARRAY=( git autoconf automake bzip2 libtool ocaml.x86_64 doxygen graphviz-devel.x86_64 \ - libicu-devel.x86_64 bzip2.x86_64 bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 \ - python-devel.x86_64 gettext-devel.x86_64 gcc-c++.x86_64) - 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 %s ${bldred} NOT ${txtrst} found.\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf "\\tPackage %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi - done - - if [ "${COUNT}" -gt 1 ]; 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" - if ! sudo "${YUM}" -y install ${DEP} - then - printf "\\n\\tYUM dependency installation failed.\\n" - printf "\\n\\tExiting now.\\n\\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 - - if [ "${ENABLE_COVERAGE_TESTING}" = true ]; then - printf "\\n\\tChecking perl installation.\\n" - perl_bin=$( command -v perl 2>/dev/null ) - if [ -z "${perl_bin}" ]; then - printf "\\n\\tInstalling perl.\\n" - if ! sudo "${YUM}" -y install perl - then - printf "\\n\\tUnable to install perl at this time.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - fi - else - printf "\\tPerl installation found at %s.\\n" "${perl_bin}" - fi - printf "\\n\\tChecking LCOV installation.\\n" - lcov=$( command -v lcov 2>/dev/null ) - if [ -z "${lcov}" ]; then - printf "\\n\\tLCOV installation not found.\\n" - printf "\\tInstalling LCOV.\\n" - if ! cd "${TEMP_DIR}" - then - printf "\\tUnable to enter directory %s.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! git clone https://github.com/linux-test-project/lcov.git - then - printf "\\tUnable to clone LCOV at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/lcov" - then - printf "\\tUnable to enter directory %s/lcov.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! sudo make install - then - printf "\\tUnable to install LCOV at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${CWD}" - then - printf "\\tUnable to enter directory %s.\\n" "${CWD}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! rm -rf "${TEMP_DIR}/lcov" - then - printf "\\tUnable to remove directory %s/lcov.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - printf "\\n\\tSuccessfully installed LCOV.\\n" - else - printf "\\tLCOV installation found @ %s.\\n" "${lcov}" - fi - fi - - printf "\\n\\tChecking CMAKE installation.\\n" - if [ ! -e "${CMAKE}" ]; then - printf "\\tInstalling CMAKE\\n" - if [ ! -d "${HOME}/opt" ]; then - if ! mkdir "${HOME}/opt" - then - printf "\\tUnable to create directory %s/opt.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - fi - if ! cd "${HOME}/opt" - then - printf "\\tUnable to enter directory %s/opt.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - STATUS=$(curl -LO -w '%{http_code}' --connect-timeout 30 https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz) - if [ "${STATUS}" -ne 200 ]; then - printf "\\tUnable to download CMAKE at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! tar xf "${HOME}/opt/cmake-3.10.2.tar.gz" - then - printf "\\tUnable to unarchive %s/opt/cmake-3.10.2.tar.gz.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! rm -f "${HOME}/opt/cmake-3.10.2.tar.gz" - then - printf "\\tUnable to remove %s/opt/cmake-3.10.2.tar.gz.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! ln -s "${HOME}/opt/cmake-3.10.2/" "${HOME}/opt/cmake" - then - printf "\\tUnable to symlink %s/opt/cmake-3.10.2 to %s/opt/cmake-3.10.2/cmake.\\n" "${HOME}" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${HOME}/opt/cmake" - then - printf "\\tUnable to enter directory %s/opt/cmake.\\n" "${HOME}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! ./bootstrap - then - printf "\\tError running bootstrap for CMAKE.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! make -j"${JOBS}" - then - printf "\\tCompiling CMAKE has exited with the above error.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - printf "\\tCMAKE successfully installed @ %s.\\n\\n" "${CMAKE}" - else - printf "\\tCMAKE found @ %s.\\n" "${CMAKE}" - fi - - function print_instructions() - { - printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" - printf "\\tsource /opt/rh/python33/enable\\n" - printf '\texport PATH=${HOME}/opt/mongodb/bin:$PATH\n' - printf "\\tcd %s; make test\\n\\n" "${BUILD_DIR}" - return 0 - } diff --git a/scripts/eosio_build_darwin.sh b/scripts/eosio_build_darwin.sh deleted file mode 100644 index b202108104..0000000000 --- a/scripts/eosio_build_darwin.sh +++ /dev/null @@ -1,181 +0,0 @@ - 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) / 10^8) / 10") - CPU_CORE=$( sysctl -in machdep.cpu.core_count ) - - DISK_INSTALL=$(df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 || cut -d' ' -f1) - blksize=$(df . | head -1 | awk '{print $2}' | cut -d- -f1) - gbfactor=$(( 1073741824 / blksize )) - total_blks=$(df . | tail -1 | awk '{print $2}') - avail_blks=$(df . | tail -1 | awk '{print $4}') - DISK_TOTAL=$((total_blks / gbfactor )) - DISK_AVAIL=$((avail_blks / gbfactor )) - - printf "\\n\\tOS name: %s\\n" "${ARCH}" - printf "\\tOS Version: %s\\n" "${OS_VER}" - printf "\\tCPU speed: %sGhz\\n" "${CPU_SPEED}" - printf "\\tCPU cores: %s\\n" "${CPU_CORE}" - printf "\\tPhysical Memory: %s Gbytes\\n" "${MEM_GIG}" - printf "\\tDisk install: %s\\n" "${DISK_INSTALL}" - printf "\\tDisk space total: %sG\\n" "${DISK_TOTAL}" - printf "\\tDisk space available: %sG\\n\\n" "${DISK_AVAIL}" - - if [ "${MEM_GIG}" -lt 7 ]; then - echo "Your system must have 7 or more Gigabytes of physical memory installed." - echo "Exiting now." - exit 1 - fi - - if [ "${OS_MIN}" -lt 12 ]; then - 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 "$DISK_MIN" ]; then - echo "You must have at least ${DISK_MIN}GB of available storage to install EOSIO." - echo "Exiting now." - exit 1 - fi - - printf "\\tChecking xcode-select installation\\n" - if ! XCODESELECT=$( command -v xcode-select) - then - printf "\\n\\tXCode must be installed in order to proceed.\\n\\n" - printf "\\tExiting now.\\n" - exit 1 - fi - - printf "\\txcode-select installation found @ \\n" - printf "\\t%s \\n\\n" "${XCODESELECT}" - - printf "\\tChecking Ruby installation.\\n" - if ! RUBY=$( command -v ruby) - then - printf "\\nRuby must be installed in order to proceed.\\n\\n" - printf "\\tExiting now.\\n" - exit 1 - fi - - printf "\\tRuby installation found @ \\n" - printf "\\t%s \\n\\n" "${RUBY}" - - printf "\\tChecking Home Brew installation\\n" - if ! BREW=$( command -v brew ) - 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; - if ! "${RUBY}" -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - then - echo "Unable to install homebrew at this time. Exiting now." - exit 1; - else - BREW=$( command -v brew ) - fi - break;; - [Nn]* ) echo "User aborted homebrew installation. Exiting now."; - exit 1;; - * ) echo "Please enter 1 for yes or 2 for no.";; - esac - done - fi - - printf "\\tHome Brew installation found @\\n" - printf "\\t%s\\n\\n" "${BREW}" - - COUNT=1 - PERMISSION_GETTEXT=0 - DISPLAY="" - DEP="" - - printf "\\tChecking dependencies.\\n" - var_ifs="${IFS}" - IFS="," - while read -r name tester testee brewname uri - do - printf "\\tChecking %s ... " "${name}" - if [ "${tester}" "${testee}" ]; then - printf "\\t\\t %s found\\n" "${name}" - continue - fi - # resolve conflict with homebrew glibtool and apple/gnu installs of libtool - if [ "${testee}" == "/usr/local/bin/glibtool" ]; then - if [ "${tester}" "/usr/local/bin/libtool" ]; then - printf "\\t\\t %s found\\n" "${name}" - continue - fi - fi - if [ "${brewname}" = "gettext" ]; then - PERMISSION_GETTEXT=1 - fi - DEP=$DEP"${brewname} " - DISPLAY="${DISPLAY}${COUNT}. ${name}\\n\\t" - printf "\\t\\t %s ${bldred}NOT${txtrst} found.\\n" "${name}" - (( COUNT++ )) - done < scripts/eosio_build_dep - IFS="${var_ifs}" - - printf "\\tChecking Python3 ... " - if [ -z "$( python3 -c 'import sys; print(sys.version_info.major)' 2>/dev/null )" ]; then - DEP=$DEP"python@3 " - DISPLAY="${DISPLAY}${COUNT}. Python 3\\n\\t" - printf "\\t\\t python3 ${bldred}NOT${txtrst} found.\\n" - (( COUNT++ )) - else - printf "\\t\\t Python3 found\\n" - fi - - if [ $COUNT -gt 1 ]; then - printf "\\n\\tThe following dependencies are required to install EOSIO.\\n" - printf "\\n\\t%s\\n\\n" "${DISPLAY}" - 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" - if ! brew update - then - printf "\\tUnable to update Home Brew at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - printf "\\tInstalling Dependencies.\\n" - if ! "${BREW}" install --force ${DEP} - then - printf "\\tHomebrew exited with the above errors.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! "${BREW}" unlink {DEP} && "${BREW}" link --force ${DEP} - then - printf "\\tHomebrew exited with the above errors.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - 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 Home Brew dependencies to install.\\n" - fi - - function print_instructions() - { - printf "\\tcd %s; make test\\n\\n" "${BUILD_DIR}" - return 0 - } diff --git a/scripts/eosio_build_dep b/scripts/eosio_build_dep deleted file mode 100644 index d5f5c709e3..0000000000 --- a/scripts/eosio_build_dep +++ /dev/null @@ -1,9 +0,0 @@ -automake,-x,/usr/local/bin/automake,automake,http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz -Libtool,-x,/usr/local/bin/glibtool,libtool,http://gnu.askapache.com/libtool/libtool-2.4.6.tar.gz -wget,-x,/usr/local/bin/wget,wget,https://ftp.gnu.org/gnu/wget/wget-1.19.2.tar.gz -CMake,-x,/usr/local/bin/cmake,cmake,https://cmake.org/files/v3.10/cmake-3.10.1-Darwin-x86_64.tar.gz -GMP,-f,/usr/local/opt/gmp/include/gmpxx.h,gmp,https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.bz2 -gettext,-x,/usr/local/opt/gettext/bin/gettext,gettext,https://ftp.gnu.org/pub/gnu/gettext/gettext-latest.tar.gz -Doxygen,-x,/usr/local/bin/doxygen,doxygen,http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.14.src.tar.gz -Graphviz,-x,/usr/local/bin/dot,graphviz,https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz -LCOV,-f,/usr/local/bin/lcov,lcov,http://downloads.sourceforge.net/ltp/lcov-1.13.tar.gz diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh deleted file mode 100644 index 051d0b2a33..0000000000 --- a/scripts/eosio_build_fedora.sh +++ /dev/null @@ -1,163 +0,0 @@ - OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' ) - - MEM_MEG=$( free -m | sed -n 2p | 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 ) - MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) - JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - - DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) - DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) - DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) - DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) - DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - - printf "\\n\\tOS name: %s\\n" "${OS_NAME}" - printf "\\tOS Version: %s\\n" "${OS_VER}" - printf "\\tCPU speed: %sMhz\\n" "${CPU_SPEED}" - printf "\\tCPU cores: %s\\n" "${CPU_CORE}" - printf "\\tPhysical Memory: %s Mgb\\n" "${MEM_MEG}" - printf "\\tDisk install: %s\\n" "${DISK_INSTALL}" - printf "\\tDisk space total: %sG\\n" "${DISK_TOTAL%.*}" - printf "\\tDisk space available: %sG\\n" "${DISK_AVAIL%.*}" - - if [ "${MEM_MEG}" -lt 7000 ]; then - printf "\\tYour system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "\\tExiting now.\\n" - exit 1; - fi - - if [ "${OS_VER}" -lt 25 ]; then - printf "\\tYou must be running Fedora 25 or higher to install EOSIO.\\n" - printf "\\tExiting now.\\n" - exit 1; - fi - - if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then - printf "\\tYou must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "\\tExiting now.\\n" - exit 1; - fi - - printf "\\n\\tChecking Yum installation\\n" - - YUM=$( command -v yum 2>/dev/null ) - if [ -z "${YUM}" ]; then - printf "\\n\\tYum must be installed to compile EOS.IO.\\n" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - - printf "\\tYum installation found at %s.\\n" "${YUM}" - printf "\\tUpdating YUM.\\n" - if ! sudo yum -y update - then - printf "\\n\\tYUM update failed with the above errors.\\n" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - - DEP_ARRAY=( git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make cmake.x86_64 \ - bzip2.x86_64 bzip2-devel.x86_64 gmp-devel.x86_64 libstdc++-devel.x86_64 \ - python2-devel.x86_64 python3-devel.x86_64 libedit.x86_64 \ - graphviz.x86_64 doxygen.x86_64 ) - 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 %s ${bldred} NOT ${txtrst} found.\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf "\\tPackage %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi - done - - if [ ${COUNT} -gt 1 ]; 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" - if ! sudo yum -y install ${DEP} - 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 - - if [ "${ENABLE_COVERAGE_TESTING}" = true ]; then - printf "\\n\\tCode coverage build requested." - printf "\\n\\tChecking perl installation.\\n" - perl_bin=$( command -v perl 2>/dev/null ) - if [ -z "${perl_bin}" ]; then - printf "\\n\\tInstalling perl.\\n" - if ! sudo "${YUM}" -y install perl - then - printf "\\n\\tUnable to install perl at this time.\\n" - printf "\\n\\tExiting now.\\n\\n" - exit 1; - fi - else - printf "\\tPerl installation found at %s.\\n" "${perl_bin}" - fi - printf "\\n\\tChecking LCOV installation." - if [ ! -e "/usr/local/bin/lcov" ]; then - printf "\\n\\tLCOV installation not found.\\n" - printf "\\tInstalling LCOV.\\n" - if ! cd "${TEMP_DIR}" - then - printf "\\n\\tUnable to enter %s. Exiting now.\\n" "${TEMP_DIR}" - exit 1; - fi - if ! git clone "https://github.com/linux-test-project/lcov.git" - then - printf "\\n\\tUnable to clone LCOV at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/lcov" - then - printf "\\n\\tUnable to enter %s/lcov. Exiting now.\\n" "${TEMP_DIR}" - exit 1; - fi - if ! sudo make install - then - printf "\\n\\tUnable to install LCOV at this time.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - rm -rf "${TEMP_DIR}/lcov" - printf "\\n\\tSuccessfully installed LCOV.\\n\\n" - else - printf "\\n\\tLCOV installation found @ /usr/local/bin.\\n" - fi - fi - - function print_instructions() - { - printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" - printf "\\tcd %s; make test\\n\\n" "${BUILD_DIR}" - return 0; - } diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh deleted file mode 100644 index e200a2f36f..0000000000 --- a/scripts/eosio_build_ubuntu.sh +++ /dev/null @@ -1,115 +0,0 @@ - OS_VER=$( grep VERSION_ID /etc/os-release | 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 | sed -n 2p | tr -s ' ' | cut -d\ -f2 || cut -d' ' -f2 ) - CPU_SPEED=$( lscpu | grep -m1 "MHz" | tr -s ' ' | cut -d\ -f3 || cut -d' ' -f3 | cut -d'.' -f1 ) - CPU_CORE=$( lscpu | grep "^CPU(s)" | tr -s ' ' | cut -d\ -f2 || cut -d' ' -f2 ) - - MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) - JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - - DISK_INSTALL=$(df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 || cut -d' ' -f1) - DISK_TOTAL_KB=$(df . | tail -1 | awk '{print $2}') - DISK_AVAIL_KB=$(df . | tail -1 | awk '{print $4}') - DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) - DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - - printf "\\n\\tOS name: %s\\n" "${OS_NAME}" - printf "\\tOS Version: %s\\n" "${OS_VER}" - printf "\\tCPU speed: %sMhz\\n" "${CPU_SPEED}" - printf "\\tCPU cores: %s\\n" "${CPU_CORE}" - printf "\\tPhysical Memory: %s Mgb\\n" "${MEM_MEG}" - printf "\\tDisk install: %s\\n" "${DISK_INSTALL}" - printf "\\tDisk space total: %sG\\n" "${DISK_TOTAL%.*}" - printf "\\tDisk space available: %sG\\n" "${DISK_AVAIL%.*}" - - if [ "${MEM_MEG}" -lt 7000 ]; then - printf "\\tYour system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "\\tExiting now.\\n" - exit 1 - fi - - case "${OS_NAME}" in - "Linux Mint") - if [ "${OS_MAJ}" -lt 18 ]; then - printf "\\tYou must be running Linux Mint 18.x or higher to install EOSIO.\\n" - printf "\\tExiting now.\\n" - exit 1 - fi - ;; - "Ubuntu") - if [ "${OS_MAJ}" -lt 16 ]; then - printf "\\tYou must be running Ubuntu 16.04.x or higher to install EOSIO.\\n" - printf "\\tExiting now.\\n" - exit 1 - fi - ;; - esac - - if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then - printf "\\tYou must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "\\tExiting now.\\n" - exit 1 - fi - - DEP_ARRAY=(clang-4.0 lldb-4.0 libclang-4.0-dev cmake make automake libbz2-dev libssl-dev \ - libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev python3-dev \ - autoconf libtool curl zlib1g-dev doxygen graphviz) - COUNT=1 - DISPLAY="" - DEP="" - - if [[ "${ENABLE_CODE_COVERAGE}" == true ]]; then - DEP_ARRAY+=(lcov) - fi - - 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 %s ${bldred} NOT ${txtrst} found.\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf "\\tPackage %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi - done - - if [ "${COUNT}" -gt 1 ]; 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 - if ! sudo apt-get -y install ${DEP} - 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 - - function print_instructions() - { - printf '\n\texport PATH=${HOME}/opt/mongodb/bin:$PATH\n' - printf "\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" - printf "\\tcd %s; make test\\n\\n" "${BUILD_DIR}" - return 0 - } diff --git a/scripts/eosiocdt_build.sh b/scripts/eosiocdt_build.sh new file mode 100755 index 0000000000..ba7e2ab64a --- /dev/null +++ b/scripts/eosiocdt_build.sh @@ -0,0 +1,185 @@ +#!/bin/bash + +printf "=========== eosio.cdt ===========\n\n" + +VERSION=2.1 # Build script version +CMAKE_BUILD_TYPE=Release +export DISK_MIN=20 +DOXYGEN=false +ENABLE_COVERAGE_TESTING=false +CORE_SYMBOL_NAME="SYS" +START_MAKE=true + +TIME_BEGIN=$( date -u +%s ) +txtbld=$(tput bold) +bldred=${txtbld}$(tput setaf 1) +txtrst=$(tput sgr0) + +export SRC_LOCATION=${HOME}/src +export OPT_LOCATION=${HOME}/opt +export VAR_LOCATION=${HOME}/var +export ETC_LOCATION=${HOME}/etc +export BIN_LOCATION=${HOME}/bin +export DATA_LOCATION=${HOME}/data +export CMAKE_VERSION_MAJOR=3 +export CMAKE_VERSION_MINOR=13 +export CMAKE_VERSION_PATCH=2 +export CMAKE_VERSION=${CMAKE_VERSION_MAJOR}.${CMAKE_VERSION_MINOR}.${CMAKE_VERSION_PATCH} +export BOOST_VERSION_MAJOR=1 +export BOOST_VERSION_MINOR=67 +export BOOST_VERSION_PATCH=0 +export BOOST_VERSION=${BOOST_VERSION_MAJOR}_${BOOST_VERSION_MINOR}_${BOOST_VERSION_PATCH} +export BOOST_ROOT=${SRC_LOCATION}/boost_${BOOST_VERSION} +export BOOST_LINK_LOCATION=${OPT_LOCATION}/boost +export TINI_VERSION=0.18.0 + +export PATH=$HOME/bin:$PATH:$HOME/opt/llvm/bin + +# Setup directories +mkdir -p $SRC_LOCATION +mkdir -p $OPT_LOCATION +mkdir -p $VAR_LOCATION +mkdir -p $BIN_LOCATION +mkdir -p $VAR_LOCATION/log +mkdir -p $ETC_LOCATION + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +REPO_ROOT="${SCRIPT_DIR}/.." +BUILD_DIR="${REPO_ROOT}/build" + +# Use current directory's tmp directory if noexec is enabled for /tmp +if (mount | grep "/tmp " | grep --quiet noexec); then + mkdir -p $REPO_ROOT/tmp + TEMP_DIR="${REPO_ROOT}/tmp" + rm -rf $REPO_ROOT/tmp/* +else # noexec wasn't found + TEMP_DIR="/tmp" +fi + +if [ ! -d "${REPO_ROOT}/.git" ]; then + printf "\\nThis build script only works with sources cloned from git\\n" + printf "Please clone a new eos directory with 'git clone https://github.com/EOSIO/eos --recursive'\\n" + printf "See the wiki for instructions: https://github.com/EOSIO/eos/wiki\\n" + exit 1 +fi + +cd $REPO_ROOT + +STALE_SUBMODS=$(( $(git submodule status --recursive | grep -c "^[+\-]") )) +if [ $STALE_SUBMODS -gt 0 ]; then + printf "\\ngit submodules are not up to date.\\n" + printf "Please run the command 'git submodule update --init --recursive'.\\n" + exit 1 +fi + +printf "Beginning build version: %s\\n" "${VERSION}" +printf "%s\\n" "$( date -u )" +printf "User: %s\\n" "$( whoami )" +# printf "git head id: %s\\n" "$( cat .git/refs/heads/master )" +printf "Current branch: %s\\n" "$( git rev-parse --abbrev-ref HEAD )" + +ARCH=$( uname ) +printf "\\nARCHITECTURE: %s\\n" "${ARCH}" + +# Find and use existing CMAKE +export CMAKE=$(command -v cmake 2>/dev/null) + +if [ "$ARCH" == "Linux" ]; then + # Check if cmake is already installed or not and use source install location + if [ -z $CMAKE ]; then export CMAKE=$HOME/bin/cmake; fi + export OS_NAME=$( cat /etc/os-release | grep ^NAME | cut -d'=' -f2 | sed 's/\"//gI' ) + case "$OS_NAME" in + "Amazon Linux AMI"|"Amazon Linux") + FILE="./scripts/eosiocdt_build_amazon.sh" + CXX_COMPILER=g++ + C_COMPILER=gcc + ;; + "CentOS Linux") + FILE="${REPO_ROOT}/scripts/eosiocdt_build_centos.sh" + CXX_COMPILER=g++ + C_COMPILER=gcc + ;; + "elementary OS") + FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" + CXX_COMPILER=clang++-4.0 + C_COMPILER=clang-4.0 + ;; + "Fedora") + FILE="${REPO_ROOT}/scripts/eosiocdt_build_fedora.sh" + CXX_COMPILER=g++ + C_COMPILER=gcc + ;; + "Linux Mint") + FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" + CXX_COMPILER=clang++-4.0 + C_COMPILER=clang-4.0 + ;; + "Ubuntu") + FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" + CXX_COMPILER=clang++-4.0 + C_COMPILER=clang-4.0 + ;; + "Debian GNU/Linux") + FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" + CXX_COMPILER=clang++-4.0 + C_COMPILER=clang-4.0 + ;; + *) + printf "\\nUnsupported Linux Distribution. Exiting now.\\n\\n" + exit 1 + esac +fi + +if [ "$ARCH" == "Darwin" ]; then + # Check if cmake is already installed or not and use source install location + if [ -z $CMAKE ]; then export CMAKE=/usr/local/bin/cmake; fi + FILE="${REPO_ROOT}/scripts/eosiocdt_build_darwin.sh" + FREE_MEM=`vm_stat | grep "Pages free:"` + read -ra FREE_MEM <<< "$FREE_MEM" + FREE_MEM=$((${FREE_MEM[2]%?}*(4096))) # free pages * page size +else + FREE_MEM=`LC_ALL=C free | grep "Mem:" | awk '{print $7}'` +fi + +cd $SRC_LOCATION +. "$FILE" # Execute OS specific build file + +CORES_AVAIL=`getconf _NPROCESSORS_ONLN` +MEM_CORES=$(( ${FREE_MEM}/4000000 )) # 4 gigabytes per core +MEM_CORES=$(( $MEM_CORES > 0 ? $MEM_CORES : 1 )) +CORES=$(( $CORES_AVAIL < $MEM_CORES ? $CORES_AVAIL : $MEM_CORES )) + +mkdir -p $BUILD_DIR +cd $BUILD_DIR + +printf "\\n========================================================================\\n" +printf "======================= Starting EOSIO.CDT Build =======================\\n" + +$CMAKE -DCMAKE_INSTALL_PREFIX=$OPT_LOCATION/eosio.cdt "${REPO_ROOT}" +if [ $? -ne 0 ]; then exit -1; fi +make -j$CORES +if [ $? -ne 0 ]; then exit -1; fi + +TIME_END=$(( $(date -u +%s) - $TIME_BEGIN )) + +printf "\n${bldred}\t ___ ___ ___ ___\n" +printf "\t / /\\ / /\\ / /\\ ___ / /\\ \n" +printf "\t / /:/_ / /::\\ / /:/_ / /\\ / /::\\ \n" +printf "\t / /:/ /\\ / /:/\\:\\ / /:/ /\\ / /:/ / /:/\\:\\ \n" +printf "\t / /:/ /:/_ / /:/ \\:\\ / /:/ /::\\ /__/::\\ / /:/ \\:\\ \n" +printf "\t /__/:/ /:/ /\\ /__/:/ \\__\\:\\ /__/:/ /:/\\:\\ \\__\\/\\:\\__ /__/:/ \\__\\:\\ \n" +printf "\t \\ \\:\\/:/ /:/ \\ \\:\\ / /:/ \\ \\:\\/:/~/:/ \\ \\:\\/\\ \\ \\:\\ / /:/ \n" +printf "\t \\ \\::/ /:/ \\ \\:\\ /:/ \\ \\::/ /:/ \\__\\::/ \\ \\:\\ /:/ \n" +printf "\t \\ \\:\\/:/ \\ \\:\\/:/ \\__\\/ /:/ /__/:/ \\ \\:\\/:/ \n" +printf "\t \\ \\::/ \\ \\::/ /__/:/ \\__\\/ \\ \\::/ \n" +printf "\t \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n${txtrst}" + +printf "\\nEOSIO.CDT has been successfully built. %02d:%02d:%02d\\n\\n" $(($TIME_END/3600)) $(($TIME_END%3600/60)) $(($TIME_END%60)) +printf "${txtrst}==============================================================================================\\n" + +printf "For more information:\\n" +printf "EOSIO website: https://eos.io\\n" +printf "EOSIO Telegram channel @ https://t.me/EOSProject\\n" +printf "EOSIO resources: https://eos.io/resources/\\n" +printf "EOSIO Stack Exchange: https://eosio.stackexchange.com\\n" +printf "EOSIO wiki: https://github.com/EOSIO/eos/wiki\\n\\n\\n" diff --git a/scripts/eosiocdt_build_amazon.sh b/scripts/eosiocdt_build_amazon.sh new file mode 100644 index 0000000000..31fd0ab945 --- /dev/null +++ b/scripts/eosiocdt_build_amazon.sh @@ -0,0 +1,135 @@ +OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' | cut -d'.' -f1 ) + +MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 ) +CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) +CPU_CORE=$( nproc ) +MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) +export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) + +DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) +DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) +DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) +DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) +DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) + +DEP_ARRAY=( + sudo procps which gcc72 gcc72-c++ autoconf automake libtool make \ + bzip2 bzip2-devel openssl-devel gmp gmp-devel libstdc++72 python27 python27-devel python34 python34-devel \ + libedit-devel ncurses-devel swig wget file +) +COUNT=1 +DISPLAY="" +DEP="" + +printf "\\nOS name: %s\\n" "${OS_NAME}" +printf "OS Version: %s\\n" "${OS_VER}" +printf "CPU speed: %sMhz\\n" "${CPU_SPEED}" +printf "CPU cores: %s\\n" "${CPU_CORE}" +printf "Physical Memory: %sMgb\\n" "${MEM_MEG}" +printf "Disk space total: %sGb\\n" "${DISK_TOTAL}" +printf "Disk space available: %sG\\n" "${DISK_AVAIL}" + +if [ "${MEM_MEG}" -lt 7000 ]; then + printf "Your system must have 7 or more Gigabytes of physical memory installed.\\n" + printf "exiting now.\\n" + exit 1 +fi + +if [[ "${OS_NAME}" == "Amazon Linux AMI" && "${OS_VER}" -lt 2017 ]]; then + printf "You must be running Amazon Linux 2017.09 or higher to install EOSIO.\\n" + printf "exiting now.\\n" + exit 1 +fi + +if [ "${DISK_AVAIL}" -lt "${DISK_MIN}" ]; then + printf "You must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" + printf "exiting now.\\n" + exit 1 +fi + +printf "\\nChecking Yum installation.\\n" +if ! YUM=$( command -v yum 2>/dev/null ) +then + printf "\\nYum must be installed to compile EOS.IO.\\n" + printf "\\nExiting now.\\n" + exit 1 +fi +printf "Yum installation found at ${YUM}.\\n" + +printf "\\nDo you wish to update YUM repositories?\\n\\n" +select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\\n\\nUpdating...\\n\\n" + if ! sudo $YUM -y update; then + printf "\\nYUM update failed.\\n" + printf "\\nExiting now.\\n\\n" + exit 1; + else + printf "\\nYUM update complete.\\n" + fi + break;; + [Nn]* ) echo "Proceeding without update!" + break;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac +done + +printf "Checking RPM for installed dependencies...\\n" +for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do + pkg=$( rpm -qi "${DEP_ARRAY[$i]}" 2>/dev/null | grep Name ) + if [[ -z $pkg ]]; then + DEP=$DEP" ${DEP_ARRAY[$i]} " + DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" + printf "!! Package %s ${bldred} NOT ${txtrst} found !!\\n" "${DEP_ARRAY[$i]}" + (( COUNT++ )) + else + printf " - Package %s found.\\n" "${DEP_ARRAY[$i]}" + continue + fi +done +printf "\\n" +if [ "${COUNT}" -gt 1 ]; then + printf "The following dependencies are required to install EOSIO.\\n" + printf "${DISPLAY}\\n\\n" + printf "Do you wish to install these dependencies?\\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "Installing dependencies\\n\\n" + if ! sudo $YUM -y install ${DEP}; then + printf "!! YUM dependency installation failed !!\\n" + printf "Exiting now.\\n" + exit 1; + else + printf "YUM 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 " - No required YUM dependencies to install.\\n" +fi + + +printf "\\n" + + +printf "Checking CMAKE installation...\\n" +if [ -z $CMAKE ]; then + printf "Installing CMAKE...\\n" + curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ + && tar -xzf cmake-$CMAKE_VERSION.tar.gz \ + && cd cmake-$CMAKE_VERSION \ + && ./bootstrap --prefix=$HOME \ + && make -j"${JOBS}" \ + && make install \ + && cd .. \ + && rm -f cmake-$CMAKE_VERSION.tar.gz \ + || exit 1 + printf " - CMAKE successfully installed @ ${CMAKE}.\\n" +else + printf " - CMAKE found @ ${CMAKE}.\\n" +fi diff --git a/scripts/eosiocdt_build_centos.sh b/scripts/eosiocdt_build_centos.sh new file mode 100644 index 0000000000..0f2f70de53 --- /dev/null +++ b/scripts/eosiocdt_build_centos.sh @@ -0,0 +1,197 @@ +OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' \ +| cut -d'.' -f1 ) + +MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 ) +CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) +CPU_CORE=$( nproc ) +MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) +export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) + +DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) +DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) +DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) +DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) +DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) + +printf "\\nOS name: ${OS_NAME}\\n" +printf "OS Version: ${OS_VER}\\n" +printf "CPU speed: ${CPU_SPEED}Mhz\\n" +printf "CPU cores: ${CPU_CORE}\\n" +printf "Physical Memory: ${MEM_MEG}Mgb\\n" +printf "Disk install: ${DISK_INSTALL}\\n" +printf "Disk space total: ${DISK_TOTAL%.*}G\\n" +printf "Disk space available: ${DISK_AVAIL%.*}G\\n" +printf "Concurrent Jobs (make -j): ${JOBS}\\n" + +if [ "${MEM_MEG}" -lt 7000 ]; then + printf "\\nYour system must have 7 or more Gigabytes of physical memory installed.\\n" + printf "Exiting now.\\n\\n" + exit 1; +fi + +if [ "${OS_VER}" -lt 7 ]; then + printf "\\nYou must be running Centos 7 or higher to install EOSIO.\\n" + printf "Exiting now.\\n\\n" + exit 1; +fi + +if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then + printf "\\nYou must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" + printf "Exiting now.\\n\\n" + exit 1; +fi + +printf "\\n" + +printf "Checking Yum installation...\\n" +if ! YUM=$( command -v yum 2>/dev/null ); then + printf "!! Yum must be installed to compile EOS.IO !!\\n" + printf "Exiting now.\\n" + exit 1; +fi +printf " - Yum installation found at %s.\\n" "${YUM}" + +printf "\\nDo you wish to update YUM repositories?\\n\\n" +select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\\n\\nUpdating...\\n\\n" + if ! sudo $YUM -y update; then + printf "\\nYUM update failed.\\n" + printf "\\nExiting now.\\n\\n" + exit 1; + else + printf "\\nYUM update complete.\\n" + fi + break;; + [Nn]* ) + echo "Proceeding without update!" + break;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac +done + +printf "Checking installation of Centos Software Collections Repository...\\n" +SCL=$( rpm -qa | grep -E 'centos-release-scl-[0-9].*' ) +if [ -z "${SCL}" ]; then + printf " - Do you wish to install and enable this repository?\\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "Installing SCL...\\n" + if ! sudo $YUM -y --enablerepo=extras install centos-release-scl; then + printf "!! Centos Software Collections Repository installation failed !!\\n" + printf "Exiting now.\\n\\n" + exit 1; + else + printf "Centos Software Collections Repository installed successfully.\\n" + fi + break;; + [Nn]* ) echo "User aborting installation of required Centos Software Collections Repository, Exiting now."; exit;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac + done +else + printf " - ${SCL} found.\\n" +fi + +printf "Checking installation of devtoolset-7...\\n" +DEVTOOLSET=$( rpm -qa | grep -E 'devtoolset-7-[0-9].*' ) +if [ -z "${DEVTOOLSET}" ]; then + printf "Do you wish to install devtoolset-7?\\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "Installing devtoolset-7...\\n" + if ! sudo $YUM install -y devtoolset-7 2>/dev/null; then + printf "!! Centos devtoolset-7 installation failed !!\\n" + printf "Exiting now.\\n" + exit 1; + else + printf "Centos devtoolset installed successfully.\\n" + fi + break;; + [Nn]* ) echo "User aborting installation of devtoolset-7. Exiting now."; exit;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac + done +else + printf " - ${DEVTOOLSET} found.\\n" +fi +printf "Enabling Centos devtoolset-7...\\n" +if ! source "/opt/rh/devtoolset-7/enable" 2>/dev/null; then + printf "!! Unable to enable Centos devtoolset-7 at this time !!\\n" + printf "Exiting now.\\n\\n" + exit 1; +fi +printf "Centos devtoolset-7 successfully enabled.\\n" + +printf "\\n" + +DEP_ARRAY=( + git autoconf automake libtool make bzip2 \ + bzip2-devel openssl-devel gmp-devel \ + ocaml libicu-devel python python-devel python33 \ + gettext-devel file sudo +) +COUNT=1 +DISPLAY="" +DEP="" +printf "Checking RPM for installed dependencies...\\n" +for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do + pkg=$( rpm -qi "${DEP_ARRAY[$i]}" 2>/dev/null | grep Name ) + if [[ -z $pkg ]]; then + DEP=$DEP" ${DEP_ARRAY[$i]} " + DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" + printf "!! Package %s ${bldred} NOT ${txtrst} found !!\\n" "${DEP_ARRAY[$i]}" + (( COUNT++ )) + else + printf " - Package %s found.\\n" "${DEP_ARRAY[$i]}" + continue + fi +done +printf "\\n" +if [ "${COUNT}" -gt 1 ]; then + printf "The following dependencies are required to install EOSIO.\\n" + printf "${DISPLAY}\\n\\n" + printf "Do you wish to install these dependencies?\\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "Installing dependencies\\n\\n" + if ! sudo $YUM -y install ${DEP}; then + printf "!! YUM dependency installation failed !!\\n" + printf "Exiting now.\\n" + exit 1; + else + printf "YUM 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 " - No required YUM dependencies to install.\\n" +fi + + +printf "\\n" + + +printf "Checking CMAKE installation...\\n" +if [ -z $CMAKE ]; then + printf "Installing CMAKE...\\n" + curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ + && tar -xzf cmake-$CMAKE_VERSION.tar.gz \ + && cd cmake-$CMAKE_VERSION \ + && ./bootstrap --prefix=$HOME \ + && make -j"${JOBS}" \ + && make install \ + && cd .. \ + && rm -f cmake-$CMAKE_VERSION.tar.gz \ + || exit 1 + printf " - CMAKE successfully installed @ ${CMAKE}.\\n" +else + printf " - CMAKE found @ ${CMAKE}.\\n" +fi \ No newline at end of file diff --git a/scripts/eosiocdt_build_darwin.sh b/scripts/eosiocdt_build_darwin.sh new file mode 100644 index 0000000000..30bbe2077f --- /dev/null +++ b/scripts/eosiocdt_build_darwin.sh @@ -0,0 +1,158 @@ +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) / 10^8) / 10") +CPU_CORE=$( sysctl -in machdep.cpu.core_count ) +export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) + +DISK_INSTALL=$(df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 || cut -d' ' -f1) +blksize=$(df . | head -1 | awk '{print $2}' | cut -d- -f1) +gbfactor=$(( 1073741824 / blksize )) +total_blks=$(df . | tail -1 | awk '{print $2}') +avail_blks=$(df . | tail -1 | awk '{print $4}') +DISK_TOTAL=$((total_blks / gbfactor )) +DISK_AVAIL=$((avail_blks / gbfactor )) + +export HOMEBREW_NO_AUTO_UPDATE=1 + +COUNT=1 +DISPLAY="" +DEPS="" + +printf "\\nOS name: ${OS_NAME}\\n" +printf "OS Version: ${OS_VER}\\n" +printf "CPU speed: ${CPU_SPEED}Mhz\\n" +printf "CPU cores: %s\\n" "${CPU_CORE}" +printf "Physical Memory: ${MEM_GIG} Gbytes\\n" +printf "Disk install: ${DISK_INSTALL}\\n" +printf "Disk space total: ${DISK_TOTAL}G\\n" +printf "Disk space available: ${DISK_AVAIL}G\\n" + +if [ "${MEM_GIG}" -lt 7 ]; then + echo "Your system must have 7 or more Gigabytes of physical memory installed." + echo "Exiting now." + exit 1 +fi + +if [ "${OS_MIN}" -lt 12 ]; then + 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 "$DISK_MIN" ]; then + echo "You must have at least ${DISK_MIN}GB of available storage to install EOSIO." + echo "Exiting now." + exit 1 +fi + +printf "Checking xcode-select installation\\n" +if ! XCODESELECT=$( command -v xcode-select) +then + printf "\\nXCode must be installed in order to proceed.\\n\\n" + printf "Exiting now.\\n" + exit 1 +fi +printf "xcode-select installation found @ ${XCODESELECT}\\n" + +printf "Checking Ruby installation.\\n" +if ! RUBY=$( command -v ruby) +then + printf "\\nRuby must be installed in order to proceed.\\n\\n" + printf "Exiting now.\\n" + exit 1 +fi +printf "Ruby installation found @ ${RUBY}\\n" + +printf "Checking Home Brew installation...\\n" +if ! BREW=$( command -v brew ) +then + printf "Homebrew must be installed to compile EOS.IO!\\n" + if [ $1 == 0 ]; then read -p "Do you wish to install HomeBrew? (y/n)? " answer; fi + case ${answer} in + 1 | [Yy]* ) + "${XCODESELECT}" --install 2>/dev/null; + if ! "${RUBY}" -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; then + echo " - Unable to install homebrew at this time." + exit 1; + else + BREW=$( command -v brew ) + fi + ;; + [Nn]* ) echo "User aborted homebrew installation. Exiting now."; exit 1;; + * ) echo "Please type 'y' for yes or 'n' for no.";; + esac + +fi +printf " - Home Brew installation found @ ${BREW}\\n" + +printf "\\nChecking dependencies...\\n" +var_ifs="${IFS}" +IFS="," +while read -r name tester testee brewname uri; do + if [ "${tester}" "${testee}" ]; then + printf " - %s found\\n" "${name}" + continue + fi + # resolve conflict with homebrew glibtool and apple/gnu installs of libtool + if [ "${testee}" == "/usr/local/bin/glibtool" ]; then + if [ "${tester}" "/usr/local/bin/libtool" ]; then + printf " - %s found\\n" "${name}" + continue + fi + fi + DEPS=$DEPS"${brewname}," + DISPLAY="${DISPLAY}${COUNT}. ${name}\\n" + printf " - %s ${bldred}NOT${txtrst} found.\\n" "${name}" + (( COUNT++ )) +done < "${REPO_ROOT}/scripts/eosiocdt_build_darwin_deps" +IFS="${var_ifs}" + +if [ ! -d /usr/local/Frameworks ]; then + printf "\\n${bldred}/usr/local/Frameworks is necessary to brew install python@3. Run the following commands as sudo and try again:${txtrst}\\n" + printf "sudo mkdir /usr/local/Frameworks && sudo chown $(whoami):admin /usr/local/Frameworks\\n\\n" + exit 1; +fi + +if [ $COUNT -gt 1 ]; then + printf "\\nThe following dependencies are required to install EOSIO:\\n" + printf "${DISPLAY}\\n\\n" + if [ $1 == 0 ]; then read -p "Do you wish to install these packages? (y/n) " answer; fi + case ${answer} in + 1 | [Yy]* ) + "${XCODESELECT}" --install 2>/dev/null; + if [ $1 == 0 ]; then read -p "Do you wish to update homebrew packages first? (y/n) " answer; fi + case ${answer} in + 1 | [Yy]* ) + if ! brew update; then + printf " - Brew update failed.\\n" + exit 1; + else + printf " - Brew update complete.\\n" + fi + ;; + [Nn]* ) echo "Proceeding without update!";; + * ) echo "Please type 'y' for yes or 'n' for no."; exit;; + esac + brew tap eosio/eosio + printf "\\nInstalling Dependencies...\\n" + # DON'T INSTALL llvm@4 WITH --force! + OIFS="$IFS" + IFS=$',' + for DEP in $DEPS; do + # Eval to support string/arguments with $DEP + if ! eval $BREW install $DEP; then + printf " - Homebrew exited with the above errors!\\n" + exit 1; + fi + done + IFS="$OIFS" + ;; + [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; + * ) echo "Please type 'y' for yes or 'n' for no."; exit;; + esac +else + printf "\\n - No required Home Brew dependencies to install.\\n" +fi \ No newline at end of file diff --git a/scripts/eosiocdt_build_darwin_deps b/scripts/eosiocdt_build_darwin_deps new file mode 100644 index 0000000000..9aadb88cce --- /dev/null +++ b/scripts/eosiocdt_build_darwin_deps @@ -0,0 +1,5 @@ +automake,-x,/usr/local/bin/automake,automake,http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz +Libtool,-x,/usr/local/bin/glibtool,libtool,http://gnu.askapache.com/libtool/libtool-2.4.6.tar.gz +OpenSSL,-f,/usr/local/opt/openssl/lib/libssl.a,openssl,https://www.openssl.org/source/openssl-1.0.2n.tar.gz +GMP,-f,/usr/local/opt/gmp/include/gmpxx.h,gmp,https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.bz2 +cmake,-f,/usr/local/bin/cmake,cmake,https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4.tar.gz diff --git a/scripts/eosiocdt_build_fedora.sh b/scripts/eosiocdt_build_fedora.sh new file mode 100644 index 0000000000..e22a57c025 --- /dev/null +++ b/scripts/eosiocdt_build_fedora.sh @@ -0,0 +1,137 @@ +OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' ) + +MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 ) +CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) +CPU_CORE=$( nproc ) +MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) +export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) + +DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) +DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) +DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) +DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) +DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) + +DEP_ARRAY=( + git sudo procps-ng which gcc gcc-c++ autoconf automake libtool make \ + bzip2-devel wget bzip2 compat-openssl10 \ + openssl-devel gmp-devel libstdc++-devel python2 python2-devel python3 python3-devel \ + libedit ncurses-devel swig +) +COUNT=1 +DISPLAY="" +DEP="" + +printf "\\nOS name: ${OS_NAME}\\n" +printf "OS Version: ${OS_VER}\\n" +printf "CPU speed: ${CPU_SPEED}Mhz\\n" +printf "CPU cores: %s\\n" "${CPU_CORE}" +printf "Physical Memory: ${MEM_MEG} Mgb\\n" +printf "Disk install: ${DISK_INSTALL}\\n" +printf "Disk space total: ${DISK_TOTAL%.*}G\\n" +printf "Disk space available: ${DISK_AVAIL%.*}G\\n" + +if [ "${MEM_MEG}" -lt 7000 ]; then + printf "Your system must have 7 or more Gigabytes of physical memory installed.\\n" + printf "Exiting now.\\n" + exit 1; +fi + +if [ "${OS_VER}" -lt 25 ]; then + printf "You must be running Fedora 25 or higher to install EOSIO.\\n" + printf "Exiting now.\\n" + exit 1; +fi + +if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then + printf "You must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" + printf "Exiting now.\\n" + exit 1; +fi + +printf "\\nChecking Yum installation...\\n" +if ! YUM=$( command -v yum 2>/dev/null ); then + printf "!! Yum must be installed to compile EOS.IO !!\\n" + printf "Exiting now.\\n" + exit 1; +fi +printf " - Yum installation found at %s.\\n" "${YUM}" + +printf "\\nDo you wish to update YUM repositories?\\n\\n" +select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\\n\\nUpdating...\\n\\n" + if ! sudo $YUM -y update; then + printf "\\nYUM update failed.\\n" + printf "\\nExiting now.\\n\\n" + exit 1; + else + printf "\\nYUM update complete.\\n" + fi + break;; + [Nn]* ) echo "Proceeding without update!" + break;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac +done + +printf "\\n" + +printf "Checking RPM for installed dependencies...\\n" +for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do + pkg=$( rpm -qi "${DEP_ARRAY[$i]}" 2>/dev/null | grep Name ) + if [[ -z $pkg ]]; then + DEP=$DEP" ${DEP_ARRAY[$i]} " + DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" + printf "!! Package %s ${bldred} NOT ${txtrst} found !!\\n" "${DEP_ARRAY[$i]}" + (( COUNT++ )) + else + printf " - Package %s found.\\n" "${DEP_ARRAY[$i]}" + continue + fi +done +if [ "${COUNT}" -gt 1 ]; then + printf "The following dependencies are required to install EOSIO.\\n" + printf "${DISPLAY}\\n" + printf "Do you wish to install these dependencies?\\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "Installing dependencies\\n\\n" + if ! sudo $YUM -y install ${DEP}; then + printf "!! YUM dependency installation failed !!\\n" + printf "Exiting now.\\n" + exit 1; + else + printf "YUM 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 " - No required YUM dependencies to install.\\n" +fi + + +printf "\\n" + + +printf "Checking CMAKE installation...\\n" +if [ -z $CMAKE ]; then + printf "Installing CMAKE...\\n" + curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ + && tar xf cmake-$CMAKE_VERSION.tar.gz \ + && cd cmake-$CMAKE_VERSION \ + && ./bootstrap --prefix=$HOME \ + && make -j"${JOBS}" \ + && make install \ + && cd .. \ + && rm -f cmake-$CMAKE_VERSION.tar.gz \ + || exit 1 + printf " - CMAKE successfully installed @ ${CMAKE}.\\n" +else + printf " - CMAKE found @ ${CMAKE}.\\n" +fi diff --git a/scripts/eosiocdt_build_ubuntu.sh b/scripts/eosiocdt_build_ubuntu.sh new file mode 100644 index 0000000000..aadf8ef04c --- /dev/null +++ b/scripts/eosiocdt_build_ubuntu.sh @@ -0,0 +1,161 @@ +OS_VER=$( grep VERSION_ID /etc/os-release | 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 | sed -n 2p | tr -s ' ' | cut -d\ -f2 || cut -d' ' -f2 ) +CPU_SPEED=$( lscpu | grep -m1 "MHz" | tr -s ' ' | cut -d\ -f3 || cut -d' ' -f3 | cut -d'.' -f1 ) +CPU_CORE=$( nproc ) +MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) +export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) + +DISK_INSTALL=$(df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 || cut -d' ' -f1) +DISK_TOTAL_KB=$(df . | tail -1 | awk '{print $2}') +DISK_AVAIL_KB=$(df . | tail -1 | awk '{print $4}') +DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) +DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) + +printf "\\nOS name: ${OS_NAME}\\n" +printf "OS Version: ${OS_VER}\\n" +printf "CPU speed: ${CPU_SPEED}Mhz\\n" +printf "CPU cores: %s\\n" "${CPU_CORE}" +printf "Physical Memory: ${MEM_MEG} Mgb\\n" +printf "Disk install: ${DISK_INSTALL}\\n" +printf "Disk space total: ${DISK_TOTAL%.*}G\\n" +printf "Disk space available: ${DISK_AVAIL%.*}G\\n" + +if [ "${MEM_MEG}" -lt 7000 ]; then + printf "Your system must have 7 or more Gigabytes of physical memory installed.\\n" + printf "Exiting now.\\n" + exit 1 +fi + +case "${OS_NAME}" in + "Linux Mint") + if [ "${OS_MAJ}" -lt 18 ]; then + printf "You must be running Linux Mint 18.x or higher to install EOSIO.\\n" + printf "Exiting now.\\n" + exit 1 + fi + ;; + "Ubuntu") + if [ "${OS_MAJ}" -lt 16 ]; then + printf "You must be running Ubuntu 16.04.x or higher to install EOSIO.\\n" + printf "Exiting now.\\n" + exit 1 + fi + # UBUNTU 18 doesn't have MONGODB 3.6.3 + if [ $OS_MAJ -gt 16 ]; then + export MONGODB_VERSION=4.1.1 + fi + # We have to re-set this with the new version + export MONGODB_ROOT=${OPT_LOCATION}/mongodb-${MONGODB_VERSION} + ;; + "Debian") + if [ $OS_MAJ -lt 10 ]; then + printf "You must be running Debian 10 to install EOSIO, and resolve missing dependencies from unstable (sid).\n" + printf "Exiting now.\n" + exit 1 + fi + ;; +esac + +if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then + printf "You must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" + printf "Exiting now.\\n" + exit 1 +fi + +# llvm-4.0 is installed into /usr/lib/llvm-4.0 +DEP_ARRAY=( + git llvm-4.0 clang-4.0 libclang-4.0-dev make automake libbz2-dev libssl-dev \ + libgmp3-dev autotools-dev build-essential libicu-dev python2.7 python2.7-dev python3 python3-dev \ + autoconf libtool curl zlib1g-dev sudo ruby +) +COUNT=1 +DISPLAY="" +DEP="" + +if [[ "${ENABLE_CODE_COVERAGE}" == true ]]; then + DEP_ARRAY+=(lcov) +fi + +printf "Do you wish to update repositories with apt-get update?\\n\\n" +select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\\n\\nUpdating...\\n\\n" + if ! sudo apt-get update; then + printf "\\nAPT update failed.\\n" + printf "\\nExiting now.\\n\\n" + exit 1; + else + printf "\\nAPT update complete.\\n" + fi + break;; + [Nn]* ) echo "Proceeding without update!" + break;; + * ) echo "Please type 1 for yes or 2 for no.";; + esac +done + +printf "\\nChecking 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" + printf "Package %s ${bldred} NOT ${txtrst} found.\\n" "${DEP_ARRAY[$i]}" + (( COUNT++ )) + else + printf "Package %s found.\\n" "${DEP_ARRAY[$i]}" + continue + fi +done + +if [ "${COUNT}" -gt 1 ]; then + printf "\\nThe following dependencies are required to install EOSIO.\\n" + printf "\\n${DISPLAY}\\n\\n" + printf "Do you wish to install these packages?\\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + printf "\\n\\nInstalling dependencies\\n\\n" + if ! sudo apt-get -y install ${DEP} + then + printf "\\nDPKG dependency failed.\\n" + printf "\\nExiting now.\\n" + exit 1 + else + printf "\\nDPKG 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 "\\nNo required dpkg dependencies to install." +fi + + +printf "\\n" + + +printf "Checking CMAKE installation...\\n" +if [ ! -d $SRC_LOCATION/cmake-$CMAKE_VERSION ]; then + printf "Installing CMAKE...\\n" + curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ + && tar xf cmake-$CMAKE_VERSION.tar.gz \ + && cd cmake-$CMAKE_VERSION \ + && ./bootstrap --prefix=$HOME \ + && make -j"${JOBS}" \ + && make install \ + && cd .. \ + && rm -f cmake-$CMAKE_VERSION.tar.gz \ + || exit 1 + printf " - CMAKE successfully installed @ ${CMAKE}.\\n" +else + printf " - CMAKE found @ ${CMAKE}.\\n" +fi diff --git a/scripts/eosiocdt_install.sh b/scripts/eosiocdt_install.sh new file mode 100755 index 0000000000..959cf20841 --- /dev/null +++ b/scripts/eosiocdt_install.sh @@ -0,0 +1,85 @@ +#!/bin/bash +########################################################################## +# This is the EOSIO automated install script for Linux and Mac OS. +# This file was downloaded from https://github.com/EOSIO/eos +# +# Copyright (c) 2017, Respective Authors all rights reserved. +# +# After June 1, 2018 this software is available under the following terms: +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# https://github.com/EOSIO/eos/blob/master/LICENSE.txt +########################################################################## + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +REPO_ROOT="${SCRIPT_DIR}/.." +BUILD_DIR="${REPO_ROOT}/build" + +OPT_LOCATION=$HOME/opt +BIN_LOCATION=$HOME/bin +LIB_LOCATION=$HOME/lib + +CMAKE_BUILD_TYPE=Release +TIME_BEGIN=$( date -u +%s ) +VERSION=2.0 + +txtbld=$(tput bold) +bldred=${txtbld}$(tput setaf 1) +txtrst=$(tput sgr0) + +if [ ! -d "${BUILD_DIR}" ]; then + printf "\\n\Error, build.sh has not run successfully. Please run ./build.sh first!\\n\\n" + exit -1 +fi + +if ! pushd "${BUILD_DIR}" &> /dev/null; then + printf "Unable to enter build directory ${BUILD_DIR}.\\n Exiting now.\\n" + exit 1; +fi + +if ! make install; then + printf "\\nMAKE installing EOSIO has exited with the above error.\\n\\n" + exit -1 +fi +popd &> /dev/null + +printf "\n${bldred} ___ ___ ___ ___\n" +printf " / /\\ / /\\ / /\\ ___ / /\\ \n" +printf " / /:/_ / /::\\ / /:/_ / /\\ / /::\\ \n" +printf " / /:/ /\\ / /:/\\:\\ / /:/ /\\ / /:/ / /:/\\:\\ \n" +printf " / /:/ /:/_ / /:/ \\:\\ / /:/ /::\\ /__/::\\ / /:/ \\:\\ \n" +printf " /__/:/ /:/ /\\ /__/:/ \\__\\:\\ /__/:/ /:/\\:\\ \\__\\/\\:\\__ /__/:/ \\__\\:\\ \n" +printf " \\ \\:\\/:/ /:/ \\ \\:\\ / /:/ \\ \\:\\/:/~/:/ \\ \\:\\/\\ \\ \\:\\ / /:/ \n" +printf " \\ \\::/ /:/ \\ \\:\\ /:/ \\ \\::/ /:/ \\__\\::/ \\ \\:\\ /:/ \n" +printf " \\ \\:\\/:/ \\ \\:\\/:/ \\__\\/ /:/ /__/:/ \\ \\:\\/:/ \n" +printf " \\ \\::/ \\ \\::/ /__/:/ \\__\\/ \\ \\::/ \n" +printf " \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n\n${txtrst}" + +printf "==============================================================================================\\n" +printf "EOSIO has been installed into ${OPT_LOCATION}/eosio.cdt/bin!\\n" +printf "If you need to, you can fully uninstall using eosiocdt_uninstall.sh.\\n" +printf "==============================================================================================\\n\\n" + +printf "For more information:\\n" +printf "EOSIO website: https://eos.io\\n" +printf "EOSIO resources: https://eos.io/resources/\\n" +printf "EOSIO Stack Exchange: https://eosio.stackexchange.com\\n" diff --git a/scripts/eosiocdt_uninstall.sh b/scripts/eosiocdt_uninstall.sh new file mode 100755 index 0000000000..f2ec7d71f6 --- /dev/null +++ b/scripts/eosiocdt_uninstall.sh @@ -0,0 +1,100 @@ +#! /bin/bash + +OPT_LOCATION=$HOME/opt + +binaries=( + eosio-ranlib + eosio-ar + eosio-objdump + eosio-readelf + eosio-abigen + eosio-wasm2wast + eosio-wast2wasm + eosio-pp + eosio-cc + eosio-cpp + eosio-ld + eosio-abidiff + eosio-init + llvm-readelf + llvm-objdump + llvm-ar + llvm-ranlib +) + +if [ -d "/usr/local/eosio.cdt" ]; then + printf "Do you wish to remove this install? (requires sudo)\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + if [ "$(id -u)" -ne 0 ]; then + printf "\nThis requires sudo, please run ./uninstall.sh with sudo\n\n" + exit -1 + fi + pushd /usr/local &> /dev/null + rm -rf eosio.cdt + pushd bin &> /dev/null + for binary in ${binaries[@]}; do + rm ${binary} + done + popd &> /dev/null + pushd lib/cmake &> /dev/null + rm -rf eosio.cdt + popd &> /dev/null + break;; + [Nn]* ) + printf "Aborting uninstall\n\n" + exit -1;; + esac + done +fi + +if [ -d "/usr/local/eosio.wasmsdk" ]; then + printf "Do you wish to remove this install? (requires sudo)\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + if [ "$(id -u)" -ne 0 ]; then + printf "\nThis requires sudo, please run ./uninstall.sh with sudo\n\n" + exit -1 + fi + pushd /usr/local &> /dev/null + rm -rf eosio.wasmsdk + pushd bin &> /dev/null + for binary in ${binaries[@]}; do + rm ${binary} + done + popd &> /dev/null + break;; + + [Nn]* ) + printf "Aborting uninstall\n\n" + exit -1;; + esac + done +fi + +if [ -d $OPT_LOCATION/eosio.cdt ] || [[ $1 == "force-new" ]]; then + printf "Do you wish to remove this install?\n" + select yn in "Yes" "No"; do + case $yn in + [Yy]* ) + pushd $HOME &> /dev/null + pushd opt &> /dev/null + rm -rf eosio.cdt + popd &> /dev/null + pushd bin &> /dev/null + for binary in ${binaries[@]}; do + rm ${binary} + done + popd &> /dev/null + pushd lib/cmake &> /dev/null + rm -rf eosio.cdt + popd &> /dev/null + break;; + [Nn]* ) + printf "\tAborting uninstall\n\n" + exit -1;; + esac + done +fi \ No newline at end of file diff --git a/scripts/generate_bottle.sh b/scripts/generate_bottle.sh index f94fe1711a..d93dc23190 100644 --- a/scripts/generate_bottle.sh +++ b/scripts/generate_bottle.sh @@ -14,7 +14,7 @@ else MAC_VERSION="high_sierra" fi -NAME="${PROJECT}-${VERSION}.${MAC_VERSION}.bottle.tar.gz" +NAME="${PROJECT}-${VERSION}.${MAC_VERSION}.bottle" mkdir -p ${PROJECT}/${VERSION}/opt/eosio_cdt/lib/cmake @@ -28,9 +28,9 @@ export SPREFIX export SUBPREFIX export SSUBPREFIX -bash generate_tarball.sh ${NAME} +. ./generate_tarball.sh ${NAME} -hash=`openssl dgst -sha256 ${NAME} | awk 'NF>1{print $NF}'` +hash=`openssl dgst -sha256 ${NAME}.tar.gz | awk 'NF>1{print $NF}'` echo "class EosioCdt < Formula @@ -64,4 +64,4 @@ echo "class EosioCdt < Formula end __END__" &> eosio.cdt.rb -rm -r ${PROJECT} +rm -r ${PROJECT} || exit 1 diff --git a/scripts/generate_deb.sh b/scripts/generate_deb.sh index 6892ed73c9..b0460aa17a 100644 --- a/scripts/generate_deb.sh +++ b/scripts/generate_deb.sh @@ -22,18 +22,18 @@ Architecture: amd64 Homepage: ${URL} Maintainer: ${EMAIL} Description: ${DESC}" &> ${PROJECT}/DEBIAN/control +cat ${PROJECT}/DEBIAN/control export PREFIX export SUBPREFIX export SPREFIX export SSUBPREFIX -bash generate_tarball.sh ${NAME}.tar.gz - -tar -xvzf ${NAME}.tar.gz -C ${PROJECT} -dpkg-deb --build ${PROJECT} -BUILDSTATUS=$? -mv ${PROJECT}.deb ${NAME}.deb -rm -r ${PROJECT} +. ./generate_tarball.sh ${NAME} +echo "Unpacking tarball: ${NAME}.tar.gz..." +tar -xzvf ${NAME}.tar.gz -C ${PROJECT} || exit 1 +dpkg-deb --build ${PROJECT} || exit 1 +mv ${PROJECT}.deb ${NAME}.deb || exit 1 +rm -r ${PROJECT} || exit 1 exit $BUILDSTATUS diff --git a/scripts/generate_package.sh.in b/scripts/generate_package.sh.in index b462833073..4874a1b424 100644 --- a/scripts/generate_package.sh.in +++ b/scripts/generate_package.sh.in @@ -6,7 +6,8 @@ VERSION_NO_SUFFIX="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@" VERSION_SUFFIX="@VERSION_SUFFIX@" VERSION="@VERSION_FULL@" -BUILD_DIR="@CMAKE_BINARY_DIR@" +# Using CMAKE_BINARY_DIR uses an absolute path and will break cross-vm building/download/make functionality +BUILD_DIR="../../build" VENDOR="@VENDOR@" PROJECT="@PROJECT_NAME@" @@ -24,21 +25,17 @@ export DESC export URL export EMAIL -mkdir tmp +mkdir -p tmp if [[ ${VARIANT} == "brew" ]]; then - bash generate_bottle.sh + . ./generate_bottle.sh elif [[ ${VARIANT} == "deb" ]]; then - bash generate_deb.sh + . ./generate_deb.sh elif [[ ${VARIANT} == "rpm" ]]; then - bash generate_rpm.sh + . ./generate_rpm.sh else echo "Error, unknown package type. Use either ['brew', 'deb', 'rpm']." exit -1 fi -BUILDSTATUS=$? - -rm -r tmp - -exit $BUILDSTATUS +rm -r tmp || exit 1 diff --git a/scripts/generate_rpm.sh b/scripts/generate_rpm.sh index 077109a11b..5ed33751ca 100644 --- a/scripts/generate_rpm.sh +++ b/scripts/generate_rpm.sh @@ -18,10 +18,10 @@ export SUBPREFIX export SPREFIX export SSUBPREFIX -bash generate_tarball.sh ${NAME}.tar.gz +. ./generate_tarball.sh ${NAME} RPMBUILD=`realpath ~/rpmbuild/BUILDROOT/${NAME}.x86_64` -mkdir -p ${RPMBUILD} +mkdir -p ${RPMBUILD} FILES=$(tar -xvzf ${NAME}.tar.gz -C ${RPMBUILD}) PFILES="" for f in ${FILES[@]}; do @@ -31,7 +31,7 @@ for f in ${FILES[@]}; do done echo -e ${PFILES} &> ~/rpmbuild/BUILD/filenames.txt -mkdir -p ${PROJECT} +mkdir -p ${PROJECT} echo -e "Name: ${PROJECT} Version: ${VERSION_NO_SUFFIX} License: MIT @@ -44,10 +44,8 @@ Release: ${RELEASE} %description ${DESC} %files -f filenames.txt" &> ${PROJECT}.spec +cat ${PROJECT}.spec -rpmbuild -bb ${PROJECT}.spec -BUILDSTATUS=$? -mv ~/rpmbuild/RPMS/x86_64 ./ -rm -r ${PROJECT} ~/rpmbuild/BUILD/filenames.txt ${PROJECT}.spec - -exit $BUILDSTATUS +rpmbuild -bb ${PROJECT}.spec || exit 1 +mv ~/rpmbuild/RPMS/x86_64/*.rpm ./ || exit 1 +rm -r ${PROJECT} ~/rpmbuild/BUILD/filenames.txt ${PROJECT}.spec || exit 1 diff --git a/scripts/generate_tarball.sh b/scripts/generate_tarball.sh index 2c414b541d..cd4f25057b 100644 --- a/scripts/generate_tarball.sh +++ b/scripts/generate_tarball.sh @@ -14,47 +14,47 @@ mkdir -p ${CDT_PREFIX}/licenses #echo "${PREFIX} ** ${SUBPREFIX} ** ${CDT_PREFIX}" # install binaries -cp -R ${BUILD_DIR}/bin/* ${CDT_PREFIX}/bin -cp -R ${BUILD_DIR}/licenses/* ${CDT_PREFIX}/licenses +cp -R ${BUILD_DIR}/bin/* ${CDT_PREFIX}/bin || exit 1 +cp -R ${BUILD_DIR}/licenses/* ${CDT_PREFIX}/licenses || exit 1 # install cmake modules -sed "s/_PREFIX_/\/${SPREFIX}/g" ${BUILD_DIR}/modules/EosioCDTMacrosPackage.cmake &> ${CDT_PREFIX}/lib/cmake/${PROJECT}/EosioCDTMacros.cmake -sed "s/_PREFIX_/\/${SPREFIX}/g" ${BUILD_DIR}/modules/EosioWasmToolchainPackage.cmake &> ${CDT_PREFIX}/lib/cmake/${PROJECT}/EosioWasmToolchain.cmake -sed "s/_PREFIX_/\/${SPREFIX}\/${SSUBPREFIX}/g" ${BUILD_DIR}/modules/${PROJECT}-config.cmake.package &> ${CDT_PREFIX}/lib/cmake/${PROJECT}/${PROJECT}-config.cmake +sed "s/_PREFIX_/\/${SPREFIX}/g" ${BUILD_DIR}/modules/EosioCDTMacrosPackage.cmake &> ${CDT_PREFIX}/lib/cmake/${PROJECT}/EosioCDTMacros.cmake || exit 1 +sed "s/_PREFIX_/\/${SPREFIX}/g" ${BUILD_DIR}/modules/EosioWasmToolchainPackage.cmake &> ${CDT_PREFIX}/lib/cmake/${PROJECT}/EosioWasmToolchain.cmake || exit 1 +sed "s/_PREFIX_/\/${SPREFIX}\/${SSUBPREFIX}/g" ${BUILD_DIR}/modules/${PROJECT}-config.cmake.package &> ${CDT_PREFIX}/lib/cmake/${PROJECT}/${PROJECT}-config.cmake || exit 1 # install scripts -cp -R ${BUILD_DIR}/scripts/* ${CDT_PREFIX}/scripts +cp -R ${BUILD_DIR}/scripts/* ${CDT_PREFIX}/scripts || exit 1 # install misc. -cp ${BUILD_DIR}/eosio.imports ${CDT_PREFIX} +cp ${BUILD_DIR}/eosio.imports ${CDT_PREFIX} || exit 1 # install wasm includes -cp -R ${BUILD_DIR}/include/* ${CDT_PREFIX}/include +cp -R ${BUILD_DIR}/include/* ${CDT_PREFIX}/include || exit 1 # install wasm libs -cp ${BUILD_DIR}/lib/*.a ${CDT_PREFIX}/lib +cp ${BUILD_DIR}/lib/*.a ${CDT_PREFIX}/lib || exit 1 # make symlinks pushd ${PREFIX}/lib/cmake/${PROJECT} &> /dev/null -ln -sf ../../../${SUBPREFIX}/lib/cmake/${PROJECT}/${PROJECT}-config.cmake ${PROJECT}-config.cmake -ln -sf ../../../${SUBPREFIX}/lib/cmake/${PROJECT}/EosioWasmToolchain.cmake EosioWasmToolchain.cmake -ln -sf ../../../${SUBPREFIX}/lib/cmake/${PROJECT}/EosioCDTMacros.cmake EosioCDTMacros.cmake +ln -sf ../../../${SUBPREFIX}/lib/cmake/${PROJECT}/${PROJECT}-config.cmake ${PROJECT}-config.cmake || exit 1 +ln -sf ../../../${SUBPREFIX}/lib/cmake/${PROJECT}/EosioWasmToolchain.cmake EosioWasmToolchain.cmake || exit 1 +ln -sf ../../../${SUBPREFIX}/lib/cmake/${PROJECT}/EosioCDTMacros.cmake EosioCDTMacros.cmake || exit 1 popd &> /dev/null create_symlink() { - pushd ${PREFIX}/bin &> /dev/null - ln -sf ../${SUBPREFIX}/bin/$1 $2 - popd &> /dev/null + ln -sf ../${SUBPREFIX}/bin/$1 ${PREFIX}/bin/$2 || exit 1 } -create_symlink "eosio-cc eosio-cc" -create_symlink "eosio-cpp eosio-cpp" -create_symlink "eosio-ld eosio-ld" -create_symlink "eosio-pp eosio-pp" -create_symlink "eosio-init eosio-init" -create_symlink "eosio-abigen eosio-abigen" -create_symlink "eosio-wasm2wast eosio-wasm2wast" -create_symlink "eosio-wast2wasm eosio-wast2wasm" - -tar -cvzf $NAME ./${PREFIX}/* -rm -r ${PREFIX} +create_symlink eosio-cc eosio-cc +create_symlink eosio-cpp eosio-cpp +create_symlink eosio-ld eosio-ld +create_symlink eosio-pp eosio-pp +create_symlink eosio-init eosio-init +create_symlink eosio-abigen eosio-abigen +create_symlink eosio-wasm2wast eosio-wasm2wast +create_symlink eosio-wast2wasm eosio-wast2wasm +create_symlink eosio-ar eosio-ar + +echo "Generating Tarball $NAME.tar.gz..." +tar -cvzf $NAME.tar.gz ./${PREFIX}/* || exit 1 +rm -r ${PREFIX} || exit 1 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ab8a503bee..1dd02ff0e7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,8 @@ add_test( print_tests ${CMAKE_BINARY_DIR}/tests/unit/print_tests ) set_property(TEST print_tests PROPERTY LABELS unit_tests) add_test( serialize_tests ${CMAKE_BINARY_DIR}/tests/unit/serialize_tests ) set_property(TEST serialize_tests PROPERTY LABELS unit_tests) +add_test( string_tests ${CMAKE_BINARY_DIR}/tests/unit/string_tests ) +set_property(TEST string_tests PROPERTY LABELS unit_tests) add_test( symbol_tests ${CMAKE_BINARY_DIR}/tests/unit/symbol_tests ) set_property(TEST symbol_tests PROPERTY LABELS unit_tests) add_test( system_tests ${CMAKE_BINARY_DIR}/tests/unit/system_tests ) @@ -40,4 +42,4 @@ set_property(TEST varint_tests PROPERTY LABELS unit_tests) if (eosio_FOUND AND EOSIO_RUN_INTEGRATION_TESTS) add_test(integration_tests ${CMAKE_BINARY_DIR}/tests/integration/integration_tests) set_property(TEST integration_tests PROPERTY LABELS integration_tests) -endif() \ No newline at end of file +endif() diff --git a/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.cpp b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.cpp new file mode 100644 index 0000000000..ab144ec55a --- /dev/null +++ b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.cpp @@ -0,0 +1,23 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/602. + * + * Verifies that an aliased type can be used as a variant template arg. + */ + +#include + +using namespace eosio; + +using str = std::string; + +class [[eosio::contract]] aliased_type_variant_template_arg : public contract { +public: + using contract::contract; + + [[eosio::action]] + void hi(std::variant v) { + if (std::holds_alternative(v)) { + } else if (std::holds_alternative(v)) { + } + } +}; diff --git a/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json new file mode 100644 index 0000000000..3a5f5d8150 --- /dev/null +++ b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "abi": "{\n \"____comment\": \"This file was generated with eosio-abigen. DO NOT EDIT \",\n \"version\": \"eosio::abi\/1.1\",\n \"types\": [\n {\n \"new_type_name\": \"str\",\n \"type\": \"string\"\n }\n ],\n \"structs\": [\n {\n \"name\": \"hi\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"v\",\n \"type\": \"variant_uint64_str\"\n }\n ]\n }\n ],\n \"actions\": [\n {\n \"name\": \"hi\",\n \"type\": \"hi\",\n \"ricardian_contract\": \"\"\n }\n ],\n \"tables\": [],\n \"ricardian_clauses\": [],\n \"variants\": [\n {\n \"name\": \"variant_uint64_str\",\n \"types\": [\"uint64\",\"str\"]\n }\n ]\n}" + } + } + ] +} + diff --git a/tests/toolchain/abigen-pass/struct_base_typedefd.cpp b/tests/toolchain/abigen-pass/struct_base_typedefd.cpp new file mode 100644 index 0000000000..43ef5d760a --- /dev/null +++ b/tests/toolchain/abigen-pass/struct_base_typedefd.cpp @@ -0,0 +1,28 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/601. + * + * Verifies that a struct can inherit from a typedef'd class/struct. + */ + +#include + +using namespace eosio; + +struct foo { + int value; +}; + +using bar = foo; + +struct baz : bar { +}; + +class [[eosio::contract]] struct_base_typedefd : public contract { +public: + using contract::contract; + + [[eosio::action]] + void hi(baz b) { + print(b.value); + } +}; diff --git a/tests/toolchain/abigen-pass/struct_base_typedefd.json b/tests/toolchain/abigen-pass/struct_base_typedefd.json new file mode 100644 index 0000000000..0f56342de1 --- /dev/null +++ b/tests/toolchain/abigen-pass/struct_base_typedefd.json @@ -0,0 +1,9 @@ +{ + "tests": [ + { + "expected": { + "abi": "{\n \"____comment\": \"This file was generated with eosio-abigen. DO NOT EDIT \",\n \"version\": \"eosio::abi\/1.1\",\n \"types\": [\n {\n \"new_type_name\": \"bar\",\n \"type\": \"foo\"\n }\n ],\n \"structs\": [\n {\n \"name\": \"baz\",\n \"base\": \"bar\",\n \"fields\": []\n },\n {\n \"name\": \"foo\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"value\",\n \"type\": \"int32\"\n }\n ]\n },\n {\n \"name\": \"hi\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"b\",\n \"type\": \"baz\"\n }\n ]\n }\n ],\n \"actions\": [\n {\n \"name\": \"hi\",\n \"type\": \"hi\",\n \"ricardian_contract\": \"\"\n }\n ],\n \"tables\": [],\n \"ricardian_clauses\": [],\n \"variants\": []\n}" + } + } + ] +} diff --git a/tests/toolchain/build-pass/self_referential_table.cpp b/tests/toolchain/build-pass/self_referential_table.cpp new file mode 100644 index 0000000000..7fa02bb60c --- /dev/null +++ b/tests/toolchain/build-pass/self_referential_table.cpp @@ -0,0 +1,40 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/527. + * + * Verifies that a table can reference its own type. + */ + +#include +using namespace eosio; + +CONTRACT self_referential_table : public contract { + public: + using contract::contract; + + ACTION hi( name nm ); + using hi_action = action_wrapper<"hi"_n, &self_referential_table::hi>; + + private: + + + TABLE testtab { + uint64_t id; + name acc; + std::string mdata; + + std::vector container; + + auto primary_key() const { + return id; + } + + }; + + typedef eosio::multi_index< "testtabs"_n, testtab > testtabs; + +}; +ACTION self_referential_table::hi( name nm ) { + /* fill in action body */ + // print_f("Name : %\n",nm); + +} diff --git a/tests/toolchain/build-pass/self_referential_table.json b/tests/toolchain/build-pass/self_referential_table.json new file mode 100644 index 0000000000..b3598b0cf4 --- /dev/null +++ b/tests/toolchain/build-pass/self_referential_table.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 0 + } + } + ] +} + diff --git a/tests/toolchain/build-pass/separate_cpp_hpp.cpp b/tests/toolchain/build-pass/separate_cpp_hpp.cpp new file mode 100644 index 0000000000..76aa373204 --- /dev/null +++ b/tests/toolchain/build-pass/separate_cpp_hpp.cpp @@ -0,0 +1,11 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/582 + * + * Verifies that separate cpp and hpp files can be compile without `-o` + */ + +#include "separate_cpp_hpp.hpp" + +void separate_cpp_hpp::act() { + eosio::print("ok\n"); +} diff --git a/tests/toolchain/build-pass/separate_cpp_hpp.hpp b/tests/toolchain/build-pass/separate_cpp_hpp.hpp new file mode 100644 index 0000000000..2002834021 --- /dev/null +++ b/tests/toolchain/build-pass/separate_cpp_hpp.hpp @@ -0,0 +1,8 @@ +#include + +class [[eosio::contract]] separate_cpp_hpp : eosio::contract { +public: + using contract::contract; + + [[eosio::action]] void act(); +}; diff --git a/tests/toolchain/build-pass/separate_cpp_hpp.json b/tests/toolchain/build-pass/separate_cpp_hpp.json new file mode 100644 index 0000000000..b3598b0cf4 --- /dev/null +++ b/tests/toolchain/build-pass/separate_cpp_hpp.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 0 + } + } + ] +} + diff --git a/tests/toolchain/build-pass/using_nested_typedef.cpp b/tests/toolchain/build-pass/using_nested_typedef.cpp new file mode 100644 index 0000000000..d5ad2a23a3 --- /dev/null +++ b/tests/toolchain/build-pass/using_nested_typedef.cpp @@ -0,0 +1,22 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/600 + * + * Verifies that nested typedefs build. + */ + +#include +using namespace eosio; + +namespace foo { +//using str = std::string; +typedef std::string str; +} + +class [[eosio::contract]] using_nested_typedef : public contract { +public: + using contract::contract; + [[eosio::action]] + void hi(foo::str s) { + print(s); + } +}; diff --git a/tests/toolchain/build-pass/using_nested_typedef.json b/tests/toolchain/build-pass/using_nested_typedef.json new file mode 100644 index 0000000000..b3598b0cf4 --- /dev/null +++ b/tests/toolchain/build-pass/using_nested_typedef.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 0 + } + } + ] +} + diff --git a/tests/toolchain/build-pass/using_std_tuple.cpp b/tests/toolchain/build-pass/using_std_tuple.cpp new file mode 100644 index 0000000000..1f0520f6ad --- /dev/null +++ b/tests/toolchain/build-pass/using_std_tuple.cpp @@ -0,0 +1,30 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/558 + * + * Verifies that a class/function can be used from the std namespace + */ + +#include +#include +#include + +using std::tuple; +using namespace eosio; + +class[[eosio::contract("hello")]] hello : public contract +{ +public: + using contract::contract; + + [[eosio::action]] void hi(name user) { + require_auth(user); + print("Hello, ", user); + } + + struct [[eosio::table]] greeting { + uint64_t id; + tuple t; + uint64_t primary_key() const { return id; } + }; + typedef multi_index<"greeting"_n, greeting> greeting_index; +}; diff --git a/tests/toolchain/build-pass/using_std_tuple.json b/tests/toolchain/build-pass/using_std_tuple.json new file mode 100644 index 0000000000..b3598b0cf4 --- /dev/null +++ b/tests/toolchain/build-pass/using_std_tuple.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 0 + } + } + ] +} + diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 356bee274a..c6f165e2d5 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,3 +1,5 @@ +cmake_minimum_required(VERSION 3.5) + list( APPEND CMAKE_MODULE_PATH ${EOSIO_CDT_BIN} ) include( EosioCDTMacros ) @@ -9,6 +11,7 @@ add_native_executable( fixed_bytes_tests fixed_bytes_tests.cpp ) add_native_executable( name_tests name_tests.cpp ) add_native_executable( rope_tests rope_tests.cpp ) add_native_executable( serialize_tests serialize_tests.cpp ) +add_native_executable( string_tests string_tests.cpp ) add_native_executable( symbol_tests symbol_tests.cpp ) add_native_executable( system_tests system_tests.cpp ) add_native_executable( rope_tests rope_tests.cpp ) diff --git a/tests/unit/crypto_tests.cpp b/tests/unit/crypto_tests.cpp index 697e3228b2..41f860cd2b 100644 --- a/tests/unit/crypto_tests.cpp +++ b/tests/unit/crypto_tests.cpp @@ -13,26 +13,26 @@ using eosio::signature; EOSIO_TEST_BEGIN(public_key_type_test) // ----------------------------------------------------- // bool operator==(const public_key&, const public_key&) - CHECK_EQUAL( (public_key{0, std::array{}} == public_key{0, std::array{}}), true ) - CHECK_EQUAL( (public_key{0, std::array{1}} == public_key{0, std::array{}}), false ) + CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array{}) == public_key(std::in_place_index<0>, std::array{})), true ) + CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array{1}) == public_key(std::in_place_index<0>, std::array{})), false ) // ----------------------------------------------------- // bool operator!=(const public_key&, const public_key&) - CHECK_EQUAL( (public_key{0, std::array{}} != public_key{0, std::array{}}), false ) - CHECK_EQUAL( (public_key{0, std::array{1}} != public_key{0, std::array{}}), true ) + CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array{}) != public_key(std::in_place_index<0>, std::array{})), false ) + CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array{1}) != public_key(std::in_place_index<0>, std::array{})), true ) EOSIO_TEST_END // Definitions in `eosio.cdt/libraries/eosio/crypto.hpp` EOSIO_TEST_BEGIN(signature_type_test) // --------------------------------------------------- // bool operator==(const signature&, const signature&) - CHECK_EQUAL( (signature{0, std::array{}} == signature{0, std::array{}}), true ) - CHECK_EQUAL( (signature{0, std::array{1}} == signature{0, std::array{}}), false ) + CHECK_EQUAL( (signature(std::in_place_index<0>, std::array{}) == signature(std::in_place_index<0>, std::array{})), true ) + CHECK_EQUAL( (signature(std::in_place_index<0>, std::array{1}) == signature(std::in_place_index<0>, std::array{})), false ) // --------------------------------------------------- // bool operator!=(const signature&, const signature&) - CHECK_EQUAL( (signature{0, std::array{1}} != signature{0, std::array{}}), true ) - CHECK_EQUAL( (signature{0, std::array{}} != signature{0, std::array{}}), false ) + CHECK_EQUAL( (signature(std::in_place_index<0>, std::array{1}) != signature(std::in_place_index<0>, std::array{})), true ) + CHECK_EQUAL( (signature(std::in_place_index<0>, std::array{}) != signature(std::in_place_index<0>, std::array{})), false ) EOSIO_TEST_END int main(int argc, char* argv[]) { diff --git a/tests/unit/datastream_tests.cpp b/tests/unit/datastream_tests.cpp index cf102ec1b0..98fd528d1c 100644 --- a/tests/unit/datastream_tests.cpp +++ b/tests/unit/datastream_tests.cpp @@ -39,7 +39,9 @@ using eosio::ignore; using eosio::ignore_wrapper; using eosio::pack; using eosio::pack_size; +using eosio::ecc_public_key; using eosio::public_key; +using eosio::ecc_signature; using eosio::signature; using eosio::symbol; using eosio::symbol_code; @@ -507,7 +509,7 @@ EOSIO_TEST_BEGIN(datastream_stream_test) // eosio::public_key ds.seekp(0); fill(begin(datastream_buffer), end(datastream_buffer), 0); - static const public_key cpubkey{{},'a','b','c','d','e','f','g','h','i'}; + static const public_key cpubkey(std::in_place_index<0>,ecc_public_key{'a','b','c','d','e','f','g','h','i'}); public_key pubkey{}; ds << cpubkey; ds.seekp(0); @@ -518,7 +520,7 @@ EOSIO_TEST_BEGIN(datastream_stream_test) // eosio::signature ds.seekp(0); fill(begin(datastream_buffer), end(datastream_buffer), 0); - static const signature csig{{},'a','b','c','d','e','f','g','h','i'}; + static const signature csig(std::in_place_index<0>,ecc_signature{'a','b','c','d','e','f','g','h','i'}); signature sig{}; ds << csig; ds.seekp(0); diff --git a/tests/unit/string_tests.cpp b/tests/unit/string_tests.cpp new file mode 100644 index 0000000000..9bcda8a272 --- /dev/null +++ b/tests/unit/string_tests.cpp @@ -0,0 +1,1506 @@ +/** + * @file + * @copyright defined in eosio.cdt/LICENSE.txt + */ + +#include +#include +#include + +using std::fill; +using std::move; + +using eosio::datastream; +using eosio::string; + +// Definitions found in `eosio.cdt/libraries/eosiolib/core/eosio/string.hpp` +EOSIO_TEST_BEGIN(string_test) + //// template + //// string(const char (&str)[N]) + { + static const string eostr0{"a"}; + static const string eostr1{"abcdef"}; + + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "a"), 0 ) + + CHECK_EQUAL( eostr1.size(), 6 ) + CHECK_EQUAL( eostr1.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "abcdef"), 0) + } + + //// string() + { + static const string eostr{}; + + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( eostr.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0) + } + + //// constexpr string(const char* str, const size_t n) + { + static const char* str0{""}; + static const char* str1{"abc"}; + static const char* str2{"abcdef"}; + + static const string eostr0(str0, 0); + static const string eostr1(str1, 1); + static const string eostr2(str2, 6); + + CHECK_EQUAL( eostr0.size(), 0 ) + CHECK_EQUAL( eostr0.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) + + CHECK_EQUAL( eostr1.size(), 1 ) + CHECK_EQUAL( eostr1.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2.size(), 6 ) + CHECK_EQUAL( eostr2.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdef"), 0) + } + + //// string(const size_t n, const char c) + { + static const string eostr0(0, 'c'); + static const string eostr1(1, 'c'); + static const string eostr2(3, 'c'); + + CHECK_EQUAL( eostr0.size(), 0 ) + CHECK_EQUAL( eostr0.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) + + CHECK_EQUAL( eostr1.size(), 1 ) + CHECK_EQUAL( eostr1.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "c"), 0) + + CHECK_EQUAL( eostr2.size(), 3 ) + CHECK_EQUAL( eostr2.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "ccc"), 0) + } + + //// string(const string& str, const size_t pos, const size_t n = string::npos) + { + static const string eostr{"abcdef"}; + static const string eostr0_sub(eostr, 0, 0); + static const string eostr1_sub(eostr, 1, 0); + static const string eostr2_sub(eostr, 0, 1); + static const string eostr3_sub(eostr, 0, 3); + static const string eostr4_sub(eostr, 0, 8); + static const string eostr5_sub(eostr, 0, 7); + static const string eostr6_sub(eostr, 0, 6); + static const string eostr7_sub(eostr, 3, 3); + static const string eostr8_sub(eostr, 3, 2); + + CHECK_EQUAL( eostr0_sub.size(), 0 ) + CHECK_EQUAL( eostr0_sub.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_sub.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_sub.size(), 0 ) + CHECK_EQUAL( eostr1_sub.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr1_sub.c_str(), ""), 0) + + CHECK_EQUAL( eostr2_sub.size(), 1 ) + CHECK_EQUAL( eostr2_sub.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr2_sub.c_str(), "a"), 0) + + CHECK_EQUAL( eostr3_sub.size(), 3 ) + CHECK_EQUAL( eostr3_sub.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr3_sub.c_str(), "abc"), 0) + + CHECK_EQUAL( eostr4_sub.size(), 6 ) + CHECK_EQUAL( eostr4_sub.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr4_sub.c_str(), "abcdef"), 0) + + CHECK_EQUAL( eostr5_sub.size(), 6 ) + CHECK_EQUAL( eostr5_sub.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr5_sub.c_str(), "abcdef"), 0) + + CHECK_EQUAL( eostr6_sub.size(), 6 ) + CHECK_EQUAL( eostr6_sub.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr6_sub.c_str(), "abcdef"), 0 ) + + CHECK_EQUAL( eostr7_sub.size(), 3 ) + CHECK_EQUAL( eostr7_sub.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr7_sub.c_str(), "def"), 0 ) + + CHECK_EQUAL( eostr8_sub.size(), 2 ) + CHECK_EQUAL( eostr8_sub.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr8_sub.c_str(), "de"), 0) + } + + //// constexpr string(const string& str) + { + static const string eostr0{""}; + static const string eostr1{"a"}; + static const string eostr2{"abcdef"}; + static const string eostr0_cpy{eostr0}; + static const string eostr1_cpy{eostr1}; + static const string eostr2_cpy{eostr2}; + + CHECK_EQUAL( eostr0_cpy.size(), 0 ) + CHECK_EQUAL( eostr0_cpy.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_cpy.size(), 1 ) + CHECK_EQUAL( eostr1_cpy.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_cpy.size(), 6 ) + CHECK_EQUAL( eostr2_cpy.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2_cpy.c_str(), "abcdef"), 0) + } + + { + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_cpy{eostr0}; + static string eostr1_cpy{eostr1}; + + CHECK_EQUAL( eostr0_cpy.size(), 1 ) + CHECK_EQUAL( eostr0_cpy.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_cpy.size(), 6 ) + CHECK_EQUAL( eostr1_cpy.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "abcdef"), 0) + } + + //// constexpr string(const string&& str) + { + static string eostr0{""}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static const string eostr0_mv{move(eostr0)}; + static const string eostr1_mv{move(eostr1)}; + static const string eostr2_mv{move(eostr2)}; + + CHECK_EQUAL( eostr0_mv.size(), 0 ) + CHECK_EQUAL( eostr0_mv.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_mv.size(), 1 ) + CHECK_EQUAL( eostr1_mv.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_mv.size(), 6 ) + CHECK_EQUAL( eostr2_mv.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdef"), 0) + } + + { + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_cpy{move(eostr0)}; + static string eostr1_cpy{move(eostr1)}; + + CHECK_EQUAL( eostr0_cpy.size(), 1 ) + CHECK_EQUAL( eostr0_cpy.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_cpy.size(), 6 ) + CHECK_EQUAL( eostr1_cpy.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "abcdef"), 0) + } + + //// string& operator=(const string& str); + { + static const string eostr0{""}; + static const string eostr1{"a"}; + static const string eostr2{"abcdef"}; + static string eostr0_cpy_assig{}; + static string eostr1_cpy_assig{}; + static string eostr2_cpy_assig{}; + eostr0_cpy_assig = eostr0; + eostr1_cpy_assig = eostr1; + eostr2_cpy_assig = eostr2; + + CHECK_EQUAL( eostr0_cpy_assig.size(), 0 ) + CHECK_EQUAL( eostr0_cpy_assig.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_cpy_assig.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_cpy_assig.size(), 1 ) + CHECK_EQUAL( eostr1_cpy_assig.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1_cpy_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_cpy_assig.size(), 6 ) + CHECK_EQUAL( eostr2_cpy_assig.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2_cpy_assig.c_str(), "abcdef"), 0) + } + + { + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_cpy_assig{}; + static string eostr1_cpy_assig{}; + eostr0_cpy_assig = eostr0; + eostr1_cpy_assig = eostr1; + + CHECK_EQUAL( eostr0_cpy_assig.size(), 1 ) + CHECK_EQUAL( eostr0_cpy_assig.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_cpy_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_cpy_assig.size(), 6 ) + CHECK_EQUAL( eostr1_cpy_assig.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_cpy_assig.c_str(), "abcdef"), 0) + } + + //// string& operator=(string&& str) + { + static string eostr0{""}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr0_mv_assig{}; + static string eostr1_mv_assig{}; + static string eostr2_mv_assig{}; + eostr0_mv_assig = move(eostr0); + eostr1_mv_assig = move(eostr1); + eostr2_mv_assig = move(eostr2); + + CHECK_EQUAL( eostr0_mv_assig.size(), 0 ) + CHECK_EQUAL( eostr0_mv_assig.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_mv_assig.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_mv_assig.size(), 1 ) + CHECK_EQUAL( eostr1_mv_assig.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1_mv_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_mv_assig.size(), 6 ) + CHECK_EQUAL( eostr2_mv_assig.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2_mv_assig.c_str(), "abcdef"), 0) + } + + { + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_mv_assig{}; + static string eostr1_mv_assig{}; + eostr0_mv_assig = move(eostr0); + eostr1_mv_assig = move(eostr1); + + CHECK_EQUAL( eostr0_mv_assig.size(), 1 ) + CHECK_EQUAL( eostr0_mv_assig.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_mv_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_mv_assig.size(), 6 ) + CHECK_EQUAL( eostr1_mv_assig.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_mv_assig.c_str(), "abcdef"), 0) + } + + //// string& operator=(const char* str) + { + static string eostr{}; + eostr = "abcdef"; + + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + + eostr = eostr; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + } + + { + static string eostr{}; + eostr = ""; + eostr += "abcdef"; + + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + + eostr = eostr; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + } + + //// char& operator[](const size_t n) + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr[0], 'a' ) + CHECK_EQUAL( eostr[5], 'f' ) + } + + { + static string eostr{"abc"}; + eostr += "def"; + CHECK_EQUAL( eostr[0], 'a' ) + CHECK_EQUAL( eostr[5], 'f' ) + } + + //// const char& operator[](const size_t n) const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr[0], 'a' ) + CHECK_EQUAL( eostr[5], 'f' ) + } + + //// char& at(const size_t n) + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.at(0), 'a' ) + CHECK_EQUAL( eostr.at(5), 'f' ) + + CHECK_ASSERT( "eosio::string::at", []() {eostr.at(6);} ) + } + + //// const char& at(const size_t n) const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.at(0), 'a' ) + CHECK_EQUAL( eostr.at(5), 'f' ) + + CHECK_ASSERT( "eosio::string::at const", []() {eostr.at(6);} ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + const char c0{eostr.at(0)}; + const char c1{eostr.at(5)}; + CHECK_EQUAL( c0, 'a' ) + CHECK_EQUAL( c1, 'f' ) + } + + //// char& front() + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.front(), 'a' ) + + static string empty_str; + CHECK_EQUAL( eostr.front(), 'a' ) + } + + //// const char& front() const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.front(), 'a' ) + } + + //// char& back() + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.back(), 'f' ) + } + + //// const char& back() const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.back(), 'f' ) + } + + //// char* data() + { + static string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.data(), "abcdef"), 0 ) + + eostr = "abc"; + CHECK_EQUAL( strcmp(eostr.data(), "abc"), 0 ) + } + + //// const char* data() const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.data(), "abcdef"), 0 ) + } + + //// const char* c_str() const + { + static string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + CHECK_EQUAL( eostr.c_str()[eostr.size()], '\0' ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + CHECK_EQUAL( eostr.c_str()[eostr.size()], '\0' ) + } + + //// char* begin() + { + static string eostr{"abcdef"}; + char* iter{eostr.begin()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + char* iter{eostr.begin()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) + } + + //// const char* cbegin() const + { + static const string eostr{"abcdef"}; + const char* iter{eostr.cbegin()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) + } + + //// char* end() + { + static string eostr{"abcdef"}; + char* iter{eostr.end()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str()+eostr.size(), iter), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + char* iter{eostr.end()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str()+eostr.size(), iter), 0 ) + } + + //// const char* cend() const + { + static const string eostr{"abcdef"}; + const char* iter{eostr.cend()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.data()+eostr.size(), iter), 0 ) + } + + //// bool string::empty() const + { + static string eostr{}; + CHECK_EQUAL( eostr.empty(), true ) + eostr += 'c'; + CHECK_EQUAL( eostr.empty(), false ) + } + + //// size_t string::size() const + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.size(), 6 ) + eostr += 'g'; + CHECK_EQUAL( eostr.size(), 7 ) + } + + //// size_t string::length() const + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.length(), 6 ) + eostr += 'g'; + CHECK_EQUAL( eostr.length(), 7 ) + } + + //// size_t string::capacity() const + { + static string eostr{"abc"}; + CHECK_EQUAL( eostr.capacity(), 3 ) + eostr += 'd', eostr += 'e', eostr += 'f'; + CHECK_EQUAL( eostr.capacity(), 8 ) + eostr += 'g'; + CHECK_EQUAL( eostr.capacity(), 8 ) + } + + //// size_t string::max_size() const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.max_size(), string::npos ) + } + + //// void reserve(const size_t n) + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.capacity(), 6 ) + eostr.reserve(10); + CHECK_EQUAL( eostr.capacity(), 10 ) + eostr.reserve(24); + CHECK_EQUAL( eostr.capacity(), 24 ) + eostr.reserve(1); + CHECK_EQUAL( eostr.capacity(), 24 ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( eostr.capacity(), 12 ) + eostr.reserve(10); + CHECK_EQUAL( eostr.capacity(), 12 ) + eostr.reserve(24); + CHECK_EQUAL( eostr.capacity(), 24 ) + eostr.reserve(1); + CHECK_EQUAL( eostr.capacity(), 24 ) + } + + //// void string::shrink_to_fit() const + { + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + + CHECK_EQUAL( eostr0.capacity(), 0 ) + eostr0.reserve(100); + CHECK_EQUAL( eostr0.capacity(), 100 ) + eostr0.shrink_to_fit(); + CHECK_EQUAL( eostr0.capacity(), 0 ) + + CHECK_EQUAL( eostr1.capacity(), 1 ) + eostr1.reserve(100); + CHECK_EQUAL( eostr1.capacity(), 100 ) + eostr1.shrink_to_fit(); + CHECK_EQUAL( eostr1.capacity(), 1 ) + + CHECK_EQUAL( eostr2.capacity(), 6 ) + eostr2.reserve(100); + CHECK_EQUAL( eostr2.capacity(), 100 ) + eostr2.shrink_to_fit(); + CHECK_EQUAL( eostr2.capacity(), 6 ) + } + + //// void string::clear() + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.empty(), false ) + eostr.clear(); + CHECK_EQUAL( eostr.empty(), true ) + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( eostr.data()[0], '\0' ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( eostr.empty(), false ) + eostr.clear(); + CHECK_EQUAL( eostr.empty(), true ) + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( eostr.data()[0], '\0' ) + } + + //// void resize(size_t n) + { + static string eostr{"abcdef"}; + + eostr.resize(3); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + + eostr.resize(5); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + + eostr.resize(13); + CHECK_EQUAL( eostr.size(), 13 ) + CHECK_EQUAL( eostr.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + + eostr.resize(3); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + + eostr.resize(5); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + + eostr.resize(13); + CHECK_EQUAL( eostr.size(), 13 ) + CHECK_EQUAL( eostr.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + } + + //// void swap(string& str) + { + static string eostr_swap0{"abc"}; + static string eostr_swap1{"123456"}; + + eostr_swap0.swap(eostr_swap1); + + CHECK_EQUAL( eostr_swap0.size(), 6 ) + CHECK_EQUAL( eostr_swap0.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr_swap0.c_str(), "123456"), 0 ) + + CHECK_EQUAL( eostr_swap1.size(), 3 ) + CHECK_EQUAL( eostr_swap1.capacity(), 3 ) + CHECK_EQUAL( strcmp(eostr_swap1.c_str(), "abc"), 0 ) + } + + //// void push_back(char c) + { + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.size(), 6 ) + eostr.push_back('g'); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( eostr.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) + } + + //// void pop_back() + { + static string eostr{"abcdefg"}; + CHECK_EQUAL( eostr.size(), 7 ) + eostr.pop_back(); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + } + + { + static string eostr{"abc"}; + CHECK_EQUAL( eostr.size(), 3 ) + eostr.pop_back(); + eostr.pop_back(); + eostr.pop_back(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + + eostr.pop_back(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + //// string substr(size_t pos = 0, size_t len = npos) const + { + static const string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.substr(0).c_str(), "abcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,1).c_str(), "a"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,2).c_str(), "ab"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,3).c_str(), "abc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,4).c_str(), "abcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,5).c_str(), "abcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,6).c_str(), "abcdef"), 0 ) + + CHECK_EQUAL( strcmp(eostr.substr(1,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,1).c_str(), "b"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,2).c_str(), "bc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,3).c_str(), "bcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,4).c_str(), "bcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,5).c_str(), "bcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,6).c_str(), "bcdef"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( strcmp(eostr.substr(0).c_str(), "abcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,1).c_str(), "a"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,2).c_str(), "ab"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,3).c_str(), "abc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,4).c_str(), "abcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,5).c_str(), "abcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,6).c_str(), "abcdef"), 0 ) + + CHECK_EQUAL( strcmp(eostr.substr(1,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,1).c_str(), "b"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,2).c_str(), "bc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,3).c_str(), "bcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,4).c_str(), "bcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,5).c_str(), "bcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,6).c_str(), "bcdef"), 0 ) + } + + //// size_t copy(char* dest, size_t len, size_t pos = 0) const + { + static const string eostr{"abcdef"}; + static char str[7]{}; + + CHECK_EQUAL( eostr.copy(str, 0), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 0), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 1), 5 ) + CHECK_EQUAL( strcmp(str, "bcdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 2), 4 ) + CHECK_EQUAL( strcmp(str, "cdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 3), 3 ) + CHECK_EQUAL( strcmp(str, "def"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 4), 2 ) + CHECK_EQUAL( strcmp(str, "ef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 5), 1 ) + CHECK_EQUAL( strcmp(str, "f"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 6), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdef"; + static char str[7]{}; + + CHECK_EQUAL( eostr.copy(str, 0), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 0), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 1), 5 ) + CHECK_EQUAL( strcmp(str, "bcdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 2), 4 ) + CHECK_EQUAL( strcmp(str, "cdef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 3), 3 ) + CHECK_EQUAL( strcmp(str, "def"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 4), 2 ) + CHECK_EQUAL( strcmp(str, "ef"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 5), 1 ) + CHECK_EQUAL( strcmp(str, "f"), 0 ) + + CHECK_EQUAL( eostr.copy(str, 10, 6), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) + } + + { + static const string eostr{"abcdef"}; + static char str[7]{}; + CHECK_ASSERT( "eosio::string::copy", []() {eostr.copy(str, 1, eostr.size()+1);} ) + } + + //// string& insert(const size_t pos, const char* str) + { + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii"), 0 ) + } + + { + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii"), 0 ) + } + + { + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi"), 0 ) + } + + { + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii"), 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii"), 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi"), 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) + } + + { + static string eostr{"abcdefg"}; + static const char* null_man{nullptr}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(0, null_man, 1);} ) + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, "ooo", 1);} ) + } + + //// string& insert(const size_t pos, const string& str) + { + static string eostr{}; + static const string str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) + } + + { + static string eostr{"abc"}; + static const string str{"d"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( eostr.capacity(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) + } + + { + static string eostr{"abc"}; + static const string str{"def"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) + } + + { + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) + } + + { + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) + } + + { + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) + } + + { + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) + } + + { + static string eostr{"abcdefg"}; + static const string str{"ooo"}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) + } + + { + static string eostr{""}; + static string str{""}; + str += "ooo"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) + } + + { + static string eostr{""}; + eostr += "abc"; + static string str{""}; + str += "d"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) + } + + { + static string eostr{""}; + eostr += "abc"; + static string str{""}; + str += "def"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(1, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(2, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) + } + + { + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(3, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) + } + + { + static string eostr{"abcdefg"}; + static string str{"ooo"}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) + } + + { // Bucky's test for bug he caught; PR #459. + static string eostr = "hello"; + eostr.insert(0, "0", 1); /// `_capacity` is now 12; `_begin` now holds `std::unique_ptr` + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "0hello") , 0 ) + + eostr.insert(0, "h", 1); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "h0hello") , 0 ) + } + + //// string& erase(size_t pos = 0, size_t len = npos) + { + static string eostr{"abcdefgh"}; + eostr.erase(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(0); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(0, string::npos); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(1, string::npos); + CHECK_EQUAL( eostr.size(), 1 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(2, string::npos); + CHECK_EQUAL( eostr.size(), 2 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(3, string::npos); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(4, string::npos); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(5, string::npos); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(6, string::npos); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(7, string::npos); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(8, string::npos); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) + } + + { + static string eostr{"abcdefgh"}; + eostr.erase(8, 0); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) + } + + { + static string eostr{"abcdefg"}; + CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(0); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(0, string::npos); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(1, string::npos); + CHECK_EQUAL( eostr.size(), 1 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(2, string::npos); + CHECK_EQUAL( eostr.size(), 2 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(3, string::npos); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(4, string::npos); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(5, string::npos); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(6, string::npos); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(7, string::npos); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(8, string::npos); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) + } + + { + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(8, 0); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) + } + + { + static string eostr{"abcdefg"}; + CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) + } + + //// string& append(const char* str) + { + static string eostr{}; + static const char* str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) + } + + { + static string eostr{"abcdefg"}; + static const char* str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 10 ) + CHECK_EQUAL( eostr.capacity(), 20 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) + } + + { + static string eostr{"abcdefg"}; + static const char* null_man{nullptr}; + CHECK_ASSERT( "eosio::string::append", []() {eostr.append(null_man);} ) + } + + //// string& append(const string& str) + { + static string eostr{}; + static const string str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) + } + + { + static string eostr{"abcdefg"}; + static const string str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 10 ) + CHECK_EQUAL( eostr.capacity(), 20 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) + } + + //// string& operator+=(const char c) + { + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + + eostr0 += 'c'; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += 'c'; + eostr1 += 'c'; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += 'c'; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + } + + //// string& operator+=(const char* rhs) + { + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr3{"abcdef"}; + + eostr0 += "c"; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += "c"; + eostr1 += "c"; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += "c"; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + + eostr3 += "ghijklm"; + CHECK_EQUAL( eostr3.size(), 13 ) + CHECK_EQUAL( eostr3.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) + } + + //// string& operator+=(const string& rhs) + { + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr3{"abcdef"}; + + eostr0 += string{"c"}; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += string{"c"}; + eostr1 += string{"c"}; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += string{"c"}; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + + eostr3 += string{"ghijklm"}; + CHECK_EQUAL( eostr3.size(), 13 ) + CHECK_EQUAL( eostr3.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) + } + + //// string& operator+=(const string& s) + { + static string eostr0{"a"}; + static string eostr1{"b"}; + CHECK_EQUAL( eostr0.size(), 1 ) + eostr0 += eostr1; + CHECK_EQUAL( eostr0.size(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "ab"), 0 ) + } + + { + static string eostr0{"abc"}; + static string eostr1{"def"}; + CHECK_EQUAL( eostr0.size(), 3 ) + eostr0 += eostr1; + CHECK_EQUAL( eostr0.size(), 6 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "abcdef"), 0 ) + } + + //// inline void print(eosio::string str) + { + static const string eostr0{""}; + static const string eostr1{"abc"}; + static const string eostr2{"abcdef"}; + + CHECK_PRINT( "", [](){ print(eostr0); } ) + CHECK_PRINT( "abc", [](){ print(eostr1); } ) + CHECK_PRINT( "abcdef", [](){ print(eostr2); } ) + } + + //// friend bool operator< (const string& lhs, const string& rhs) + { + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 < eostr0), false ) + CHECK_EQUAL( (eostr1 < eostr1), false ) + CHECK_EQUAL( (eostr0 < eostr1), true ) + } + + //// friend bool operator> (const string& lhs, const string& rhs) + { + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 > eostr0), false ) + CHECK_EQUAL( (eostr1 > eostr1), false ) + CHECK_EQUAL( (eostr0 > eostr1), false ) + } + + //// friend bool operator<=(const string& lhs, const string& rhs) + { + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 <= eostr0), true ) + CHECK_EQUAL( (eostr1 <= eostr1), true ) + CHECK_EQUAL( (eostr0 <= eostr1), true ) + } + + //// friend bool operator>=(const string& lhs, const string& rhs) + { + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 >= eostr0), true ) + CHECK_EQUAL( (eostr1 >= eostr1), true ) + CHECK_EQUAL( (eostr0 >= eostr1), false ) + } + + //// friend bool operator==(const string& lhs, const string& rhs) + { + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 == eostr0), true ) + CHECK_EQUAL( (eostr1 == eostr1), true ) + CHECK_EQUAL( (eostr0 == eostr1), false ) + } + + //// friend bool operator!=(const string& lhs, const string& rhs) + { + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 != eostr0), false ) + CHECK_EQUAL( (eostr1 != eostr1), false ) + CHECK_EQUAL( (eostr0 != eostr1), true ) + } + + //// template + //// DataStream& operator<<(DataStream& ds, const string& str) + //// DataStream& operator>>(DataStream& ds, string& str) + { + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; // Buffer for the datastream to point to + static char buffer[buffer_size]; // Buffer to compare `datastream_buffer` with + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {""}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) + } + + { + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; + static char buffer[buffer_size]; + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {"a"}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) + } + + { + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; + static char buffer[buffer_size]; + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {"abcdefghi"}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) + } +EOSIO_TEST_END + +int main(int argc, char* argv[]) { + bool verbose = false; + if( argc >= 2 && std::strcmp( argv[1], "-v" ) == 0 ) { + verbose = true; + } + silence_output(!verbose); + + EOSIO_TEST(string_test) + return has_failed(); +} diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index 531f784d06..90ed8151d3 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -145,11 +145,13 @@ void generate(const std::vector& base_options, std::string input, s if (tool_run != 0) { throw std::runtime_error("abigen error"); } - std::string abi_s; - if (get_abigen_ref().is_empty()) - return; - get_abigen_ref().to_json().dump(abi_s); - codegen::get().set_abi(abi_s); + + if (!get_abigen_ref().is_empty()) { + std::string abi_s; + get_abigen_ref().to_json().dump(abi_s); + codegen::get().set_abi(abi_s); + } + tool_run = ctool.run(newFrontendActionFactory().get()); if (tool_run != 0) { throw std::runtime_error("codegen error"); diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 030cfdb4c3..bbbdddc52b 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -19,6 +19,10 @@ static llvm::cl::OptionCategory EosioLdToolCategory("ld options"); #endif /// begin ld options +static cl::opt no_abigen_opt( + "no-abigen", + cl::desc("Disable ABI file generation"), + cl::cat(LD_CAT)); static cl::opt fquery_opt( "fquery", cl::desc("Produce binaries for wasmql"), @@ -358,6 +362,11 @@ struct Options { static void GetCompDefaults(std::vector& copts) { const char* eosio_apply_suff = "${CMAKE_SHARED_LIBRARY_SUFFIX}"; std::string apply_lib; + // add the define for whether this is compiling with CDT and version macros + copts.emplace_back("-D__eosio_cdt__"); + copts.emplace_back(std::string("-D__eosio_cdt_major__=")+"${VERSION_MAJOR}"); + copts.emplace_back(std::string("-D__eosio_cdt_minor__=")+"${VERSION_MINOR}"); + copts.emplace_back(std::string("-D__eosio_cdt_patchlevel__=")+"${VERSION_PATCH}"); if (!fnative_opt) { copts.emplace_back("--target=wasm32"); copts.emplace_back("-ffreestanding"); @@ -376,6 +385,7 @@ static void GetCompDefaults(std::vector& copts) { if (!fasm_opt) { copts.emplace_back("-fno-builtin"); copts.emplace_back("-mstackrealign"); + copts.emplace_back("-D__eosio_cdt_native__"); copts.emplace_back("-DEOSIO_NATIVE"); copts.emplace_back("-DLLP64"); } @@ -499,6 +509,10 @@ static Options CreateOptions(bool add_defaults=true) { debug = g_opt; #endif + if (no_abigen_opt) { + ldopts.emplace_back("-no-abigen"); + } + if (add_defaults) { GetCompDefaults(copts); GetCompDefaults(agopts); diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index cd6c70c50e..1cd33e636b 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -436,6 +436,7 @@ namespace eosio { namespace cdt { if (as.base == td.new_type_name) return true; } + for ( auto v : _abi.variants ) { for ( auto vt : v.types ) { if ( remove_suffix(vt) == td.new_type_name ) diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index 8312164b27..c2f811afb2 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -399,6 +399,10 @@ namespace eosio { namespace cdt { for (auto nd : visitor->notify_decls) visitor->create_notify_dispatch(nd); + if (cg.actions.size() < 1 && cg.notify_handlers.size() < 1) { + return; + } + int fd; llvm::SmallString<128> fn; try { diff --git a/tools/include/eosio/whereami/linux.hpp b/tools/include/eosio/whereami/linux.hpp index 5e993942d1..7fb97080ac 100644 --- a/tools/include/eosio/whereami/linux.hpp +++ b/tools/include/eosio/whereami/linux.hpp @@ -2,7 +2,9 @@ #include #include #include -#define __STDC_FORMAT_MACROS +#ifndef __STDC_FORMAT_MACROS +# define __STDC_FORMAT_MACROS +#endif #include template diff --git a/tools/toolchain-tester/CMakeLists.txt b/tools/toolchain-tester/CMakeLists.txt new file mode 100644 index 0000000000..aadb128a1c --- /dev/null +++ b/tools/toolchain-tester/CMakeLists.txt @@ -0,0 +1,4 @@ +project(toolchain-tester) +cmake_minimum_required(VERSION 3.5) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/toolchain-tester ${CMAKE_BINARY_DIR}/ COPYONLY) diff --git a/tools/toolchain-tester/README.md b/tools/toolchain-tester/README.md new file mode 100644 index 0000000000..ca91540757 --- /dev/null +++ b/tools/toolchain-tester/README.md @@ -0,0 +1,104 @@ +# CDT Toolchain Testing Framework + +### Running Tests +Supported features: +- Running individual tests/test suites +- Parallel execution of tests +- Comparing output WASMs for correctness +- Comparing output abis for correctness +- Outputting results a human readable format +- [JSON File](#json-file) for controlling test runs (expected output, compile flags, etc) + +### Types of tests +There are multiple different types of toolchain tests, each is designed to exercise a different part of the toolchain. +* compile-fail: fail to compile +* compile-pass: compile successfully +* build-fail: fail to compile and link +* build-pass: compile and link successfully +* abigen-pass: abis are generated correctly +* abigen-fail: fail to generate abi + +### Test organization +Tests are put into directories under `tests/toolchain` based on their type as seen above (ie all compile-fail tests would be in `tests/toolchain/compile-fail`) + +If a test is intended to check the output WASM matches an expected WASM, the expected WASM is defined in the JSON file. A compressed version can be generated by running `xxd -p `. + +Test files should include a comment summarizing the point of the test at the start of the file. Focus on parts of the test that are more important, and what the bug was that the test is fixing. Issue/PR numbers are also helpful. + +### JSON File +The tests are managed by a JSON file placed next to the test file. It can define expected output, compile flags, etc. + +#### Expected Output +Allowable type of expected output are: +- "exit-code": Checks that it exited with a given code. +- "stderr": Checks for matching stderr. Currently a non-exact match. +- "wasm": A compressed version of the hex array representing the expected WASM. +- "abi": A stringified version of the abi that is expected. + +#### Example files: +```json +{ + "tests": [ + { + "compile-flags": ["-O0", "-fno-lto"], + "expected": { + "exit-code": 0 + } + } + ] +} +``` +```json +{ + "tests": [ + { + "expected": { + "stderr": "iostreams currently clash with eosio::datastream" + } + } + ] +} +``` +```json +{ +"tests": [ + { + "expected": { + "wasm": "0061736d01000000019c808080000660027f7e0060027f7f0060017e0060017f0060037e7e7e0060000002bb818080000903656e760f5f5f6c696e6561725f6d656d6f727902000103656e76195f5f696e6469726563745f66756e6374696f6e5f7461626c650170000003656e76087072696e74735f6c000103656e76067072696e746e000203656e76067072696e7473000303656e760c656f73696f5f617373657274000103656e76115f5f7761736d5f63616c6c5f63746f7273000503656e7611656f73696f5f6173736572745f636f6465000003656e760e5f5f6378615f66696e616c697a650003038480808000030000040aef81808000035801027f418080808000210202404180808080002d00002203450d000240034020034125460d0120024101108080808000200241016a22022d00002203450d020c000b0b2001108180808000200241016a1082808080000b0b7901027f418080808000210202404180808080002d00002203450d000240034020034125460d0120024101108080808000200241016a22022d00002203450d020c000b0b2001108180808000200241016a1082808080000b02402001428080808080c0c6d1ea00510d004100418a808080001083808080000b0b1a001084808080004100420110858080800041001086808080000b0bb580808000020041000b0a4e616d65203a20250a0000410a0b20636865636b206e616d65206e6f7420657175616c20746f206068656c6c6f600000bf80808000082e696d706f72747311656f73696f5f6173736572745f636f64650c656f73696f5f617373657274087072696e74735f6c067072696e746e067072696e7473008c808080000a2e656f73696f5f6162690000bf81808000076c696e6b696e67010885818080000c0004071a5f5a4e3568656c6c6f326869454e35656f73696f346e616d65450102062e4c2e73747200000a0010000010010010020004081d5f5a4e3568656c6c6f35636865636b454e35656f73696f346e616d65450102082e4c2e7374722e31010020001003000509125f5f696e736572745f656f73696f5f61626900100400100500100605a580808000020e2e726f646174612e2e4c2e7374720100102e726f646174612e2e4c2e7374722e31010000c7808080000a72656c6f632e434f4445030f0406010004100100002d02004803005304045f0100046901000086010200a1010300ac010404c701060000cd010700d7010900e1010a00e9010b" + } + } + ] +} +``` +```json +{ + "tests": [ + { + "expected": { + "abi": "{\"____comment\": \"This file was generated with eosio-abigen. DO NOT EDIT\",\n\"version\": \"eosio::abi/1.1\",\"types\": [],\"structs\": [..." + } + } + ] +} +``` + +### Command API +``` +usage: toolchain-tester [-h] [-v] [-j JOBS] [-t TESTS] [--format {human,xunit}] + [--cdt CDT] + test_directory + +positional arguments: + test_directory The directory where the toolchain tests are located. + +optional arguments: + -h, --help show this help message and exit + -v, --verbose Print verbose output + -j JOBS, --jobs JOBS Number of threads to use for parallel execution + (defaults to half of the system max) + -t TESTS, --tests TESTS + Test/Testsuite to run (defaults to all) + --format {human,xunit} + Format of the test output (defaults to human) + --cdt CDT Path to CDT (defaults to built CDT in this repo) +``` diff --git a/tools/toolchain-tester/__init__.py b/tools/toolchain-tester/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/toolchain-tester/examples/abigen-pass/multi_index_example.cpp b/tools/toolchain-tester/examples/abigen-pass/multi_index_example.cpp new file mode 100644 index 0000000000..fdb7ed3bb5 --- /dev/null +++ b/tools/toolchain-tester/examples/abigen-pass/multi_index_example.cpp @@ -0,0 +1,64 @@ +#include +using namespace eosio; + +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + + ACTION set(name user); + ACTION print( name user ); + ACTION bysec( name secid ); + ACTION mod( name user, uint32_t n ); + + TABLE test_table { + name test_primary; + name secondary; + uint64_t datum; + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; + using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; + using mod_action = action_wrapper<"mod"_n, &multi_index_example::mod>; + test_tables testtab; +}; + +ACTION multi_index_example::set( name user ) { + auto itr = testtab.find(user.value); + if ( itr == testtab.end() ) { + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} + +ACTION multi_index_example::print( name user ) { + auto itr = testtab.find(user.value); + check( itr != testtab.end(), "test table not set" ); + eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); +} + +ACTION multi_index_example::bysec( name secid ) { + auto idx = testtab.get_index<"secid"_n>(); + for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { + print( itr->test_primary ); + } +} + + +ACTION multi_index_example::mod( name user, uint32_t n ) { + auto itr = testtab.find(user.value); + check( itr != testtab.end(), "test table not set" ); + testtab.modify( itr, _self, [&]( auto& row ) { + row.secondary = user; + row.datum = n; + }); +} diff --git a/tools/toolchain-tester/examples/abigen-pass/multi_index_example.json b/tools/toolchain-tester/examples/abigen-pass/multi_index_example.json new file mode 100644 index 0000000000..60e1f57333 --- /dev/null +++ b/tools/toolchain-tester/examples/abigen-pass/multi_index_example.json @@ -0,0 +1,9 @@ +{ + "tests": [ + { + "expected": { + "abi": "{\n \"____comment\": \"This file was generated with eosio-abigen. DO NOT EDIT \",\n \"version\": \"eosio::abi\/1.1\",\n \"types\": [],\n \"structs\": [\n {\n \"name\": \"bysec\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"secid\",\n \"type\": \"name\"\n }\n ]\n },\n {\n \"name\": \"mod\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"user\",\n \"type\": \"name\"\n },\n {\n \"name\": \"n\",\n \"type\": \"uint32\"\n }\n ]\n },\n {\n \"name\": \"print\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"user\",\n \"type\": \"name\"\n }\n ]\n },\n {\n \"name\": \"set\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"user\",\n \"type\": \"name\"\n }\n ]\n },\n {\n \"name\": \"test_table\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"test_primary\",\n \"type\": \"name\"\n },\n {\n \"name\": \"secondary\",\n \"type\": \"name\"\n },\n {\n \"name\": \"datum\",\n \"type\": \"uint64\"\n }\n ]\n }\n ],\n \"actions\": [\n {\n \"name\": \"bysec\",\n \"type\": \"bysec\",\n \"ricardian_contract\": \"\"\n },\n {\n \"name\": \"mod\",\n \"type\": \"mod\",\n \"ricardian_contract\": \"\"\n },\n {\n \"name\": \"print\",\n \"type\": \"print\",\n \"ricardian_contract\": \"\"\n },\n {\n \"name\": \"set\",\n \"type\": \"set\",\n \"ricardian_contract\": \"\"\n }\n ],\n \"tables\": [\n {\n \"name\": \"testtaba\",\n \"type\": \"test_table\",\n \"index_type\": \"i64\",\n \"key_names\": [],\n \"key_types\": []\n }\n ],\n \"ricardian_clauses\": [],\n \"variants\": []\n}" + } + } + ] +} diff --git a/tools/toolchain-tester/examples/build-pass/multi_index_example.cpp b/tools/toolchain-tester/examples/build-pass/multi_index_example.cpp new file mode 100644 index 0000000000..fdb7ed3bb5 --- /dev/null +++ b/tools/toolchain-tester/examples/build-pass/multi_index_example.cpp @@ -0,0 +1,64 @@ +#include +using namespace eosio; + +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + + ACTION set(name user); + ACTION print( name user ); + ACTION bysec( name secid ); + ACTION mod( name user, uint32_t n ); + + TABLE test_table { + name test_primary; + name secondary; + uint64_t datum; + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; + using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; + using mod_action = action_wrapper<"mod"_n, &multi_index_example::mod>; + test_tables testtab; +}; + +ACTION multi_index_example::set( name user ) { + auto itr = testtab.find(user.value); + if ( itr == testtab.end() ) { + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} + +ACTION multi_index_example::print( name user ) { + auto itr = testtab.find(user.value); + check( itr != testtab.end(), "test table not set" ); + eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); +} + +ACTION multi_index_example::bysec( name secid ) { + auto idx = testtab.get_index<"secid"_n>(); + for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { + print( itr->test_primary ); + } +} + + +ACTION multi_index_example::mod( name user, uint32_t n ) { + auto itr = testtab.find(user.value); + check( itr != testtab.end(), "test table not set" ); + testtab.modify( itr, _self, [&]( auto& row ) { + row.secondary = user; + row.datum = n; + }); +} diff --git a/tools/toolchain-tester/examples/build-pass/multi_index_example.json b/tools/toolchain-tester/examples/build-pass/multi_index_example.json new file mode 100644 index 0000000000..45cc13fc90 --- /dev/null +++ b/tools/toolchain-tester/examples/build-pass/multi_index_example.json @@ -0,0 +1,5 @@ +{ + "tests": [ + { "expected": { "exit-code": 0 } } + ] +} diff --git a/tools/toolchain-tester/examples/compile-fail/hello_world.cpp b/tools/toolchain-tester/examples/compile-fail/hello_world.cpp new file mode 100644 index 0000000000..27e7ec8d4e --- /dev/null +++ b/tools/toolchain-tester/examples/compile-fail/hello_world.cpp @@ -0,0 +1,23 @@ +#include +#include +using namespace eosio; + +CONTRACT hello : public contract { + public: + using contract::contract; + + ACTION hi( name nm ); + ACTION check( name nm ); + + using hi_action = action_wrapper<"hi"_n, &hello::hi>; + using check_action = action_wrapper<"check"_n, &hello::check>; +}; + +ACTION hello::hi( name nm ) { + print_f("Name : %\n", nm); +} + +ACTION hello::check( name nm ) { + print_f("Name : %\n", nm); + eosio::check(nm == "hello"_n, "check name not equal to `hello`"); +} diff --git a/tools/toolchain-tester/examples/compile-fail/hello_world.json b/tools/toolchain-tester/examples/compile-fail/hello_world.json new file mode 100644 index 0000000000..8cbe14c31b --- /dev/null +++ b/tools/toolchain-tester/examples/compile-fail/hello_world.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 255, + "stderr": "iostreams currently clash with eosio::datastream" + } + } + ] +} diff --git a/tools/toolchain-tester/examples/compile-pass/hello_world.cpp b/tools/toolchain-tester/examples/compile-pass/hello_world.cpp new file mode 100644 index 0000000000..a86034b1aa --- /dev/null +++ b/tools/toolchain-tester/examples/compile-pass/hello_world.cpp @@ -0,0 +1,22 @@ +#include +using namespace eosio; + +CONTRACT hello : public contract { + public: + using contract::contract; + + ACTION hi( name nm ); + ACTION check( name nm ); + + using hi_action = action_wrapper<"hi"_n, &hello::hi>; + using check_action = action_wrapper<"check"_n, &hello::check>; +}; + +ACTION hello::hi( name nm ) { + print_f("Name : %\n", nm); +} + +ACTION hello::check( name nm ) { + print_f("Name : %\n", nm); + eosio::check(nm == "hello"_n, "check name not equal to `hello`"); +} diff --git a/tools/toolchain-tester/examples/compile-pass/hello_world.json b/tools/toolchain-tester/examples/compile-pass/hello_world.json new file mode 100644 index 0000000000..488f20bed9 --- /dev/null +++ b/tools/toolchain-tester/examples/compile-pass/hello_world.json @@ -0,0 +1,15 @@ +{ + "tests": [ + { + "compile-flags": ["-O0", "-fno-lto"], + "expected": { + "exit-code": 0 + } + }, + { + "expected": { + "wasm": "0061736d01000000019c808080000660027f7e0060027f7f0060017e0060017f0060037e7e7e0060000002bb818080000903656e760f5f5f6c696e6561725f6d656d6f727902000103656e76195f5f696e6469726563745f66756e6374696f6e5f7461626c650170000003656e76087072696e74735f6c000103656e76067072696e746e000203656e76067072696e7473000303656e760c656f73696f5f617373657274000103656e76115f5f7761736d5f63616c6c5f63746f7273000503656e7611656f73696f5f6173736572745f636f6465000003656e760e5f5f6378615f66696e616c697a650003038480808000030000040aef81808000035801027f418080808000210202404180808080002d00002203450d000240034020034125460d0120024101108080808000200241016a22022d00002203450d020c000b0b2001108180808000200241016a1082808080000b0b7901027f418080808000210202404180808080002d00002203450d000240034020034125460d0120024101108080808000200241016a22022d00002203450d020c000b0b2001108180808000200241016a1082808080000b02402001428080808080c0c6d1ea00510d004100418a808080001083808080000b0b1a001084808080004100420110858080800041001086808080000b0bb580808000020041000b0a4e616d65203a20250a0000410a0b20636865636b206e616d65206e6f7420657175616c20746f206068656c6c6f600000bf80808000082e696d706f72747311656f73696f5f6173736572745f636f64650c656f73696f5f617373657274087072696e74735f6c067072696e746e067072696e7473008c808080000a2e656f73696f5f6162690000bf81808000076c696e6b696e67010885818080000c0004071a5f5a4e3568656c6c6f326869454e35656f73696f346e616d65450102062e4c2e73747200000a0010000010010010020004081d5f5a4e3568656c6c6f35636865636b454e35656f73696f346e616d65450102082e4c2e7374722e31010020001003000509125f5f696e736572745f656f73696f5f61626900100400100500100605a580808000020e2e726f646174612e2e4c2e7374720100102e726f646174612e2e4c2e7374722e31010000c7808080000a72656c6f632e434f4445030f0406010004100100002d02004803005304045f0100046901000086010200a1010300ac010404c701060000cd010700d7010900e1010a00e9010b" + } + } + ] +} diff --git a/tools/toolchain-tester/main.py b/tools/toolchain-tester/main.py new file mode 100644 index 0000000000..c6d12fc801 --- /dev/null +++ b/tools/toolchain-tester/main.py @@ -0,0 +1,90 @@ +import argparse +import os +import tempfile + +from pathlib import Path +from timeit import default_timer as timer +from typing import List + +from printer import Printer as P +from printer import print_test_results, print_test_results_machine + +from settings import Config +from testrunner import TestRunner +from testsuite import TestSuite + + +def main(): + parser = argparse.ArgumentParser() + + parser.add_argument( + "test_directory", help="The directory where the toolchain tests are located." + ) + + parser.add_argument( + "-v", "--verbose", action="store_true", help="Print verbose output" + ) + parser.add_argument( + "-j", + "--jobs", + type=int, + default=int(os.cpu_count() / 2), + help="Number of threads to use for parallel execution (defaults to half of the system max)", + ) + parser.add_argument( + "-t", "--tests", default="all", help="Test/Testsuite to run (defaults to all)" + ) + parser.add_argument( + "--format", + choices=("human", "xunit"), + default="human", + help="Format of the test output (defaults to human)", + ) + parser.add_argument( + "--cdt", + default=get_cdt_path(), + help="Path to CDT (defaults to built CDT in this repo)", + ) + + args = parser.parse_args() + + Config.cdt_path = args.cdt + P.verbose = args.verbose + + abs_test_directory = os.path.abspath(args.test_directory) + + temp_dir = tempfile.mkdtemp() + + P.print(f"Temp files will be written to {temp_dir}...", verbose=True) + + os.chdir(temp_dir) + + test_directories: List[str] = [] + + for f in os.listdir(abs_test_directory): + abs_f = os.path.join(abs_test_directory, f) + + if os.path.isdir(abs_f): + test_directories.append(abs_f) + + test_suites = list(map(lambda d: TestSuite(d), test_directories)) + + start = timer() + test_runner = TestRunner(test_suites, args.tests, args.jobs) + test_results = test_runner.run_tests() + end = timer() + + if args.format == "human": + print_test_results(test_results, end - start) + else: + print_test_results_machine(test_results, end - start) + + +def get_cdt_path() -> str: + return os.path.join( + Path(os.path.realpath(__file__)).parent.parent.parent, "build", "bin" + ) + + +if __name__ == "__main__": + main() diff --git a/tools/toolchain-tester/printer.py b/tools/toolchain-tester/printer.py new file mode 100644 index 0000000000..b524b80464 --- /dev/null +++ b/tools/toolchain-tester/printer.py @@ -0,0 +1,125 @@ +# Prevents an import at runtime so there's no cyclical dependency +from __future__ import annotations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from tests import Test + +from typing import List, Optional, Tuple + +from settings import TestFailure + +COLORS = { + "black": 0, + "red": 1, + "green": 2, + "yellow": 3, + "blue": 4, + "magenta": 5, + "cyan": 6, + "white": 7, +} + +STYLES = {"reset": 0, "bold": 1, "italic": 3, "underline": 4} + + +def print_test_results( + results: List[Tuple[Test, Optional[TestFailure]]], run_time: float +) -> None: + Printer.print("\n========= Results =========") + + failures = [] + successes = [] + + total_tests = len(results) + + for t, r in results: + if r is not None: + failures.append(r) + else: + successes.append(t) + + if failures: + for f in failures: + Printer.red("Failure: ", newline=False) + Printer.print(f"{f.failing_test.fullname} failed with message: ") + Printer.red(f"\t{f}") + Printer.print() + + for s in successes: + Printer.green("Success: ", newline=False) + Printer.print(f"{s.fullname}") + + num_failures = len(failures) + pct = 100 - (100 * num_failures / total_tests) + Printer.yellow( + f"\n{pct:.0f}% of tests passed, {num_failures} tests failed out of {total_tests}" + ) + else: + Printer.green(f"\n100% of tests passed, 0 tests failed out of {total_tests}") + + Printer.print(f"\nTotal Test discovery and run time = {run_time:.2f} sec") + + +def print_test_results_machine( + results: List[Tuple[Test, Optional[TestFailure]]], run_time: float +) -> None: + Printer.red("TODO") + + +class Printer: + verbose = False + + @staticmethod + def print(*text, verbose=False, newline=True): + end = "\n" if newline else "" + + if not verbose: + print(*text, end=end) + + if verbose and Printer.verbose: + print(*text, end=end) + + @staticmethod + def red(*text, verbose=False, newline=True): + if not verbose: + print_decorated(*text, fcolor="red", newline=newline) + + if verbose and Printer.verbose: + print_decorated(*text, fcolor="red", newline=newline) + + @staticmethod + def green(*text, verbose=False, newline=True): + if not verbose: + print_decorated(*text, fcolor="green", newline=newline) + + if verbose and Printer.verbose: + print_decorated(*text, fcolor="green", newline=newline) + + @staticmethod + def yellow(*text, verbose=False, newline=True): + if not verbose: + print_decorated(*text, fcolor="yellow", newline=newline) + + if verbose and Printer.verbose: + print_decorated(*text, fcolor="yellow", newline=newline) + + +def print_decorated(*text, style=None, fcolor=None, bcolor=None, newline=True): + text_format = parse(style, fcolor, bcolor) + end = "\n" if newline else "" + print(f"\033[{text_format}m", end="") + print(*text, end="") + print("\033[0m", end=end) + + +def parse(style="", fcolor="", bcolor=""): + attr = [] if not style else [STYLES[style]] + + if fcolor: + attr.append(30 + COLORS[fcolor]) + + if bcolor: + attr.append(40 + COLORS[bcolor]) + + return ";".join([str(x) for x in attr]) diff --git a/tools/toolchain-tester/settings.py b/tools/toolchain-tester/settings.py new file mode 100644 index 0000000000..7e52333e6f --- /dev/null +++ b/tools/toolchain-tester/settings.py @@ -0,0 +1,36 @@ +from enum import Enum + + +class Config: + cdt_path = "" + verbose = False + + +class TestType(Enum): + COMPILE_FAIL = 1 + COMPILE_PASS = 2 + BUILD_FAIL = 3 + BUILD_PASS = 4 + ABIGEN_PASS = 5 + ABIGEN_FAIL = 6 + + @staticmethod + def from_str(s): + s = s.upper() + s = s.replace("-", "_") + + return TestType[s] + + +class TestFailure(Exception): + def __init__(self, error_msg, failing_test=None): + super().__init__(error_msg) + self.failing_test = failing_test + + +class MissingCppError(Exception): + pass + + +class MissingJsonError(Exception): + pass diff --git a/tools/toolchain-tester/setup.cfg b/tools/toolchain-tester/setup.cfg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/toolchain-tester/testrunner.py b/tools/toolchain-tester/testrunner.py new file mode 100644 index 0000000000..d0b3982491 --- /dev/null +++ b/tools/toolchain-tester/testrunner.py @@ -0,0 +1,75 @@ +from multiprocessing import Pool +from typing import Dict, List, NamedTuple, Optional, Tuple + +from printer import Printer as P + +from settings import TestFailure +from testsuite import TestSuite +from tests import Test + + +class TestResult(NamedTuple): + test: Test + failure: Optional[TestFailure] + + +class TestRunner: + def __init__( + self, test_suites: List[TestSuite], name_of_tests_to_run: str, num_jobs: int + ): + self.test_suites: List[TestSuite] = test_suites + self.name_of_tests_to_run = name_of_tests_to_run + self.tests_to_run: List[Test] = self.get_tests_to_run() + self.num_jobs: int = num_jobs + + self.test_map: Dict[str, Test] = {} + self.test_suite_map: Dict[str, TestSuite] = {} + + def get_tests_to_run(self): + tests_to_run: List[Test] = [] + + if self.name_of_tests_to_run == "all": + tests_to_run = [t for ts in self.test_suites for t in ts.tests] + elif "/" in self.name_of_tests_to_run: + # We're running a test + self.build_test_map() + tests_to_run.append(self.test_map[self.name_of_tests_to_run]) + else: + # We're running a test suite + self.build_test_suite_map() + ts = self.test_suites_map[self.name_of_tests_to_run] + tests_to_run = [t for t in ts.tests] + + return tests_to_run + + def run_tests(self) -> List[TestResult]: + with Pool(self.num_jobs) as p: + results_list = p.map(self.run_test, self.tests_to_run) + + return results_list + + def run_test(self, t: Test) -> TestResult: + try: + P.print(f"Running {t.fullname}") + t.run() + except TestFailure as f: + return TestResult(t, f) + + return TestResult(t, None) + + def build_test_suite_map(self): + test_suites_map = {} + + for ts in self.test_suites: + test_suites_map[ts.name] = ts + + self.test_suites_map = test_suites_map + + def build_test_map(self): + test_map = {} + + for ts in self.test_suites: + for t in ts.tests: + test_map[t.name] = t + + self.test_map = test_map diff --git a/tools/toolchain-tester/tests.py b/tools/toolchain-tester/tests.py new file mode 100644 index 0000000000..6f5a2e2c73 --- /dev/null +++ b/tools/toolchain-tester/tests.py @@ -0,0 +1,190 @@ +from __future__ import annotations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from testsuite import TestSuite + +import difflib +import json +import os +import subprocess +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Dict, List + +from printer import Printer as P +from settings import Config, TestFailure + + +class Test(ABC): + """ + This class represents a singular test file. + """ + + def __init__( + self, cpp_file: str, test_json: Dict, index: int, test_suite: TestSuite + ): + self.cpp_file: str = cpp_file + self.test_json: Dict = test_json + self.test_suite: TestSuite = test_suite + + self._name = cpp_file.split("/")[-1].split(".")[0] + self.name: str = f"{self._name}_{index}" + + self.fullname: str = f"{test_suite.name}/{self.name}" + + self.out_wasm: str = f"{self._name}.wasm" + + self.success: bool = False + + @abstractmethod + def _run(self, eosio_cpp: str, args: List[str]): + pass + + def run(self): + cf = self.test_json.get("compile_flags") + args = cf if cf else [] + + eosio_cpp = os.path.join(Config.cdt_path, "eosio-cpp") + self._run(eosio_cpp, args) + + def handle_test_result(self, res: subprocess.CompletedProcess, expected_pass=True): + stdout = res.stdout.decode("utf-8").strip() + stderr = res.stderr.decode("utf-8").strip() + + P.print(stdout, verbose=True) + P.print(stderr, verbose=True) + + if expected_pass and res.returncode > 0: + self.success = False + raise TestFailure( + f"{self.fullname} failed with the following stderr {stderr}", + failing_test=self, + ) + + if not expected_pass and res.returncode == 0: + self.success = False + raise TestFailure( + "expected to fail compilation/linking but didn't.", failing_test=self + ) + + if not self.test_json.get("expected"): + self.success = True + else: + self.handle_expecteds(res) + + def handle_expecteds(self, res: subprocess.CompletedProcess): + expected = self.test_json["expected"] + + if expected.get("exit-code"): + exit_code = expected["exit-code"] + + if res.returncode != exit_code: + self.success = False + raise TestFailure( + f"expected {exit_code} exit code but got {res.returncode}", + failing_test=self, + ) + + if expected.get("stderr"): + expected_stderr = expected["stderr"] + actual_stderr = res.stderr.decode("utf-8") + + if expected_stderr not in actual_stderr: + self.success = False + raise TestFailure( + f"expected {expected_stderr} stderr but got {actual_stderr}", + failing_test=self, + ) + + if expected.get("abi"): + expected_abi = expected["abi"] + with open(f"{self._name}.abi") as f: + actual_abi = f.read() + + expected_abi_str = json.dumps(json.loads(expected_abi), indent=2) + actual_abi_str = json.dumps(json.loads(actual_abi), indent=2) + + if expected_abi_str != actual_abi_str: + d = difflib.Differ() + diff = d.compare( + expected_abi_str.splitlines(), actual_abi_str.splitlines() + ) + P.print("\n".join(diff), verbose=True) + self.success = False + raise TestFailure( + "actual abi did not match expected abi", failing_test=self + ) + + if expected.get("wasm"): + expected_wasm = expected["wasm"] + + xxd = subprocess.Popen(("xxd", "-p", self.out_wasm), stdout=subprocess.PIPE) + tr = subprocess.check_output(("tr", "-d", "\n"), stdin=xxd.stdout) + xxd.wait() + + actual_wasm = tr.decode("utf-8") + + if expected_wasm != actual_wasm: + self.success = False + raise TestFailure( + "actual wasm did not match expected wasm", failing_test=self + ) + + self.success = True + + def __repr__(self): + return self.__str__() + + def __str__(self): + return self.fullname + + +class BuildPassTest(Test): + def _run(self, eosio_cpp, args): + command = [eosio_cpp, self.cpp_file] + command.extend(args) + res = subprocess.run(command, capture_output=True) + self.handle_test_result(res) + + return res + + +class CompilePassTest(Test): + def _run(self, eosio_cpp, args): + command = [eosio_cpp, "-c", self.cpp_file] + command.extend(args) + res = subprocess.run(command, capture_output=True) + self.handle_test_result(res) + + return res + + +class AbigenPassTest(Test): + def _run(self, eosio_cpp, args): + command = [eosio_cpp, self.cpp_file, "-abigen_output=''"] + command.extend(args) + res = subprocess.run(command, capture_output=True) + self.handle_test_result(res) + + return res + + +class BuildFailTest(Test): + def _run(self, eosio_cpp, args): + command = [eosio_cpp, self.cpp_file] + command.extend(args) + res = subprocess.run(command, capture_output=True) + self.handle_test_result(res, expected_pass=False) + + return res + + +class CompileFailTest(Test): + def _run(self, eosio_cpp, args): + command = [eosio_cpp, "-c", self.cpp_file] + command.extend(args) + res = subprocess.run(command, capture_output=True) + self.handle_test_result(res, expected_pass=False) + + return res diff --git a/tools/toolchain-tester/testsuite.py b/tools/toolchain-tester/testsuite.py new file mode 100644 index 0000000000..33b489404f --- /dev/null +++ b/tools/toolchain-tester/testsuite.py @@ -0,0 +1,81 @@ +import json +import os +from typing import List + +import tests +from settings import MissingCppError, MissingJsonError, TestType + + +class TestSuite: + """ + This class represents a collection of test files. The collection is determined + by the directory structure. + """ + + def __init__(self, directory: str): + self.directory = directory + self.tests: List[tests.Test] = [] + self.name = self._get_name() + self.test_type = self._get_test_type() + + test_files = [] + + for f in os.listdir(self.directory): + abs_f = os.path.join(self.directory, f) + + file_name = abs_f.split("/")[-1] + name = file_name.split(".")[0] + + if ".cpp" in file_name: + if not os.path.isfile(os.path.join(self.directory, f"{name}.json")): + raise MissingJsonError(f"{file_name} is missing the test json file") + + if ".json" in file_name: + if not os.path.isfile(os.path.join(self.directory, f"{name}.cpp")): + raise MissingCppError(f"{file_name} is missing the test cpp file") + test_files.append(abs_f) + + for tf in test_files: + with open(tf) as jf: + test_json = json.load(jf) + + name = tf.split("/")[-1].split(".")[0] + for i, t in enumerate(test_json["tests"]): + cpp_file = os.path.join(self.directory, f"{name}.cpp") + + args = [cpp_file, t, i, self] + + if self.test_type == TestType.BUILD_PASS: + self.tests.append(tests.BuildPassTest(*args)) + elif self.test_type == TestType.BUILD_FAIL: + self.tests.append(tests.BuildPassTest(*args)) + elif self.test_type == TestType.COMPILE_PASS: + self.tests.append(tests.CompilePassTest(*args)) + elif self.test_type == TestType.COMPILE_FAIL: + self.tests.append(tests.CompileFailTest(*args)) + elif self.test_type == TestType.ABIGEN_PASS: + self.tests.append(tests.AbigenPassTest(*args)) + + def _get_test_type(self) -> TestType: + return TestType.from_str(self.directory.split("/")[-1]) + + def _get_name(self) -> str: + return self.directory.split("/")[-1] + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + s = self.name + s += ": " + first = True + + for t in self.tests: + if first: + first = False + else: + s += "," + + s += str(t) + + return s diff --git a/tools/toolchain-tester/toolchain-tester b/tools/toolchain-tester/toolchain-tester new file mode 100755 index 0000000000..1e61fff1dd --- /dev/null +++ b/tools/toolchain-tester/toolchain-tester @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_ROOT=$(git rev-parse --show-toplevel) +python3 "${REPO_ROOT}/tools/toolchain-tester/main.py" "$@" diff --git a/uninstall.sh b/uninstall.sh deleted file mode 100755 index b7d82121ec..0000000000 --- a/uninstall.sh +++ /dev/null @@ -1,57 +0,0 @@ -#! /bin/bash - -binaries=(eosio-ranlib - eosio-ar - eosio-objdump - eosio-readelf - eosio-abigen - eosio-wasm2wast - eosio-wast2wasm - eosio-pp - eosio-cc - eosio-cpp - eosio-ld) - -if [ -d "/usr/local/eosio.cdt" ]; then - printf "\tDo you wish to remove this install? (requires sudo)\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - pushd /usr/local &> /dev/null - rm -rf eosio.cdt - pushd bin &> /dev/null - for binary in ${binaries[@]}; do - rm ${binary} - done - popd &> /dev/null - pushd lib/cmake &> /dev/null - rm -rf eosio.cdt - popd &> /dev/null - break;; - [Nn]* ) - printf "\tAborting uninstall\n\n" - exit -1;; - esac - done -fi - -if [ -d "/usr/local/eosio.wasmsdk" ]; then - printf "\tDo you wish to remove this install? (requires sudo)\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - pushd /usr/local &> /dev/null - rm -rf eosio.wasmsdk - pushd bin &> /dev/null - for binary in ${binaries[@]}; do - rm ${binary} - done - popd &> /dev/null - break;; - - [Nn]* ) - printf "\tAborting uninstall\n\n" - exit -1;; - esac - done -fi