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