1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-15 04:32:21 +00:00

Merge pull request #635 from ton-blockchain/testnet

Merge 03.2023 update
This commit is contained in:
EmelyanenkoK 2023-03-06 14:07:44 +03:00 committed by GitHub
commit b2a3483cfb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
118 changed files with 4753 additions and 750 deletions

View file

@ -1,19 +0,0 @@
FROM ubuntu:18.04
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build
WORKDIR /
ARG BRANCH
RUN git clone --recurse-submodules https://github.com/ton-blockchain/ton.git && cd ton && git checkout $BRANCH
WORKDIR /ton
RUN mkdir /ton/build
WORKDIR /ton/build
ENV CC clang
ENV CXX clang++
ENV CCACHE_DISABLE 1
RUN cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DPORTABLE=1 -DTON_ARCH= -DCMAKE_CXX_FLAGS="-mavx2" ..
RUN ninja storage-daemon storage-daemon-cli tonlibjson blockchain-explorer fift func validator-engine validator-engine-console create-state generate-random-id create-hardfork dht-server lite-client

View file

@ -2,12 +2,13 @@ FROM ubuntu:20.04
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build pkg-config
WORKDIR /
ARG BRANCH
RUN git clone --recurse-submodules https://github.com/ton-blockchain/ton.git && cd ton && git checkout $BRANCH
ARG REPO
RUN git clone --recurse-submodules https://github.com/$REPO && cd ton && git checkout $BRANCH
WORKDIR /ton
RUN mkdir /ton/build

View file

@ -2,12 +2,13 @@ FROM ubuntu:22.04
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build pkg-config
WORKDIR /
ARG BRANCH
RUN git clone --recurse-submodules https://github.com/ton-blockchain/ton.git && cd ton && git checkout $BRANCH
ARG REPO
RUN git clone --recurse-submodules https://github.com/$REPO && cd ton && git checkout $BRANCH
WORKDIR /ton
RUN mkdir /ton/build

View file

@ -1,19 +0,0 @@
FROM ubuntu:18.04
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build
WORKDIR /
ARG BRANCH
RUN git clone --recurse-submodules https://github.com/ton-blockchain/ton.git && cd ton && git checkout $BRANCH
WORKDIR /ton
RUN mkdir /ton/build
WORKDIR /ton/build
ENV CC clang
ENV CXX clang++
ENV CCACHE_DISABLE 1
RUN cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DPORTABLE=1 -DTON_ARCH= ..
RUN ninja storage-daemon storage-daemon-cli tonlibjson blockchain-explorer fift func validator-engine validator-engine-console create-state generate-random-id dht-server lite-client

View file

@ -2,12 +2,13 @@ FROM ubuntu:20.04
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build pkg-config
WORKDIR /
ARG BRANCH
RUN git clone --recurse-submodules https://github.com/ton-blockchain/ton.git && cd ton && git checkout $BRANCH
ARG REPO
RUN git clone --recurse-submodules https://github.com/$REPO && cd ton && git checkout $BRANCH
WORKDIR /ton
RUN mkdir /ton/build

View file

@ -2,12 +2,13 @@ FROM ubuntu:22.04
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build
RUN apt install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git curl libreadline-dev ccache libmicrohttpd-dev ninja-build pkg-config
WORKDIR /
ARG BRANCH
RUN git clone --recurse-submodules https://github.com/ton-blockchain/ton.git && cd ton && git checkout $BRANCH
ARG REPO
RUN git clone --recurse-submodules https://github.com/$REPO && cd ton && git checkout $BRANCH
WORKDIR /ton
RUN mkdir /ton/build

View file

@ -1,50 +1,48 @@
# The script build funcfift compiler to WASM
# The script builds funcfift compiler to WASM
# dependencies:
#sudo apt-get install -y build-essential git make cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip nodejs
#sudo apt-get install -y build-essential git make cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip nodejs libevent-dev
export CC=$(which clang)
export CXX=$(which clang++)
export CCACHE_DISABLE=1
cd ../..
rm -rf openssl zlib emsdk build
echo `pwd`
git clone https://github.com/openssl/openssl.git
cd openssl
git checkout OpenSSL_1_1_1j
./config
make -j4
make -j16
OPENSSL_DIR=`pwd`
cd ..
git clone https://github.com/madler/zlib.git
cd zlib
ZLIB_DIR=`pwd`
cd ..
# clone ton repo
git clone --recursive https://github.com/the-ton-tech/ton-blockchain.git
# only to generate auto-block.cpp
cd ton-blockchain
git pull
git checkout 1566a23b2bece49fd1de9ab2f35e88297d22829f
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY=/usr/lib/x86_64-linux-gnu/libz.so -DZLIB_INCLUDE_DIR=$ZLIB_DIR -DOPENSSL_ROOT_DIR=$OPENSSL_DIR -DOPENSSL_INCLUDE_DIR=$OPENSSL_DIR/include -DOPENSSL_CRYPTO_LIBRARY=$OPENSSL_DIR/libcrypto.so -DOPENSSL_SSL_LIBRARY=$OPENSSL_DIR/libssl.so ..
make -j4 fift
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY=/usr/lib/x86_64-linux-gnu/libz.so -DZLIB_INCLUDE_DIR=$ZLIB_DIR -DOPENSSL_ROOT_DIR=$OPENSSL_DIR -DOPENSSL_INCLUDE_DIR=$OPENSSL_DIR/include -DOPENSSL_CRYPTO_LIBRARY=$OPENSSL_DIR/libcrypto.so -DOPENSSL_SSL_LIBRARY=$OPENSSL_DIR/libssl.so -DTON_USE_ABSEIL=OFF ..
test $? -eq 0 || { echo "Can't configure TON build"; exit 1; }
ninja fift smc-envelope
test $? -eq 0 || { echo "Can't compile fift "; exit 1; }
rm -rf *
cd ../..
cd ..
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
./emsdk install 3.1.19
./emsdk activate 3.1.19
EMSDK_DIR=`pwd`
source $EMSDK_DIR/emsdk_env.sh
@ -55,7 +53,8 @@ export CCACHE_DISABLE=1
cd ../zlib
emconfigure ./configure --static
emmake make -j4
emmake make -j16
test $? -eq 0 || { echo "Can't compile zlib with emmake "; exit 1; }
ZLIB_DIR=`pwd`
cd ../openssl
@ -66,14 +65,13 @@ sed -i 's/CROSS_COMPILE=.*/CROSS_COMPILE=/g' Makefile
sed -i 's/-ldl//g' Makefile
sed -i 's/-O3/-Os/g' Makefile
emmake make depend
emmake make -j4
cd ../ton-blockchain
cd build
emcmake cmake -DUSE_EMSCRIPTEN=ON -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY=$ZLIB_DIR/libz.a -DZLIB_INCLUDE_DIR=$ZLIB_DIR -DOPENSSL_ROOT_DIR=$OPENSSL_DIR -DOPENSSL_INCLUDE_DIR=$OPENSSL_DIR/include -DOPENSSL_CRYPTO_LIBRARY=$OPENSSL_DIR/libcrypto.a -DOPENSSL_SSL_LIBRARY=$OPENSSL_DIR/libssl.a -DCMAKE_TOOLCHAIN_FILE=$EMSDK_DIR/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CXX_FLAGS="-pthread -sUSE_ZLIB=1" ..
emmake make -j16
test $? -eq 0 || { echo "Can't compile OpenSSL with emmake "; exit 1; }
cd ../build
emcmake cmake -DUSE_EMSCRIPTEN=ON -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY=$ZLIB_DIR/libz.a -DZLIB_INCLUDE_DIR=$ZLIB_DIR -DOPENSSL_ROOT_DIR=$OPENSSL_DIR -DOPENSSL_INCLUDE_DIR=$OPENSSL_DIR/include -DOPENSSL_CRYPTO_LIBRARY=$OPENSSL_DIR/libcrypto.a -DOPENSSL_SSL_LIBRARY=$OPENSSL_DIR/libssl.a -DCMAKE_TOOLCHAIN_FILE=$EMSDK_DIR/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CXX_FLAGS="-sUSE_ZLIB=1" ..
test $? -eq 0 || { echo "Can't configure TON with with emmake "; exit 1; }
cp -R ../crypto/smartcont ../crypto/fift/lib crypto
emmake make -j4 funcfiftlib
emmake make -j16 funcfiftlib func fift tlbc emulator-emscripten

View file

@ -11,42 +11,69 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Show all artifacts
run: |
mkdir artifacts
ls -lart artifacts
- name: Download Ubuntu x86-64 artifacts
- name: Download Linux x86-64 artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: ubuntu-compile.yml
workflow: ton-x86-64-linux.yml
path: artifacts
workflow_conclusion: success
skip_unpack: true
- name: Download Ubuntu arm64 artifacts
- name: Download and unzip Linux x86-64 artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: docker-compile-ubuntu.yml
workflow: ton-x86-64-linux.yml
path: artifacts
workflow_conclusion: success
skip_unpack: false
# - name: Download Linux arm64 artifacts
# uses: dawidd6/action-download-artifact@v2
# with:
# workflow: ton-aarch64-linux.yml
# path: artifacts
# workflow_conclusion: success
# skip_unpack: true
#
# - name: Download and unzip Linux arm64 artifacts
# uses: dawidd6/action-download-artifact@v2
# with:
# workflow: ton-aarch64-linux.yml
# path: artifacts
# workflow_conclusion: success
# skip_unpack: false
- name: Download Mac x86-64 artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: ton-x86-64-macos.yml
path: artifacts
workflow_conclusion: success
skip_unpack: true
- name: Download MacOS 11.7 artifacts
- name: Download and unzip Mac x86-64 artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: macos-11.7-compile.yml
workflow: ton-x86-64-macos.yml
path: artifacts
workflow_conclusion: success
skip_unpack: true
skip_unpack: false
- name: Download MacOS 12.6 artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: macos-12.6-compile.yml
path: artifacts
workflow_conclusion: success
skip_unpack: true
# - name: Download Mac arm64 artifacts
# uses: dawidd6/action-download-artifact@v2
# with:
# workflow: ton-aarch64-macos.yml
# path: artifacts
# workflow_conclusion: success
# skip_unpack: true
#
# - name: Download and unzip Mac arm64 artifacts
# uses: dawidd6/action-download-artifact@v2
# with:
# workflow: ton-aarch64-macos.yml
# path: artifacts
# workflow_conclusion: success
# skip_unpack: false
- name: Download Windows artifacts
uses: dawidd6/action-download-artifact@v2
@ -56,9 +83,26 @@ jobs:
workflow_conclusion: success
skip_unpack: true
- name: Download and unzip Windows artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: win-2019-compile.yml
path: artifacts
workflow_conclusion: success
skip_unpack: false
- name: Download WASM artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: ton-wasm-emscripten.yml
path: artifacts
workflow_conclusion: success
skip_unpack: true
- name: Show all artifacts
run: |
tree artifacts
# create release
@ -79,7 +123,7 @@ jobs:
- name: Get registration token
id: getRegToken
run: |
curl -X POST -H \"Accept: application/vnd.github+json\" -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/neodix42/HardTestDevelopment/actions/runners/registration-token
curl -X POST -H \"Accept: application/vnd.github+json\" -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/ton-blockchain/ton/actions/runners/registration-token
- name: Create release
id: create_release
@ -94,74 +138,250 @@ jobs:
draft: false
prerelease: false
# upload
# win
- name: Upload Windows 2019 artifacts
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-win-binaries.zip
asset_name: ton-windows-2019-x86-64.zip
asset_name: ton-win-x86-64.zip
tag: v${{ steps.date.outputs.date }}
- name: Upload MacOS 11.7 x86-64 artifacts
- name: Upload Windows 2019 single artifact - fift
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-macos-11.7.zip
asset_name: ton-macos-11.7-x86-64.zip
file: artifacts/ton-win-binaries/fift.exe
asset_name: fift.exe
tag: v${{ steps.date.outputs.date }}
- name: Upload MacOS 12.6 x86-64 artifacts
- name: Upload Windows 2019 single artifact - func
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-macos-12.6.zip
asset_name: ton-macos-12.6-x86-64.zip
file: artifacts/ton-win-binaries/func.exe
asset_name: func.exe
tag: v${{ steps.date.outputs.date }}
- name: Upload Ubuntu 18.04 x86-64 artifacts
- name: Upload Windows 2019 single artifact - lite-client
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-binaries-ubuntu-18.04.zip
asset_name: ton-ubuntu-18.04-x86-64.zip
file: artifacts/ton-win-binaries/lite-client.exe
asset_name: lite-client.exe
tag: v${{ steps.date.outputs.date }}
- name: Upload Ubuntu 20.04 x86-64 artifacts
- name: Upload Windows 2019 single artifact - rldp-http-proxy
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-binaries-ubuntu-20.04.zip
asset_name: ton-ubuntu-20.04-x86-64.zip
file: artifacts/ton-win-binaries/rldp-http-proxy.exe
asset_name: rldp-http-proxy.exe
tag: v${{ steps.date.outputs.date }}
- name: Upload Ubuntu 22.04 x86-64 artifacts
- name: Upload Windows 2019 single artifact - http-proxy
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-binaries-ubuntu-22.04.zip
asset_name: ton-ubuntu-22.04-x86-64.zip
file: artifacts/ton-win-binaries/http-proxy.exe
asset_name: http-proxy.exe
tag: v${{ steps.date.outputs.date }}
- name: Upload Ubuntu 18.04 arm64 artifacts
- name: Upload Windows 2019 single artifact - storage-daemon-cli
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-ubuntu-18.04-arm64.zip
asset_name: ton-ubuntu-18.04-arm64.zip
file: artifacts/ton-win-binaries/storage-daemon-cli.exe
asset_name: storage-daemon-cli.exe
tag: v${{ steps.date.outputs.date }}
- name: Upload Ubuntu 20.04 arm64 artifacts
- name: Upload Windows 2019 single artifact - tonlibjson
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-ubuntu-20.04-arm64.zip
asset_name: ton-ubuntu-20.04-arm64.zip
file: artifacts/ton-win-binaries/tonlibjson.dll
asset_name: tonlibjson.dll
tag: v${{ steps.date.outputs.date }}
- name: Upload Ubuntu 22.04 arm64 artifacts
- name: Upload Windows 2019 single artifact - tonlib-cli
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-ubuntu-22.04-arm64.zip
asset_name: ton-ubuntu-22.04-arm64.zip
tag: v${{ steps.date.outputs.date }}
file: artifacts/ton-win-binaries/tonlib-cli.exe
asset_name: tonlib-cli.exe
tag: v${{ steps.date.outputs.date }}
# mac x86-64
- name: Upload Mac x86-64 artifacts
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries.zip
asset_name: ton-mac-x86-64.zip
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - fift
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/fift
asset_name: fift-mac-x86-64
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - func
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/func
asset_name: func-mac-x86-64
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - lite-client
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/lite-client
asset_name: lite-client-mac-x86-64
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - rldp-http-proxy
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/rldp-http-proxy
asset_name: rldp-http-proxy-mac-x86-64
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - http-proxy
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/http-proxy
asset_name: http-proxy-mac-x86-64
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - storage-daemon-cli
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/storage-daemon-cli
asset_name: storage-daemon-cli-mac-x86-64
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - tonlibjson
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/libtonlibjson.dylib
asset_name: tonlibjson-mac-x86-64.dylib
tag: v${{ steps.date.outputs.date }}
- name: Upload Mac x86-64 single artifact - tonlib-cli
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-macos-binaries/tonlib-cli
asset_name: tonlib-cli-mac-x86-64
tag: v${{ steps.date.outputs.date }}
# linux x86-64
- name: Upload Linux x86-64 artifacts
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries.zip
asset_name: ton-linux-x86_64.zip
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - fift
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/fift
asset_name: fift-linux-x86_64
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - func
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/func
asset_name: func-linux-x86_64
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - lite-client
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/lite-client
asset_name: lite-client-linux-x86_64
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - rldp-http-proxy
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/rldp-http-proxy
asset_name: rldp-http-proxy-linux-x86_64
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - http-proxy
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/http-proxy
asset_name: http-proxy-linux-x86_64
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - storage-daemon-cli
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/storage-daemon-cli
asset_name: storage-daemon-cli-linux-x86_64
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - tonlibjson
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/libtonlibjson.so.0.5
asset_name: tonlibjson-linux-x86_64.so
tag: v${{ steps.date.outputs.date }}
- name: Upload Linux x86-64 single artifact - tonlib-cli
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-x86_64-linux-binaries/tonlib-cli
asset_name: tonlib-cli-linux-x86_64
tag: v${{ steps.date.outputs.date }}
# - name: Upload Linux arm64 artifacts
# uses: svenstaro/upload-release-action@v2
# with:
# repo_token: ${{ secrets.GITHUB_TOKEN }}
# file: artifacts/ton-aarch64-linux-binaries.zip
# asset_name: ton-linux-arm64.zip
# tag: v${{ steps.date.outputs.date }}
#
# - name: Upload Mac arm64 artifacts
# uses: svenstaro/upload-release-action@v2
# with:
# repo_token: ${{ secrets.GITHUB_TOKEN }}
# file: artifacts/ton-aarch64-macos-binaries
# asset_name: ton-mac-arm64.zip
# tag: v${{ steps.date.outputs.date }}
- name: Upload WASM artifacts
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-wasm-binaries.zip
asset_name: ton-wasm-binaries.zip
tag: v${{ steps.date.outputs.date }}

View file

@ -9,7 +9,7 @@ jobs:
max-parallel: 3
matrix:
arch: [arm64]
ver: [22.04, 18.04, 20.04 ]
ver: [22.04, 20.04 ]
runs-on: ubuntu-22.04
steps:
@ -33,7 +33,7 @@ jobs:
run: |
mkdir build-${{matrix.ver}}-${{matrix.arch}}
docker buildx build --build-arg BRANCH=${{ steps.vars.outputs.short_ref }} --platform=linux/${{matrix.arch}} --progress=plain --load . -t build-${{matrix.ver}}-${{matrix.arch}} -f .github/script/${{matrix.arch}}-${{matrix.ver}}.Dockerfile
docker buildx build --build-arg REPO=${{ github.repository }} --build-arg BRANCH=${{ steps.vars.outputs.short_ref }} --platform=linux/${{matrix.arch}} --progress=plain --load . -t build-${{matrix.ver}}-${{matrix.arch}} -f .github/script/${{matrix.arch}}-${{matrix.ver}}.Dockerfile
container_id=$(docker create --platform=linux/${{matrix.arch}} build-${{matrix.ver}}-${{matrix.arch}})
docker cp $container_id:/ton/build/dht-server/dht-server build-${{matrix.ver}}-${{matrix.arch}}/
docker cp -a $container_id:/ton/build/validator-engine/validator-engine build-${{matrix.ver}}-${{matrix.arch}}/

View file

@ -23,18 +23,19 @@ jobs:
- name: Build all
run: |
export NONINTERACTIVE=1
brew install ninja
brew install ninja libmicrohttpd pkg-config
rootPath=`pwd`
mkdir build
cd build
cmake -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$rootPath/openssl_1_1_1/include -DOPENSSL_CRYPTO_LIBRARY=$rootPath/openssl_1_1_1/libcrypto.a -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=11.7 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_BUILD_TYPE=Release ..
ninja storage-daemon storage-daemon-cli fift func tonlib tonlibjson tonlib-cli validator-engine lite-client pow-miner validator-engine-console generate-random-id json2tlo dht-server http-proxy rldp-http-proxy adnl-proxy create-state create-hardfork tlbc
ninja storage-daemon storage-daemon-cli blockchain-explorer fift func tonlib tonlibjson tonlib-cli validator-engine lite-client pow-miner validator-engine-console generate-random-id json2tlo dht-server http-proxy rldp-http-proxy adnl-proxy create-state create-hardfork tlbc
- name: Find & copy binaries
run: |
mkdir artifacts
cp build/storage/storage-daemon/storage-daemon artifacts/
cp build/storage/storage-daemon/storage-daemon-cli artifacts/
cp build/blockchain-explorer/blockchain-explorer artifacts/
cp build/crypto/fift artifacts/
cp build/crypto/func artifacts/
cp build/crypto/create-state artifacts/
@ -50,10 +51,18 @@ jobs:
cp build/utils/generate-random-id artifacts/
cp build/utils/json2tlo artifacts/
cp build/adnl/adnl-proxy artifacts/
chmod +x artifacts/*
rsync -r crypto/smartcont artifacts/
rsync -r crypto/fift/lib artifacts/
ls -laRt artifacts
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:

View file

@ -23,18 +23,19 @@ jobs:
- name: Build all
run: |
export NONINTERACTIVE=1
brew install ninja
brew install ninja libmicrohttpd pkg-config
rootPath=`pwd`
mkdir build
cd build
cmake -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$rootPath/openssl_1_1_1/include -DOPENSSL_CRYPTO_LIBRARY=$rootPath/openssl_1_1_1/libcrypto.a -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=12.6 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_BUILD_TYPE=Release ..
ninja storage-daemon storage-daemon-cli fift func tonlib tonlibjson tonlib-cli validator-engine lite-client pow-miner validator-engine-console generate-random-id json2tlo dht-server http-proxy rldp-http-proxy adnl-proxy create-state create-hardfork tlbc
ninja storage-daemon storage-daemon-cli blockchain-explorer fift func tonlib tonlibjson tonlib-cli validator-engine lite-client pow-miner validator-engine-console generate-random-id json2tlo dht-server http-proxy rldp-http-proxy adnl-proxy create-state create-hardfork tlbc
- name: Find & copy binaries
run: |
mkdir artifacts
cp build/storage/storage-daemon/storage-daemon artifacts/
cp build/storage/storage-daemon/storage-daemon-cli artifacts/
cp build/blockchain-explorer/blockchain-explorer artifacts/
cp build/crypto/fift artifacts/
cp build/crypto/func artifacts/
cp build/crypto/create-state artifacts/
@ -50,10 +51,18 @@ jobs:
cp build/utils/generate-random-id artifacts/
cp build/utils/json2tlo artifacts/
cp build/adnl/adnl-proxy artifacts/
chmod +x artifacts/*
rsync -r crypto/smartcont artifacts/
rsync -r crypto/fift/lib artifacts/
ls -laRt artifacts
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:

48
.github/workflows/ton-aarch64-linux.yml vendored Normal file
View file

@ -0,0 +1,48 @@
name: "TON aarch64 Linux binaries"
on: [workflow_dispatch,workflow_call]
jobs:
build:
runs-on: ubuntu-22.04
steps:
- run: |
sudo apt update
sudo apt install -y apt-utils
sudo apt install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: cachix/install-nix-action@v18
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Compile
run: nix build .?submodules=1#packages.aarch64-linux.ton-oldglibc_staticbinaries --print-build-logs --system aarch64-linux -o result-aarch64
- name: Copy binaries
run: |
ls -lart
mkdir artifacts
cp $PWD/result-aarch64-linux/bin/* artifacts/
chmod +x artifacts/*
cp $PWD/result-aarch64-linux/lib/libtonlibjson.so.0.5 artifacts/
cp -R crypto/smartcont artifacts/
cp -R crypto/fift/lib artifacts/
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:
name: ton-aarch64-linux-binaries
path: artifacts

45
.github/workflows/ton-aarch64-macos.yml vendored Normal file
View file

@ -0,0 +1,45 @@
name: "TON aarch64 macOS binaries"
on: [workflow_dispatch,workflow_call]
jobs:
build:
runs-on: macos-12
steps:
- run: brew install qemu
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: cachix/install-nix-action@v18
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Compile
run: nix build .?submodules=1#packages.aarch64-darwin.ton-staticbin-dylib --print-build-logs -o result-aarch64-darwin
- name: Copy binaries
run: |
ls -lart
mkdir artifacts
cp $PWD/result-aarch64-darwin/bin/* artifacts/
chmod +x artifacts/*
cp $PWD/result-aarch64-darwin/lib/libtonlibjson* artifacts/
cp -R crypto/smartcont artifacts/
cp -R crypto/fift/lib artifacts/
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:
name: ton-aarch64-macos-binaries
path: artifacts

View file

@ -5,7 +5,7 @@ on: [push,workflow_dispatch,workflow_call]
jobs:
build:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
steps:
- name: Check out repository

View file

@ -0,0 +1,40 @@
name: TON WASM Compile
on: [push,workflow_dispatch,workflow_call]
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Install libraries
run: |
sudo apt update
sudo apt install -y build-essential git make cmake ninja-build clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip nodejs
- name: Configure & Build
run: |
cd .github/script
./fift-func-wasm-build-ubuntu.sh
- name: Find & copy binaries
run: |
mkdir artifacts
ls build/crypto
cp build/crypto/fift* artifacts
cp build/crypto/func* artifacts
cp build/crypto/tlbc* artifacts
cp build/emulator/emulator-emscripten* artifacts
cp -R crypto/smartcont artifacts
cp -R crypto/fift/lib artifacts
- name: Upload artifacts
uses: actions/upload-artifact@master
with:
name: ton-wasm-binaries
path: artifacts

47
.github/workflows/ton-x86-64-linux.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: "TON x86_64 Linux binaries"
on: [push,workflow_dispatch,workflow_call]
jobs:
build:
runs-on: ubuntu-22.04
steps:
- run: |
sudo apt update
sudo apt install -y apt-utils
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: cachix/install-nix-action@v18
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Compile
run: nix build .?submodules=1#packages.x86_64-linux.ton-oldglibc_staticbinaries --print-build-logs --system x86_64-linux -o result-x86_64
- name: Copy binaries
run: |
ls -lart
mkdir artifacts
cp $PWD/result-x86_64/bin/* artifacts/
chmod +x artifacts/*
cp $PWD/result-x86_64/lib/libtonlibjson.so.0.5 artifacts/
cp -R crypto/smartcont artifacts/
cp -R crypto/fift/lib artifacts/
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:
name: ton-x86_64-linux-binaries
path: artifacts

43
.github/workflows/ton-x86-64-macos.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: "TON x86_64 macOS binaries"
on: [push,workflow_dispatch,workflow_call]
jobs:
build:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: cachix/install-nix-action@v18
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Compile
run: nix build .?submodules=1#packages.x86_64-darwin.ton-staticbin-dylib --print-build-logs -o result-x86_64-darwin
- name: Copy binaries
run: |
ls -lart
mkdir artifacts
cp $PWD/result-x86_64-darwin/bin/* artifacts/
chmod +x artifacts/*
cp $PWD/result-x86_64-darwin/lib/libtonlibjson.dylib artifacts/
cp -R crypto/smartcont artifacts/
cp -R crypto/fift/lib artifacts/
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:
name: ton-x86_64-macos-binaries
path: artifacts

View file

@ -1,11 +1,11 @@
name: Ubuntu 18.04 Compile
name: Ubuntu 22.04 Compile
on: [push,workflow_dispatch,workflow_call]
jobs:
build:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
steps:
- name: Check out repository
@ -36,9 +36,17 @@ jobs:
run: |
mkdir artifacts
cp build/storage/storage-daemon/storage-daemon build/storage/storage-daemon/storage-daemon-cli build/crypto/fift build/crypto/tlbc build/crypto/func build/crypto/create-state build/validator-engine-console/validator-engine-console build/tonlib/tonlib-cli build/tonlib/libtonlibjson.so.0.5 build/http/http-proxy build/rldp-http-proxy/rldp-http-proxy build/dht-server/dht-server build/lite-client/lite-client build/validator-engine/validator-engine build/utils/generate-random-id build/utils/json2tlo build/adnl/adnl-proxy artifacts
chmod +x artifacts/*
cp -R crypto/smartcont artifacts/
cp -R crypto/fift/lib artifacts/
- name: Simple binaries test
run: |
artifacts/validator-engine -V
artifacts/lite-client -V
artifacts/fift -V
artifacts/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:

View file

@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04]
os: [ubuntu-20.04, ubuntu-22.04]
runs-on: ${{ matrix.os }}
steps:
@ -39,8 +39,17 @@ jobs:
run: |
mkdir artifacts-${{ matrix.os }}
cp build-${{ matrix.os }}/storage/storage-daemon/storage-daemon build-${{ matrix.os }}/storage/storage-daemon/storage-daemon-cli build-${{ matrix.os }}/crypto/fift build-${{ matrix.os }}/crypto/tlbc build-${{ matrix.os }}/crypto/func build-${{ matrix.os }}/crypto/create-state build-${{ matrix.os }}/validator-engine-console/validator-engine-console build-${{ matrix.os }}/tonlib/tonlib-cli build-${{ matrix.os }}/tonlib/libtonlibjson.so.0.5 build-${{ matrix.os }}/http/http-proxy build-${{ matrix.os }}/rldp-http-proxy/rldp-http-proxy build-${{ matrix.os }}/dht-server/dht-server build-${{ matrix.os }}/lite-client/lite-client build-${{ matrix.os }}/validator-engine/validator-engine build-${{ matrix.os }}/utils/generate-random-id build-${{ matrix.os }}/utils/json2tlo build-${{ matrix.os }}/adnl/adnl-proxy artifacts-${{ matrix.os }}
chmod +x artifacts-${{ matrix.os }}/*
cp -R crypto/smartcont artifacts-${{ matrix.os }}
cp -R crypto/fift/lib artifacts-${{ matrix.os }}
- name: Simple binaries test
run: |
artifacts-${{ matrix.os }}/validator-engine -V
artifacts-${{ matrix.os }}/lite-client -V
artifacts-${{ matrix.os }}/fift -V
artifacts-${{ matrix.os }}/func -V
- name: Upload artifacts
uses: actions/upload-artifact@master
with:

View file

@ -28,7 +28,10 @@ jobs:
path: zlib
- name: Setup msbuild.exe
uses: microsoft/setup-msbuild@v1.0.2
uses: microsoft/setup-msbuild@v1.1
- name: Install Pkg-config Lite
run: choco install pkgconfiglite
- name: Compile zlib Win64
run: |
@ -57,7 +60,7 @@ jobs:
mkdir build
cd build
cmake -DREADLINE_INCLUDE_DIR=%root%\readline-5.0-1-lib\include\readline -DREADLINE_LIBRARY=%root%\readline-5.0-1-lib\lib\readline.lib -DZLIB_FOUND=1 -DMHD_FOUND=1 -DMHD_LIBRARY=%root%\libmicrohttpd-0.9.75-w32-bin\x86_64\VS2019\Release-static\libmicrohttpd.lib -DMHD_INCLUDE_DIR=%root%\libmicrohttpd-0.9.75-w32-bin\x86_64\VS2019\Release-static -DZLIB_INCLUDE_DIR=%root%\zlib -DZLIB_LIBRARY=%root%\zlib\contrib\vstudio\vc14\x64\ZlibStatReleaseWithoutAsm\zlibstat.lib -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=%root%/openssl-1.1/x64/include -DOPENSSL_CRYPTO_LIBRARY=%root%/openssl-1.1/x64/lib/libcrypto.lib -DCMAKE_CXX_FLAGS="/DTD_WINDOWS=1 /EHsc /bigobj /W0" ..
cmake --build . --target storage-daemon storage-daemon-cli fift func tonlib tonlibjson tonlib-cli validator-engine lite-client pow-miner validator-engine-console generate-random-id json2tlo dht-server http-proxy rldp-http-proxy adnl-proxy create-state create-hardfork --config Release
cmake --build . --target storage-daemon storage-daemon-cli blockchain-explorer fift func tonlib tonlibjson tonlib-cli validator-engine lite-client pow-miner validator-engine-console generate-random-id json2tlo dht-server http-proxy rldp-http-proxy adnl-proxy create-state create-hardfork --config Release
- name: Show executables
run: |
@ -68,8 +71,7 @@ jobs:
- name: Check if validator-engine.exe exists
run: |
set root=%cd%
copy %root%\build\validator-engine\Release\validator-engine.exe test
copy %cd%\build\validator-engine\Release\validator-engine.exe test
- name: Find & copy binaries
run: |
@ -77,9 +79,9 @@ jobs:
mkdir artifacts\smartcont
mkdir artifacts\lib
for %%I in (build\storage\storage-daemon\Release\storage-daemon.exe build\storage\storage-daemon\Release\storage-daemon-cli.exe build\crypto\Release\fift.exe build\crypto\Release\tlbc.exe build\crypto\Release\func.exe build\crypto\Release\create-state.exe build\validator-engine-console\Release\validator-engine-console.exe build\tonlib\Release\tonlib-cli.exe build\tonlib\Release\tonlibjson.dll build\http\Release\http-proxy.exe build\rldp-http-proxy\Release\rldp-http-proxy.exe build\dht-server\Release\dht-server.exe build\lite-client\Release\lite-client.exe build\validator-engine\Release\validator-engine.exe build\utils\Release\generate-random-id.exe build\utils\Release\json2tlo.exe build\adnl\Release\adnl-proxy.exe) do copy %%I artifacts\
for %%I in (build\storage\storage-daemon\Release\storage-daemon.exe build\storage\storage-daemon\Release\storage-daemon-cli.exe build\blockchain-explorer\blockchain-explorer.exe build\crypto\Release\fift.exe build\crypto\Release\tlbc.exe build\crypto\Release\func.exe build\crypto\Release\create-state.exe build\validator-engine-console\Release\validator-engine-console.exe build\tonlib\Release\tonlib-cli.exe build\tonlib\Release\tonlibjson.dll build\http\Release\http-proxy.exe build\rldp-http-proxy\Release\rldp-http-proxy.exe build\dht-server\Release\dht-server.exe build\lite-client\Release\lite-client.exe build\validator-engine\Release\validator-engine.exe build\utils\Release\generate-random-id.exe build\utils\Release\json2tlo.exe build\adnl\Release\adnl-proxy.exe) do copy %%I artifacts\
xcopy /e /k /h /i crypto\smartcont artifacts\smartcont
xcopy /e /k /h /i crypto\fift\lib artifacts\lib
xcopy /e /k /h /i crypto\fift\lib artifacts\lib
- name: Upload artifacts
uses: actions/upload-artifact@master

View file

@ -20,19 +20,6 @@ find_library(
set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR})
set(MHD_LIBRARIES ${MHD_LIBRARY})
# debug library on windows
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
# official MHD project actually uses _d suffix
if (MSVC)
find_library(
MHD_LIBRARY_DEBUG
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d
DOC "mhd debug library"
)
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(mhd DEFAULT_MSG MHD_INCLUDE_DIR MHD_LIBRARY)
find_package_handle_standard_args(MHD DEFAULT_MSG MHD_INCLUDE_DIR MHD_LIBRARY)
mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY)

View file

@ -108,7 +108,8 @@ set(TON_ARCH "native" CACHE STRING "Architecture, will be passed to -march=")
#BEGIN M1 support
EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE )
if ((ARCHITECTURE MATCHES "arm64") AND (CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
if ((ARCHITECTURE MATCHES "arm64") AND (CMAKE_SYSTEM_NAME STREQUAL "Darwin") AND
(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)) # only clang 13+ supports cpu=apple-m1
set(TON_ARCH "apple-m1")
endif()
#END M1 support
@ -135,7 +136,16 @@ set(CRC32C_BUILD_BENCHMARKS OFF CACHE BOOL "Build CRC32C's benchmarks")
set(CRC32C_USE_GLOG OFF CACHE BOOL "Build CRC32C's tests with Google Logging")
set(CRC32C_INSTALL OFF CACHE BOOL "Install CRC32C's header and library")
message("Add crc32c")
add_subdirectory(third-party/crc32c EXCLUDE_FROM_ALL)
if (NOT MSVC)
set(OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# fix aarch64 build @ crc32c/src/crc32c_arm64_linux_check.h
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=address")
add_subdirectory(third-party/crc32c EXCLUDE_FROM_ALL)
set(CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS})
unset(OLD_CMAKE_CXX_FLAGS)
else()
add_subdirectory(third-party/crc32c EXCLUDE_FROM_ALL)
endif()
set(CRC32C_FOUND 1)
if (TON_USE_ROCKSDB)
@ -198,6 +208,7 @@ include(CheckCXXCompilerFlag)
set(CMAKE_THREAD_PREFER_PTHREAD ON)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(ZLIB REQUIRED)
if (TON_ARCH AND NOT MSVC)
@ -383,6 +394,7 @@ add_subdirectory(tl-utils)
add_subdirectory(adnl)
add_subdirectory(crypto)
add_subdirectory(lite-client)
add_subdirectory(emulator)
#BEGIN tonlib
add_subdirectory(tonlib)

View file

@ -1,43 +1,16 @@
## 05.2022 Update
* Initial synchronization improved: adjusted timeouts for state download and the way of choosing which state to download. Nodes with low network speed and/or bad connectivity will synchronize faster and consistently.
* Improved peer-to-peer network stability and DDoS resistance: now peers will only relay valid messages to the network. Large messages, which require splitting for relaying, will be retranslated as well, but only after the node gets all parts, and reassembles and checks them. Validators may sign certificates for network peers, which allow relaying large messages by parts without checks. It is used now by validators to faster relay new blocks. Sign and import certificate commands are exposed via `validator-engine-console`.
* Fixed some rare edge cases in TVM arithmetic operations related to big numbers (`2**63+`)
* Improved fixes used to combat wrong activate-destruct-activate contract behavior last November.
* Improved tonlib: support libraries (with client-side caching), getmethods completely fill c7 register, getmethods support slice arguments, improved messages listing for transactions, added extended block header params, added getConfig method.
* RocksDB updated to a newer version.
* Improved persistent state serialization: memory usage during serialization was optimized; the start of serialization on different nodes was sparsed.
* FunC update: support for string literals and constants (including precompiled constant expressions), semver, `include` expressions.
* Fixed rarely manifested bugs in `Asm.fif`.
* LiteClient supports key as cli parameter.
* Improved Liteserver DoS resistance for running getmethods.
## 03.2023 Update
1. Improvement of ADNL connection stability
2. Transaction emulator support and getAccountStateByTransaction method
3. Fixes of typos, undefined behavior and timer warnings
4. Handling incorrect integer literal values in funC; funC version bumped to 0.4.2
5. FunC Mathlib
Besides the work of the core team, this update is based on the efforts of @tvorogme (added support for slice arguments and noted bugs in Asm.fif), @akifoq (fixed bug in Asm.fif), @cryshado (noted strange behavior of LS, which, upon inspection, turned out to be a vector of DoS attack).
## 08.2022 Update
* Blockchain state serialization now works via separate db-handler which simplfies memory clearing after serialization
* CellDB now works asynchronously which substantially increase database access throughput
* Abseil-cpp and crc32 updated: solve issues with compilation on recent OS distributives
* Fixed a series of UBs and issues for exotic endianness hosts
* Added detailed network stats for overlays (can be accessed via `validator-console`)
* Improved auto-builds for wide range of systems.
* Added extended error information for unaccepted external messages: `exit_code` and TVM trace (where applicable).
* [Improved catchain DoS resistance](https://github.com/ton-blockchain/ton/blob/master/doc/catchain-dos.md)
* A series of FunC improvements, summarized [here](https://github.com/ton-blockchain/ton/pull/378)
#### Update delay
Update coincided with persistent state serialization event which lead to block production speed deterioration (issue substantially mitigated in update itself). This phenomena was aggravated by the fact that after update some validators lost ability to participate in block creation. The last was caused by threshold based hardcoded protocol version bump, where threshold was set in such manner (based on block height with value higher than 9m), that it eluded detection in private net tests. The update was temporarily paused and resumed after persistent state serialization ended and issues with block creation were resolved.
Besides the work of the core team, this update is based on the efforts of @awesome-doge (help with abseil-cpp upgrade), @rec00rsiff (noted issues for exotic endianess and implemented network stats) and third-party security auditors.
## 10.2022 Update
* Added extended block creation and general perfomance stats gathering
* Forbidden report data on blocks not committed to the master chain for LS
* Improved debug in TVM
* FunC 0.3.0: multi-line asms, bitwise operations for constants, duplication of identical definition for constants and asms now allowed
* New tonlib methods: sendMessageReturnHash, getTransactionsV2, getMasterchainBlockSignatures, getShardBlockProof, getLibraries.
* Fixed bugs related to invalid TVM output (c4, c5, libaries) and non-validated network data; avoided too deep recursion in libraries loading
* Fixed multiple undefined behavior issues
* Added build of FunC and Fift to WASM
Besides the work of the core team, this update is based on the efforts of @tvorogme (debug improvements), @AlexeyFSL (WASM builds) and third-party security auditors.
## 01.2023 Update
1. Added ConfigParam 44: `SuspendedAddressList`. Upon being set this config suspends initialisation of **uninit** addresses from the list for given time.
2. FunC: `v0.4.1` added pragmas for precise control of computation order
3. FunC: fixed compiler crashes for some exotic inputs
4. FunC: added legacy tester, a collection of smart-contracts which is used to check whether compilator update change compilation result
5. Improved archive manager: proper handling of recently garbage-collected blocks
## 12.2022 Update
Node update:
@ -54,9 +27,46 @@ Node update:
Besides the work of the core team, this update is based on the efforts of @vtamara (help with abseil-cpp upgrade), @krigga(in-place modification of global variables) and third-party security auditors.
## 01.2023 Update
1. Added ConfigParam 44: `SuspendedAddressList`. Upon being set this config suspends initialisation of **uninit** addresses from the list for given time.
2. FunC: `v0.4.1` added pragmas for precise control of computation order
3. FunC: fixed compiler crashes for some exotic inputs
4. FunC: added legacy tester, a collection of smart-contracts which is used to check whether compilator update change compilation result
5. Improved archive manager: proper handling of recently garbage-collected blocks
## 10.2022 Update
* Added extended block creation and general perfomance stats gathering
* Forbidden report data on blocks not committed to the master chain for LS
* Improved debug in TVM
* FunC 0.3.0: multi-line asms, bitwise operations for constants, duplication of identical definition for constants and asms now allowed
* New tonlib methods: sendMessageReturnHash, getTransactionsV2, getMasterchainBlockSignatures, getShardBlockProof, getLibraries.
* Fixed bugs related to invalid TVM output (c4, c5, libaries) and non-validated network data; avoided too deep recursion in libraries loading
* Fixed multiple undefined behavior issues
* Added build of FunC and Fift to WASM
Besides the work of the core team, this update is based on the efforts of @tvorogme (debug improvements), @AlexeyFSL (WASM builds) and third-party security auditors.
## 08.2022 Update
* Blockchain state serialization now works via separate db-handler which simplfies memory clearing after serialization
* CellDB now works asynchronously which substantially increase database access throughput
* Abseil-cpp and crc32 updated: solve issues with compilation on recent OS distributives
* Fixed a series of UBs and issues for exotic endianness hosts
* Added detailed network stats for overlays (can be accessed via `validator-console`)
* Improved auto-builds for wide range of systems.
* Added extended error information for unaccepted external messages: `exit_code` and TVM trace (where applicable).
* [Improved catchain DoS resistance](https://github.com/ton-blockchain/ton/blob/master/doc/catchain-dos.md)
* A series of FunC improvements, summarized [here](https://github.com/ton-blockchain/ton/pull/378)
#### Update delay
Update coincided with persistent state serialization event which lead to block production speed deterioration (issue substantially mitigated in update itself). This phenomena was aggravated by the fact that after update some validators lost ability to participate in block creation. The last was caused by threshold based hardcoded protocol version bump, where threshold was set in such manner (based on block height with value higher than 9m), that it eluded detection in private net tests. The update was temporarily paused and resumed after persistent state serialization ended and issues with block creation were resolved.
Besides the work of the core team, this update is based on the efforts of @awesome-doge (help with abseil-cpp upgrade), @rec00rsiff (noted issues for exotic endianess and implemented network stats) and third-party security auditors.
## 05.2022 Update
* Initial synchronization improved: adjusted timeouts for state download and the way of choosing which state to download. Nodes with low network speed and/or bad connectivity will synchronize faster and consistently.
* Improved peer-to-peer network stability and DDoS resistance: now peers will only relay valid messages to the network. Large messages, which require splitting for relaying, will be retranslated as well, but only after the node gets all parts, and reassembles and checks them. Validators may sign certificates for network peers, which allow relaying large messages by parts without checks. It is used now by validators to faster relay new blocks. Sign and import certificate commands are exposed via `validator-engine-console`.
* Fixed some rare edge cases in TVM arithmetic operations related to big numbers (`2**63+`)
* Improved fixes used to combat wrong activate-destruct-activate contract behavior last November.
* Improved tonlib: support libraries (with client-side caching), getmethods completely fill c7 register, getmethods support slice arguments, improved messages listing for transactions, added extended block header params, added getConfig method.
* RocksDB updated to a newer version.
* Improved persistent state serialization: memory usage during serialization was optimized; the start of serialization on different nodes was sparsed.
* FunC update: support for string literals and constants (including precompiled constant expressions), semver, `include` expressions.
* Fixed rarely manifested bugs in `Asm.fif`.
* LiteClient supports key as cli parameter.
* Improved Liteserver DoS resistance for running getmethods.
Besides the work of the core team, this update is based on the efforts of @tvorogme (added support for slice arguments and noted bugs in Asm.fif), @akifoq (fixed bug in Asm.fif), @cryshado (noted strange behavior of LS, which, upon inspection, turned out to be a vector of DoS attack).

View file

@ -1,21 +1,28 @@
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://ton.org/download/ton_logo_dark_background.svg">
<img alt="TON logo" src="https://ton.org/download/ton_logo_light_background.svg">
</picture>
<a href="https://ton.org">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://ton.org/download/ton_logo_dark_background.svg">
<img alt="TON logo" src="https://ton.org/download/ton_logo_light_background.svg">
</picture>
</a>
<h3>Reference implementation of TON Node and tools</h3>
<hr/>
</div>
##
[![TON Overflow Group][ton-overflow-badge]][ton-overflow-url]
[![Stack Overflow Group][stack-overflow-badge]][stack-overflow-url]
[![Telegram Foundation Group][telegram-foundation-badge]][telegram-foundation-url]
[![Telegram Community Chat][telegram-tondev-badge]][telegram-tondev-url]
[![Telegram Community Group][telegram-community-badge]][telegram-community-url]
[![Telegram Foundation Group][telegram-foundation-badge]][telegram-foundation-url]
[![Twitter Group][twitter-badge]][twitter-url]
[telegram-foundation-badge]: https://img.shields.io/badge/-TON%20Foundation-2CA5E0?style=flat&logo=telegram&logoColor=white
[telegram-community-badge]: https://img.shields.io/badge/-TON%20Community-2CA5E0?style=flat&logo=telegram&logoColor=white
[telegram-foundation-badge]: https://img.shields.io/badge/TON%20Foundation-2CA5E0?logo=telegram&logoColor=white&style=flat
[telegram-community-badge]: https://img.shields.io/badge/TON%20Community-2CA5E0?logo=telegram&logoColor=white&style=flat
[telegram-tondev-badge]: https://img.shields.io/badge/chat-TONDev-2CA5E0?logo=telegram&logoColor=white&style=flat
[telegram-foundation-url]: https://t.me/tonblockchain
[telegram-community-url]: https://t.me/toncoin
[telegram-tondev-url]: https://t.me/tondev_eng
[twitter-badge]: https://img.shields.io/twitter/follow/ton_blockchain
[twitter-url]: https://twitter.com/ton_blockchain
[stack-overflow-badge]: https://img.shields.io/badge/-Stack%20Overflow-FE7A16?style=flat&logo=stack-overflow&logoColor=white
@ -27,6 +34,15 @@
Main TON monorepo, which includes the code of the node/validator, lite-client, tonlib, FunC compiler, etc.
## The Open Network
__The Open Network (TON)__ is a fast, secure, scalable blockchain focused on handling _millions of transactions per second_ (TPS) with the goal of reaching hundreds of millions of blockchain users.
- To learn more about different aspects of TON blockchain and its underlying ecosystem check [documentation](ton.org/docs)
- To run node, validator or lite-server check [Participate section](https://ton.org/docs/participate/nodes/run-node)
- To develop decentralised apps check [Tutorials](https://ton.org/docs/develop/smart-contracts/), [FunC docs](https://ton.org/docs/develop/func/overview) and [DApp tutorials](https://ton.org/docs/develop/dapps/)
- To work on TON check [wallets](https://ton.app/wallets), [explorers](https://ton.app/explorers), [DEXes](https://ton.app/dex) and [utilities](https://ton.app/utilities)
- To interact with TON check [APIs](https://ton.org/docs/develop/dapps/apis/)
## Updates flow:
* **master branch** - mainnet is running on this stable branch.

View file

@ -99,6 +99,8 @@ target_link_libraries(adnl-pong PUBLIC tdactor ton_crypto tl_api tdnet common
add_library(adnltest STATIC ${ADNL_TEST_SOURCE})
target_include_directories(adnltest PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnltest PUBLIC adnl )
install(TARGETS adnl-proxy RUNTIME DESTINATION bin)
endif()
#END internal

View file

@ -68,7 +68,9 @@ void AdnlPeerPairImpl::alarm() {
}
if (retry_send_at_ && retry_send_at_.is_in_past()) {
retry_send_at_ = td::Timestamp::never();
send_messages_in(std::move(pending_messages_), false);
auto messages = std::move(pending_messages_);
pending_messages_.clear();
send_messages_in(std::move(messages), true);
}
alarm_timestamp().relax(next_dht_query_at_);
alarm_timestamp().relax(next_db_update_at_);
@ -113,6 +115,8 @@ void AdnlPeerPairImpl::discover() {
}
void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
last_received_packet_ = td::Timestamp::now();
try_reinit_at_ = td::Timestamp::never();
request_reverse_ping_after_ = td::Timestamp::in(15.0);
auto d = Adnl::adnl_start_time();
if (packet.dst_reinit_date() > d) {
@ -307,7 +311,9 @@ void AdnlPeerPairImpl::send_messages_in(std::vector<OutboundAdnlMessage> message
}
}
if (!channel_ready_) {
bool try_reinit = try_reinit_at_ && try_reinit_at_.is_in_past();
bool via_channel = channel_ready_ && !try_reinit;
if (!via_channel) {
packet.set_reinit_date(Adnl::adnl_start_time(), reinit_date_);
packet.set_source(local_id_);
}
@ -330,7 +336,7 @@ void AdnlPeerPairImpl::send_messages_in(std::vector<OutboundAdnlMessage> message
packet.run_basic_checks().ensure();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), conn, id = print_id(),
via_channel = channel_ready_](td::Result<AdnlPacket> res) {
via_channel](td::Result<AdnlPacket> res) {
if (res.is_error()) {
LOG(ERROR) << id << ": dropping OUT message: error while creating packet: " << res.move_as_error();
} else {
@ -339,9 +345,9 @@ void AdnlPeerPairImpl::send_messages_in(std::vector<OutboundAdnlMessage> message
});
td::actor::send_closure(local_actor_, &AdnlLocalId::update_packet, std::move(packet),
!channel_ready_ && ack_seqno_ == 0 && in_seqno_ == 0, !channel_ready_,
(!channel_ready_ && ack_seqno_ == 0 && in_seqno_ == 0) || try_reinit, !via_channel,
(first || s + addr_list_max_size() <= AdnlNetworkManager::get_mtu())
? peer_recv_addr_list_version_
? (try_reinit ? 0 : peer_recv_addr_list_version_)
: 0x7fffffff,
(first || s + 2 * addr_list_max_size() <= AdnlNetworkManager::get_mtu())
? peer_recv_priority_addr_list_version_
@ -388,6 +394,9 @@ void AdnlPeerPairImpl::send_messages(std::vector<OutboundAdnlMessage> messages)
void AdnlPeerPairImpl::send_packet_continue(AdnlPacket packet, td::actor::ActorId<AdnlNetworkConnection> conn,
bool via_channel) {
if (!try_reinit_at_ && last_received_packet_ < td::Timestamp::in(-5.0)) {
try_reinit_at_ = td::Timestamp::in(10.0);
}
packet.run_basic_checks().ensure();
auto B = serialize_tl_object(packet.tl(), true);
if (via_channel) {
@ -784,7 +793,9 @@ void AdnlPeerPairImpl::Conn::create_conn(td::actor::ActorId<AdnlPeerPairImpl> pe
void AdnlPeerPairImpl::conn_change_state(AdnlConnectionIdShort id, bool ready) {
if (ready) {
if (pending_messages_.size() > 0) {
send_messages_in(std::move(pending_messages_), true);
auto messages = std::move(pending_messages_);
pending_messages_.clear();
send_messages_in(std::move(messages), true);
}
}
}
@ -933,6 +944,7 @@ void AdnlPeerPairImpl::got_data_from_dht(td::Result<AdnlNode> R) {
CHECK(dht_query_active_);
dht_query_active_ = false;
next_dht_query_at_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
alarm_timestamp().relax(next_dht_query_at_);
if (R.is_error()) {
VLOG(ADNL_INFO) << this << ": dht query failed: " << R.move_as_error();
return;

View file

@ -254,6 +254,9 @@ class AdnlPeerPairImpl : public AdnlPeerPair {
td::Timestamp next_db_update_at_ = td::Timestamp::never();
td::Timestamp retry_send_at_ = td::Timestamp::never();
td::Timestamp last_received_packet_ = td::Timestamp::never();
td::Timestamp try_reinit_at_ = td::Timestamp::never();
bool has_reverse_addr_ = false;
td::Timestamp request_reverse_ping_after_ = td::Timestamp::now();
bool request_reverse_ping_active_ = false;

View file

@ -1,22 +1,28 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
option(NIX "Use \"ON\" for a static build." OFF)
find_package(MHD)
if (MHD_FOUND)
set(BLOCHAIN_EXPLORER_SOURCE
set(BLOCHAIN_EXPLORER_SOURCE
blockchain-explorer.cpp
blockchain-explorer.hpp
blockchain-explorer-http.cpp
blockchain-explorer-http.hpp
blockchain-explorer-query.cpp
blockchain-explorer-query.hpp
)
)
add_executable(blockchain-explorer ${BLOCHAIN_EXPLORER_SOURCE})
add_executable(blockchain-explorer ${BLOCHAIN_EXPLORER_SOURCE})
if (NIX)
find_package(PkgConfig REQUIRED)
pkg_check_modules(MHD libmicrohttpd)
target_include_directories(blockchain-explorer PUBLIC ${MHD_INCLUDE_DIRS} ${MHD_STATIC_INCLUDE_DIRS})
target_link_libraries(blockchain-explorer tdutils tdactor adnllite tl_lite_api tl-lite-utils ton_crypto ton_block ${MHD_LIBRARIES} ${MHD_STATIC_LIBRARIES})
else()
find_package(MHD)
target_include_directories(blockchain-explorer PUBLIC ${MHD_INCLUDE_DIRS})
target_link_libraries(blockchain-explorer tdutils tdactor adnllite tl_lite_api tl-lite-utils
ton_crypto ton_block ${MHD_LIBRARY})
target_link_libraries(blockchain-explorer tdutils tdactor adnllite tl_lite_api tl-lite-utils ton_crypto ton_block ${MHD_LIBRARIES})
endif()
install(TARGETS blockchain-explorer RUNTIME DESTINATION bin)

View file

@ -274,6 +274,10 @@ add_library(ton_crypto STATIC ${TON_CRYPTO_SOURCE})
target_include_directories(ton_crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(ton_crypto PUBLIC ${OPENSSL_CRYPTO_LIBRARY} tdutils tddb_utils)
if (USE_EMSCRIPTEN)
target_link_options(ton_crypto PRIVATE -fexceptions)
target_compile_options(ton_crypto PRIVATE -fexceptions)
endif()
if (NOT WIN32)
find_library(DL dl)
if (DL)
@ -484,6 +488,6 @@ if (WINGETOPT_FOUND)
target_link_libraries_system(test-weight-distr wingetopt)
endif()
install(TARGETS fift func pow-miner RUNTIME DESTINATION bin)
install(TARGETS fift func create-state tlbc RUNTIME DESTINATION bin)
install(DIRECTORY fift/lib/ DESTINATION lib/fift)
install(DIRECTORY smartcont DESTINATION share/ton)

View file

@ -624,6 +624,7 @@ void BlockDbImpl::get_block_by_id(ton::BlockId blk_id, bool need_data, td::Promi
}
}
promise(it->second);
return;
}
promise(td::Status::Error(-666, "block not found in database"));
}
@ -642,6 +643,7 @@ void BlockDbImpl::get_state_by_id(ton::BlockId blk_id, bool need_data, td::Promi
}
}
promise(it->second);
return;
}
if (zerostate.not_null() && blk_id == zerostate->blk.id) {
LOG(DEBUG) << "get_state_by_id(): zerostate requested";
@ -666,6 +668,7 @@ void BlockDbImpl::get_out_queue_info_by_id(ton::BlockId blk_id, td::Promise<td::
if (it == state_info.end()) {
promise(td::Status::Error(
-666, std::string{"cannot obtain output queue info for block "} + blk_id.to_str() + " : cannot load state"));
return;
}
if (it->second->data.is_null()) {
LOG(DEBUG) << "loading data for state " << blk_id.to_str();
@ -679,6 +682,7 @@ void BlockDbImpl::get_out_queue_info_by_id(ton::BlockId blk_id, td::Promise<td::
if (it2 == block_info.end()) {
promise(td::Status::Error(-666, std::string{"cannot obtain output queue info for block "} + blk_id.to_str() +
" : cannot load block description"));
return;
}
vm::StaticBagOfCellsDbLazy::Options options;
auto res = vm::StaticBagOfCellsDbLazy::create(it->second->data.clone(), options);
@ -707,10 +711,12 @@ void BlockDbImpl::get_out_queue_info_by_id(ton::BlockId blk_id, td::Promise<td::
if (it->second->blk.root_hash != state_root->get_hash().bits()) {
promise(td::Status::Error(
-668, std::string{"state for block "} + blk_id.to_str() + " is invalid : state root hash mismatch"));
return;
}
vm::CellSlice cs = vm::load_cell_slice(state_root);
if (!cs.have(64, 1) || cs.prefetch_ulong(32) != 0x9023afde) {
promise(td::Status::Error(-668, std::string{"state for block "} + blk_id.to_str() + " is invalid"));
return;
}
auto out_queue_info = cs.prefetch_ref();
promise(Ref<OutputQueueInfoDescr>{true, blk_id, it2->second->blk.root_hash.cbits(), state_root->get_hash().bits(),
@ -758,6 +764,7 @@ void BlockDbImpl::save_new_block(ton::BlockIdExt id, td::BufferSlice data, int a
auto save_res = save_db_file(id.file_hash, data, FMode::chk_if_exists | FMode::overwrite | FMode::chk_file_hash);
if (save_res.is_error()) {
promise(std::move(save_res));
return;
}
auto sz = data.size();
auto lev = bb.alloc<log::NewBlock>(id.id, id.root_hash, id.file_hash, data.size(), authority & 0xff);
@ -780,6 +787,7 @@ void BlockDbImpl::save_new_state(ton::BlockIdExt id, td::BufferSlice data, int a
auto save_res = save_db_file(id.file_hash, data, FMode::chk_if_exists | FMode::overwrite | FMode::chk_file_hash);
if (save_res.is_error()) {
promise(std::move(save_res));
return;
}
auto sz = data.size();
auto lev = bb.alloc<log::NewState>(id.id, id.root_hash, id.file_hash, data.size(), authority & 0xff);

View file

@ -1000,7 +1000,7 @@ bool Account::skip_copy_depth_balance(vm::CellBuilder& cb, vm::CellSlice& cs) co
}
const Account t_Account, t_AccountE{true};
const RefTo<Account> t_Ref_Account;
const RefTo<Account> t_Ref_AccountE{true};
bool ShardAccount::extract_account_state(Ref<vm::CellSlice> cs_ref, Ref<vm::Cell>& acc_state) {
if (cs_ref.is_null()) {

View file

@ -536,7 +536,7 @@ struct Account final : TLB_Complex {
};
extern const Account t_Account, t_AccountE;
extern const RefTo<Account> t_Ref_Account;
extern const RefTo<Account> t_Ref_AccountE;
struct AccountStatus final : TLB {
enum { acc_state_uninit, acc_state_frozen, acc_state_active, acc_state_nonexist };
@ -572,7 +572,7 @@ struct ShardAccount final : TLB_Complex {
return cs.advance_ext(0x140, 1);
}
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
return cs.advance(0x140) && t_Ref_Account.validate_skip(ops, cs, weak);
return cs.advance(0x140) && t_Ref_AccountE.validate_skip(ops, cs, weak);
}
static bool unpack(vm::CellSlice& cs, Record& info) {
return info.unpack(cs);

View file

@ -366,7 +366,7 @@ trans_merge_install$0111 split_info:SplitMergeInfo
smc_info#076ef1ea actions:uint16 msgs_sent:uint16
unixtime:uint32 block_lt:uint64 trans_lt:uint64
rand_seed:bits256 balance_remaining:CurrencyCollection
myself:MsgAddressInt = SmartContractInfo;
myself:MsgAddressInt global_config:(Maybe Cell) = SmartContractInfo;
//
//
out_list_empty$_ = OutList 0;

View file

@ -362,7 +362,7 @@ td::Status BlockProofLink::validate(td::uint32* save_utime) const {
if (to.seqno()) {
TRY_STATUS(check_block_header(vd_root, to));
if (!(tlb::unpack_cell(vd_root, blk) && tlb::unpack_cell(blk.info, info))) {
return td::Status::Error("cannot unpack header for block "s + from.to_str());
return td::Status::Error("cannot unpack header for block "s + to.to_str());
}
if (info.key_block != is_key) {
return td::Status::Error(PSTRING() << "incorrect is_key_block value " << is_key << " for destination block "

View file

@ -308,7 +308,7 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, R
THRERR("cannot create smart-contract AccountStorage");
Ref<vm::DataCell> storage = cb.finalize();
vm::CellStorageStat stats;
PDO(stats.compute_used_storage(Ref<vm::Cell>(storage)));
PDO(stats.compute_used_storage(Ref<vm::Cell>(storage)).is_ok());
if (verbosity > 2) {
std::cerr << "storage is:\n";
vm::load_cell_slice(storage).print_rec(std::cerr);

View file

@ -632,7 +632,6 @@ class Config {
static td::Result<std::vector<int>> unpack_param_dict(vm::Dictionary& dict);
static td::Result<std::vector<int>> unpack_param_dict(Ref<vm::Cell> dict_root);
protected:
Config(int _mode) : mode(_mode) {
config_addr.set_zero();
}

View file

@ -20,6 +20,7 @@
#include "block/block.h"
#include "block/block-parse.h"
#include "block/block-auto.h"
#include "crypto/openssl/rand.hpp"
#include "td/utils/bits.h"
#include "td/utils/uint128.h"
#include "ton/ton-shard.h"
@ -513,6 +514,7 @@ td::RefInt256 Account::compute_storage_fees(ton::UnixTime now, const std::vector
return StoragePrices::compute_storage_fees(now, pricing, storage_stat, last_paid, is_special, is_masterchain());
}
namespace transaction {
Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now,
Ref<vm::Cell> _inmsg)
: trans_type(ttype)
@ -588,15 +590,19 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig*
in_msg_type = 2;
in_msg_extern = true;
// compute forwarding fees for this external message
vm::CellStorageStat sstat; // for message size
sstat.compute_used_storage(cs); // message body
sstat.bits -= cs.size(); // bits in the root cells are free
sstat.cells--; // the root cell itself is not counted as a cell
vm::CellStorageStat sstat; // for message size
auto cell_info = sstat.compute_used_storage(cs).move_as_ok(); // message body
sstat.bits -= cs.size(); // bits in the root cells are free
sstat.cells--; // the root cell itself is not counted as a cell
LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
if (sstat.bits > cfg->size_limits.max_msg_bits || sstat.cells > cfg->size_limits.max_msg_cells) {
LOG(DEBUG) << "inbound external message too large, invalid";
return false;
}
if (cell_info.max_merkle_depth > max_allowed_merkle_depth) {
LOG(DEBUG) << "inbound external message has too big merkle depth, invalid";
return false;
}
// fetch message pricing info
CHECK(cfg);
const MsgPrices& msg_prices = cfg->fetch_msg_prices(account.is_masterchain());
@ -745,6 +751,7 @@ bool Transaction::prepare_credit_phase() {
total_fees += std::move(collected);
return true;
}
} // namespace transaction
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit,
td::RefInt256& delete_due_limit) {
@ -837,6 +844,7 @@ td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
: td::rshift(gas_price256 * (gas_used - flat_gas_limit), 16, 1) + flat_gas_price;
}
namespace transaction {
bool Transaction::compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig& cfg) {
// Compute gas limits
if (account.is_special) {
@ -1057,13 +1065,21 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
std::unique_ptr<StringLoggerTail> logger;
auto vm_log = vm::VmLog();
if (cfg.with_vm_log) {
logger = std::make_unique<StringLoggerTail>();
size_t log_max_size = cfg.vm_log_verbosity > 0 ? 1024 * 1024 : 256;
logger = std::make_unique<StringLoggerTail>(log_max_size);
vm_log.log_interface = logger.get();
vm_log.log_options = td::LogOptions(VERBOSITY_NAME(DEBUG), true, false);
if (cfg.vm_log_verbosity > 1) {
vm_log.log_mask |= vm::VmLog::ExecLocation;
if (cfg.vm_log_verbosity > 2) {
vm_log.log_mask |= vm::VmLog::DumpStack | vm::VmLog::GasRemaining;
}
}
}
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
vm.set_max_data_depth(cfg.max_vm_data_depth);
vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
vm.set_chksig_always_succeed(cfg.ignore_chksig);
// vm.incr_stack_trace(1); // enable stack dump after each step
LOG(DEBUG) << "starting VM";
@ -1145,19 +1161,20 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
ap.reserved_balance.set_zero();
td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
auto enforce_state_size_limits = [&]() {
auto enforce_state_limits = [&]() {
if (account.is_special) {
return true;
}
if (!check_state_size_limit(cfg)) {
auto S = check_state_limits(cfg);
if (S.is_error()) {
// Rollback changes to state, fail action phase
LOG(INFO) << "Account state size exceeded limits";
LOG(INFO) << "Account state size exceeded limits: " << S.move_as_error();
new_storage_stat.clear();
new_code = old_code;
new_data = old_data;
new_library = old_library;
ap.result_code = 50;
ap.state_size_too_big = true;
ap.state_exceeds_limits = true;
return false;
}
return true;
@ -1238,8 +1255,8 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
ap.no_funds = true;
}
LOG(DEBUG) << "invalid action " << ap.result_arg << " in action list: error code " << ap.result_code;
// This is reuqired here because changes to libraries are applied even if actipn phase fails
enforce_state_size_limits();
// This is reuqired here because changes to libraries are applied even if action phase fails
enforce_state_limits();
return true;
}
}
@ -1249,7 +1266,7 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
new_code = ap.new_code;
}
new_data = compute_phase->new_data; // tentative persistent data update applied
if (!enforce_state_size_limits()) {
if (!enforce_state_limits()) {
return true;
}
@ -1322,8 +1339,8 @@ int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, c
return 41;
}
vm::CellStorageStat sstat;
sstat.compute_used_storage(lib_ref);
if (sstat.cells > cfg.size_limits.max_library_cells) {
auto cell_info = sstat.compute_used_storage(lib_ref).move_as_ok();
if (sstat.cells > cfg.size_limits.max_library_cells || cell_info.max_merkle_depth > max_allowed_merkle_depth) {
return 43;
}
vm::CellBuilder cb;
@ -1338,6 +1355,7 @@ int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, c
ap.spec_actions++;
return 0;
}
} // namespace transaction
// msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
// ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms
@ -1372,6 +1390,7 @@ td::RefInt256 MsgPrices::get_next_part(td::RefInt256 total) const {
return (std::move(total) * next_frac) >> 16;
}
namespace transaction {
bool Transaction::check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const {
int t = (int)src_addr->prefetch_ulong(2);
if (!t && src_addr->size_ext() == 2) {
@ -1594,16 +1613,27 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
// compute size of message
vm::CellStorageStat sstat; // for message size
// preliminary storage estimation of the resulting message
sstat.add_used_storage(msg.init, true, 3); // message init
sstat.add_used_storage(msg.body, true, 3); // message body (the root cell itself is not counted)
unsigned max_merkle_depth = 0;
auto add_used_storage = [&](const auto& x, unsigned skip_root_count) {
if (x.not_null()) {
auto res = sstat.add_used_storage(x, true, skip_root_count).move_as_ok();
max_merkle_depth = std::max(max_merkle_depth, res.max_merkle_depth);
}
};
add_used_storage(msg.init, 3); // message init
add_used_storage(msg.body, 3); // message body (the root cell itself is not counted)
if (!ext_msg) {
sstat.add_used_storage(info.value->prefetch_ref());
add_used_storage(info.value->prefetch_ref(), 0);
}
LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
if (sstat.bits > cfg.size_limits.max_msg_bits || sstat.cells > cfg.size_limits.max_msg_cells) {
LOG(DEBUG) << "message too large, invalid";
return skip_invalid ? 0 : 40;
}
if (max_merkle_depth > max_allowed_merkle_depth) {
LOG(DEBUG) << "message has too big merkle depth, invalid";
return skip_invalid ? 0 : 40;
}
// compute forwarding fees
auto fees_c = msg_prices.compute_fwd_ihr_fees(sstat.cells, sstat.bits, info.ihr_disabled);
@ -1855,7 +1885,7 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap,
return 0;
}
bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) {
td::Status Transaction::check_state_limits(const ActionPhaseConfig& cfg) {
auto cell_equal = [](const td::Ref<vm::Cell>& a, const td::Ref<vm::Cell>& b) -> bool {
if (a.is_null()) {
return b.is_null();
@ -1867,21 +1897,36 @@ bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) {
};
if (cell_equal(account.code, new_code) && cell_equal(account.data, new_data) &&
cell_equal(account.library, new_library)) {
return true;
return td::Status::OK();
}
// new_storage_stat is used here beause these stats will be reused in compute_state()
new_storage_stat.limit_cells = cfg.size_limits.max_acc_state_cells;
new_storage_stat.limit_bits = cfg.size_limits.max_acc_state_bits;
new_storage_stat.add_used_storage(new_code);
new_storage_stat.add_used_storage(new_data);
new_storage_stat.add_used_storage(new_library);
td::Timer timer;
auto add_used_storage = [&](const td::Ref<vm::Cell>& cell) -> td::Status {
if (cell.not_null()) {
TRY_RESULT(res, new_storage_stat.add_used_storage(cell));
if (res.max_merkle_depth > max_allowed_merkle_depth) {
return td::Status::Error("too big merkle depth");
}
}
return td::Status::OK();
};
TRY_STATUS(add_used_storage(new_code));
TRY_STATUS(add_used_storage(new_data));
TRY_STATUS(add_used_storage(new_library));
if (timer.elapsed() > 0.1) {
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
}
if (acc_status == Account::acc_active) {
new_storage_stat.clear_limit();
} else {
new_storage_stat.clear();
}
return new_storage_stat.cells <= cfg.size_limits.max_acc_state_cells &&
new_storage_stat.bits <= cfg.size_limits.max_acc_state_bits;
new_storage_stat.bits <= cfg.size_limits.max_acc_state_bits
? td::Status::OK()
: td::Status::Error("state too big");
}
bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
@ -1978,6 +2023,7 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
bp.ok = true;
return true;
}
} // namespace transaction
/*
*
@ -2033,6 +2079,7 @@ static td::optional<vm::CellStorageStat> try_update_storage_stat(const vm::CellS
return new_stat;
}
namespace transaction {
bool Transaction::compute_state() {
if (new_total_state.not_null()) {
return true;
@ -2108,7 +2155,7 @@ bool Transaction::compute_state() {
stats = new_stats.unwrap();
} else {
td::Timer timer;
CHECK(stats.add_used_storage(Ref<vm::Cell>(storage)));
stats.add_used_storage(Ref<vm::Cell>(storage)).ensure();
if (timer.elapsed() > 0.1) {
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
}
@ -2460,6 +2507,7 @@ void Transaction::extract_out_msgs(std::vector<LtCellRef>& list) {
list.emplace_back(start_lt + i + 1, std::move(out_msgs[i]));
}
}
} // namespace transaction
void Account::push_transaction(Ref<vm::Cell> trans_root, ton::LogicalTime trans_lt) {
transactions.emplace_back(trans_lt, std::move(trans_root));
@ -2503,4 +2551,82 @@ bool Account::libraries_changed() const {
}
}
td::Status FetchConfigParams::fetch_config_params(const block::Config& config,
Ref<vm::Cell>* old_mparams,
std::vector<block::StoragePrices>* storage_prices,
block::StoragePhaseConfig* storage_phase_cfg,
td::BitArray<256>* rand_seed,
block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg,
td::RefInt256* masterchain_create_fee,
td::RefInt256* basechain_create_fee,
ton::WorkchainId wc,
ton::UnixTime now) {
*old_mparams = config.get_config_param(9);
{
auto res = config.get_storage_prices();
if (res.is_error()) {
return res.move_as_error();
}
*storage_prices = res.move_as_ok();
}
if (rand_seed->is_zero()) {
// generate rand seed
prng::rand_gen().strong_rand_bytes(rand_seed->data(), 32);
LOG(DEBUG) << "block random seed set to " << rand_seed->to_hex();
}
TRY_RESULT(size_limits, config.get_size_limits_config());
{
// compute compute_phase_cfg / storage_phase_cfg
auto cell = config.get_config_param(wc == ton::masterchainId ? 20 : 21);
if (cell.is_null()) {
return td::Status::Error(-668, "cannot fetch current gas prices and limits from masterchain configuration");
}
if (!compute_phase_cfg->parse_GasLimitsPrices(std::move(cell), storage_phase_cfg->freeze_due_limit,
storage_phase_cfg->delete_due_limit)) {
return td::Status::Error(-668, "cannot unpack current gas prices and limits from masterchain configuration");
}
compute_phase_cfg->block_rand_seed = *rand_seed;
compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth;
compute_phase_cfg->global_config = config.get_root_cell();
compute_phase_cfg->suspended_addresses = config.get_suspended_addresses(now);
}
{
// compute action_phase_cfg
block::gen::MsgForwardPrices::Record rec;
auto cell = config.get_config_param(24);
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
return td::Status::Error(-668, "cannot fetch masterchain message transfer prices from masterchain configuration");
}
action_phase_cfg->fwd_mc =
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
cell = config.get_config_param(25);
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
return td::Status::Error(-668, "cannot fetch standard message transfer prices from masterchain configuration");
}
action_phase_cfg->fwd_std =
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
action_phase_cfg->workchains = &config.get_workchain_list();
action_phase_cfg->bounce_msg_body = (config.has_capability(ton::capBounceMsgBody) ? 256 : 0);
action_phase_cfg->size_limits = size_limits;
}
{
// fetch block_grams_created
auto cell = config.get_config_param(14);
if (cell.is_null()) {
*basechain_create_fee = *masterchain_create_fee = td::zero_refint();
} else {
block::gen::BlockCreateFees::Record create_fees;
if (!(tlb::unpack_cell(cell, create_fees) &&
block::tlb::t_Grams.as_integer_to(create_fees.masterchain_block_fee, *masterchain_create_fee) &&
block::tlb::t_Grams.as_integer_to(create_fees.basechain_block_fee, *basechain_create_fee))) {
return td::Status::Error(-668, "cannot unpack BlockCreateFees from configuration parameter #14");
}
}
}
return td::Status::OK();
}
} // namespace block

View file

@ -35,7 +35,10 @@ using td::Ref;
using LtCellRef = std::pair<ton::LogicalTime, Ref<vm::Cell>>;
struct Account;
namespace transaction {
struct Transaction;
} // namespace transaction
struct CollatorError {
std::string msg;
@ -106,9 +109,11 @@ struct ComputePhaseConfig {
std::unique_ptr<vm::Dictionary> libraries;
Ref<vm::Cell> global_config;
td::BitArray<256> block_rand_seed;
bool ignore_chksig{false};
bool with_vm_log{false};
td::uint16 max_vm_data_depth = 512;
std::unique_ptr<vm::Dictionary> suspended_addresses;
int vm_log_verbosity = 0;
ComputePhaseConfig(td::uint64 _gas_price = 0, td::uint64 _gas_limit = 0, td::uint64 _gas_credit = 0)
: gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_gas_limit), gas_credit(_gas_credit) {
compute_threshold();
@ -186,7 +191,7 @@ struct ActionPhase {
bool code_changed{false};
bool action_list_invalid{false};
bool acc_delete_req{false};
bool state_size_too_big{false};
bool state_exceeds_limits{false};
enum { acst_unchanged = 0, acst_frozen = 2, acst_deleted = 3 };
int acc_status_change{acst_unchanged};
td::RefInt256 total_fwd_fees; // all fees debited from the account
@ -273,7 +278,7 @@ struct Account {
bool create_account_block(vm::CellBuilder& cb); // stores an AccountBlock with all transactions
protected:
friend struct Transaction;
friend struct transaction::Transaction;
bool set_split_depth(int split_depth);
bool check_split_depth(int split_depth) const;
bool forget_split_depth();
@ -288,7 +293,9 @@ struct Account {
bool compute_my_addr(bool force = false);
};
namespace transaction {
struct Transaction {
static constexpr unsigned max_allowed_merkle_depth = 2;
enum {
tr_none,
tr_ord,
@ -354,7 +361,7 @@ struct Transaction {
std::vector<Ref<vm::Cell>> compute_vm_libraries(const ComputePhaseConfig& cfg);
bool prepare_compute_phase(const ComputePhaseConfig& cfg);
bool prepare_action_phase(const ActionPhaseConfig& cfg);
bool check_state_size_limit(const ActionPhaseConfig& cfg);
td::Status check_state_limits(const ActionPhaseConfig& cfg);
bool prepare_bounce_phase(const ActionPhaseConfig& cfg);
bool compute_state();
bool serialize();
@ -390,5 +397,20 @@ struct Transaction {
bool serialize_bounce_phase(vm::CellBuilder& cb);
bool unpack_msg_state(bool lib_only = false);
};
} // namespace transaction
struct FetchConfigParams {
static td::Status fetch_config_params(const block::Config& config,
Ref<vm::Cell>* old_mparams,
std::vector<block::StoragePrices>* storage_prices,
StoragePhaseConfig* storage_phase_cfg,
td::BitArray<256>* rand_seed,
ComputePhaseConfig* compute_phase_cfg,
ActionPhaseConfig* action_phase_cfg,
td::RefInt256* masterchain_create_fee,
td::RefInt256* basechain_create_fee,
ton::WorkchainId wc,
ton::UnixTime now);
};
} // namespace block

View file

@ -486,7 +486,7 @@ void interpret_make_pop(vm::Stack& stack) {
}
void interpret_is_string(vm::Stack& stack) {
stack.push_bool(stack.pop().type() == vm::StackEntry::t_string);
stack.push_bool(stack.pop_chk().type() == vm::StackEntry::t_string);
}
int make_utf8_char(char buffer[4], int x) {
@ -1285,7 +1285,7 @@ void interpret_atom_anon(vm::Stack& stack) {
}
void interpret_is_atom(vm::Stack& stack) {
stack.push_bool(stack.pop().is_atom());
stack.push_bool(stack.pop_chk().is_atom());
}
bool are_eqv(vm::StackEntry x, vm::StackEntry y) {
@ -1307,11 +1307,13 @@ bool are_eqv(vm::StackEntry x, vm::StackEntry y) {
}
void interpret_is_eqv(vm::Stack& stack) {
stack.check_underflow(2);
auto y = stack.pop(), x = stack.pop();
stack.push_bool(are_eqv(std::move(x), std::move(y)));
}
void interpret_is_eq(vm::Stack& stack) {
stack.check_underflow(2);
auto y = stack.pop(), x = stack.pop();
stack.push_bool(x == y);
}

View file

@ -158,9 +158,9 @@ void VarDescr::set_const(td::RefInt256 value) {
} else if (s > 0) {
val |= _NonZero | _Pos | _Finite;
} else if (!s) {
if (*int_const == 1) {
val |= _Bit;
}
//if (*int_const == 1) {
// val |= _Bit;
//}
val |= _Zero | _Neg | _Pos | _Finite | _Bool | _Bit;
}
if (val & _Finite) {

View file

@ -735,7 +735,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
res.emplace_back(i);
}
AsmOpList tmp;
func->compile(tmp, res, args); // abstract interpretation of res := f (args)
func->compile(tmp, res, args, where); // abstract interpretation of res := f (args)
int j = 0;
for (var_idx_t i : left) {
values.add_newval(i).set_value(res[j++]);

View file

@ -112,6 +112,12 @@ def run_runner():
s = s.strip()
return int(s)
def get_version():
res = subprocess.run([FUNC_EXECUTABLE, "-s"], capture_output=True, timeout=10)
if res.returncode != 0:
raise ExecutionError(str(res.stderr, "utf-8"))
s = str(res.stdout, "utf-8")
return s.strip()
success = 0
for ti, t in enumerate(tests):
@ -142,4 +148,6 @@ for ti, t in enumerate(tests):
#exit(2)
print(" OK ", file=sys.stderr)
print(get_version())
print("Done: Success %d, Error: %d"%(success, len(tests)-success), file=sys.stderr)

View file

@ -82,9 +82,10 @@ SymDef* define_builtin_const(std::string name, TypeExpr* const_type, Args&&... a
define_builtin_func(name, TypeExpr::new_map(TypeExpr::new_unit(), const_type), std::forward<Args>(args)...));
}
bool SymValAsmFunc::compile(AsmOpList& dest, std::vector<VarDescr>& out, std::vector<VarDescr>& in) const {
bool SymValAsmFunc::compile(AsmOpList& dest, std::vector<VarDescr>& out, std::vector<VarDescr>& in,
const SrcLocation& where) const {
if (simple_compile) {
return dest.append(simple_compile(out, in));
return dest.append(simple_compile(out, in, where));
} else if (ext_compile) {
return ext_compile(dest, out, in);
} else {
@ -423,11 +424,14 @@ AsmOp push_const(td::RefInt256 x) {
return AsmOp::IntConst(std::move(x));
}
AsmOp compile_add(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_add(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) {
r.set_const(x.int_const + y.int_const);
if (!r.int_const->is_valid()) {
throw src::ParseError(where, "integer overflow");
}
x.unused();
y.unused();
return push_const(r.int_const);
@ -462,11 +466,14 @@ AsmOp compile_add(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("ADD", 2);
}
AsmOp compile_sub(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_sub(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) {
r.set_const(x.int_const - y.int_const);
if (!r.int_const->is_valid()) {
throw src::ParseError(where, "integer overflow");
}
x.unused();
y.unused();
return push_const(r.int_const);
@ -492,11 +499,14 @@ AsmOp compile_sub(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("SUB", 2);
}
AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 1);
VarDescr &r = res[0], &x = args[0];
if (x.is_int_const()) {
r.set_const(-x.int_const);
if (!r.int_const->is_valid()) {
throw src::ParseError(where, "integer overflow");
}
x.unused();
return push_const(r.int_const);
}
@ -504,7 +514,7 @@ AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("NEGATE", 1);
}
AsmOp compile_and(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_and(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) {
@ -517,7 +527,7 @@ AsmOp compile_and(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("AND", 2);
}
AsmOp compile_or(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_or(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) {
@ -530,7 +540,7 @@ AsmOp compile_or(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("OR", 2);
}
AsmOp compile_xor(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_xor(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) {
@ -543,7 +553,7 @@ AsmOp compile_xor(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("XOR", 2);
}
AsmOp compile_not(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_not(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 1);
VarDescr &r = res[0], &x = args[0];
if (x.is_int_const()) {
@ -555,9 +565,12 @@ AsmOp compile_not(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("NOT", 1);
}
AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y, const SrcLocation& where) {
if (x.is_int_const() && y.is_int_const()) {
r.set_const(x.int_const * y.int_const);
if (!r.int_const->is_valid()) {
throw src::ParseError(where, "integer overflow");
}
x.unused();
y.unused();
return push_const(r.int_const);
@ -620,23 +633,23 @@ AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
return exec_op("MUL", 2);
}
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
return compile_mul_internal(res[0], args[0], args[1]);
return compile_mul_internal(res[0], args[0], args[1], where);
}
AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (y.is_int_const()) {
auto yv = y.int_const->to_long();
if (yv < 0 || yv > 256) {
r.set_const_nan();
x.unused();
y.unused();
return push_const(r.int_const);
throw src::ParseError(where, "lshift argument is out of range");
} else if (x.is_int_const()) {
r.set_const(x.int_const << (int)yv);
if (!r.int_const->is_valid()) {
throw src::ParseError(where, "integer overflow");
}
x.unused();
y.unused();
return push_const(r.int_const);
@ -661,22 +674,20 @@ AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
}
if (xv == -1) {
x.unused();
return exec_op("NEGPOW2", 1);
return exec_op("-1 PUSHINT SWAP LSHIFT", 1);
}
}
return exec_op("LSHIFT", 2);
}
AsmOp compile_rshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
AsmOp compile_rshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where,
int round_mode) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (y.is_int_const()) {
auto yv = y.int_const->to_long();
if (yv < 0 || yv > 256) {
r.set_const_nan();
x.unused();
y.unused();
return push_const(r.int_const);
throw src::ParseError(where, "rshift argument is out of range");
} else if (x.is_int_const()) {
r.set_const(td::rshift(x.int_const, (int)yv, round_mode));
x.unused();
@ -699,9 +710,12 @@ AsmOp compile_rshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, in
return exec_op(rshift, 2);
}
AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, int round_mode) {
AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, const SrcLocation& where, int round_mode) {
if (x.is_int_const() && y.is_int_const()) {
r.set_const(div(x.int_const, y.int_const, round_mode));
if (!r.int_const->is_valid()) {
throw src::ParseError(where, *y.int_const == 0 ? "division by zero" : "integer overflow");
}
x.unused();
y.unused();
return push_const(r.int_const);
@ -709,10 +723,7 @@ AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, int round_mode
r.val = emulate_div(x.val, y.val);
if (y.is_int_const()) {
if (*y.int_const == 0) {
x.unused();
y.unused();
r.set_const(div(y.int_const, y.int_const));
return push_const(r.int_const);
throw src::ParseError(where, "division by zero");
}
if (*y.int_const == 1 && x.always_finite()) {
y.unused();
@ -739,16 +750,20 @@ AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, int round_mode
return exec_op(op, 2);
}
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where, int round_mode) {
assert(res.size() == 1 && args.size() == 2);
return compile_div_internal(res[0], args[0], args[1], round_mode);
return compile_div_internal(res[0], args[0], args[1], where, round_mode);
}
AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const src::SrcLocation& where,
int round_mode) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) {
r.set_const(mod(x.int_const, y.int_const, round_mode));
if (!r.int_const->is_valid()) {
throw src::ParseError(where, *y.int_const == 0 ? "division by zero" : "integer overflow");
}
x.unused();
y.unused();
return push_const(r.int_const);
@ -756,10 +771,7 @@ AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
r.val = emulate_mod(x.val, y.val);
if (y.is_int_const()) {
if (*y.int_const == 0) {
x.unused();
y.unused();
r.set_const(mod(y.int_const, y.int_const));
return push_const(r.int_const);
throw src::ParseError(where, "division by zero");
}
if ((*y.int_const == 1 || *y.int_const == -1) && x.always_finite()) {
x.unused();
@ -784,11 +796,15 @@ AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
return exec_op(op, 2);
}
AsmOp compile_muldiv(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
AsmOp compile_muldiv(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where,
int round_mode) {
assert(res.size() == 1 && args.size() == 3);
VarDescr &r = res[0], &x = args[0], &y = args[1], &z = args[2];
if (x.is_int_const() && y.is_int_const() && z.is_int_const()) {
r.set_const(muldiv(x.int_const, y.int_const, z.int_const, round_mode));
if (!r.int_const->is_valid()) {
throw src::ParseError(where, *z.int_const == 0 ? "division by zero" : "integer overflow");
}
x.unused();
y.unused();
z.unused();
@ -806,24 +822,20 @@ AsmOp compile_muldiv(std::vector<VarDescr>& res, std::vector<VarDescr>& args, in
r.val = emulate_div(emulate_mul(x.val, y.val), z.val);
if (z.is_int_const()) {
if (*z.int_const == 0) {
x.unused();
y.unused();
z.unused();
r.set_const(div(z.int_const, z.int_const));
return push_const(r.int_const);
throw src::ParseError(where, "division by zero");
}
if (*z.int_const == 1) {
z.unused();
return compile_mul_internal(r, x, y);
return compile_mul_internal(r, x, y, where);
}
}
if (y.is_int_const() && *y.int_const == 1) {
y.unused();
return compile_div_internal(r, x, z, round_mode);
return compile_div_internal(r, x, z, where, round_mode);
}
if (x.is_int_const() && *x.int_const == 1) {
x.unused();
return compile_div_internal(r, y, z, round_mode);
return compile_div_internal(r, y, z, where, round_mode);
}
if (z.is_int_const()) {
int k = is_pos_pow2(z.int_const);
@ -954,7 +966,7 @@ AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, i
return exec_op(cmp_names[mode], 2);
}
AsmOp compile_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
assert(res.empty() && args.size() == 1);
VarDescr& x = args[0];
if (x.is_int_const() && x.int_const->unsigned_fits_bits(11)) {
@ -986,7 +998,7 @@ AsmOp compile_cond_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args
}
}
AsmOp compile_throw_arg(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_throw_arg(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
assert(res.empty() && args.size() == 2);
VarDescr &x = args[1];
if (x.is_int_const() && x.int_const->unsigned_fits_bits(11)) {
@ -1077,7 +1089,7 @@ AsmOp compile_fetch_slice(std::vector<VarDescr>& res, std::vector<VarDescr>& arg
}
// <type> <type>_at(tuple t, int index) asm "INDEXVAR";
AsmOp compile_tuple_at(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_tuple_at(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
assert(args.size() == 2 && res.size() == 1);
auto& y = args[1];
if (y.is_int_const() && y.int_const >= 0 && y.int_const < 16) {
@ -1088,7 +1100,7 @@ AsmOp compile_tuple_at(std::vector<VarDescr>& res, std::vector<VarDescr>& args)
}
// int null?(X arg)
AsmOp compile_is_null(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
AsmOp compile_is_null(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
assert(args.size() == 1 && res.size() == 1);
auto &x = args[0], &r = res[0];
if (x.always_null() || x.always_not_null()) {
@ -1149,21 +1161,21 @@ void define_builtins() {
define_builtin_func("_-_", arith_bin_op, compile_sub);
define_builtin_func("-_", arith_un_op, compile_negate);
define_builtin_func("_*_", arith_bin_op, compile_mul);
define_builtin_func("_/_", arith_bin_op, std::bind(compile_div, _1, _2, -1));
define_builtin_func("_~/_", arith_bin_op, std::bind(compile_div, _1, _2, 0));
define_builtin_func("_^/_", arith_bin_op, std::bind(compile_div, _1, _2, 1));
define_builtin_func("_%_", arith_bin_op, std::bind(compile_mod, _1, _2, -1));
define_builtin_func("_~%_", arith_bin_op, std::bind(compile_mod, _1, _2, 0));
define_builtin_func("_^%_", arith_bin_op, std::bind(compile_mod, _1, _2, 1));
define_builtin_func("_/_", arith_bin_op, std::bind(compile_div, _1, _2, _3, -1));
define_builtin_func("_~/_", arith_bin_op, std::bind(compile_div, _1, _2, _3, 0));
define_builtin_func("_^/_", arith_bin_op, std::bind(compile_div, _1, _2, _3, 1));
define_builtin_func("_%_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, -1));
define_builtin_func("_~%_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, 0));
define_builtin_func("_^%_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, 1));
define_builtin_func("_/%_", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2));
define_builtin_func("divmod", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2));
define_builtin_func("~divmod", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2));
define_builtin_func("moddiv", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2), {}, {1, 0});
define_builtin_func("~moddiv", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2), {}, {1, 0});
define_builtin_func("_<<_", arith_bin_op, compile_lshift);
define_builtin_func("_>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, -1));
define_builtin_func("_~>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, 0));
define_builtin_func("_^>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, 1));
define_builtin_func("_>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, -1));
define_builtin_func("_~>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, 0));
define_builtin_func("_^>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, 1));
define_builtin_func("_&_", arith_bin_op, compile_and);
define_builtin_func("_|_", arith_bin_op, compile_or);
define_builtin_func("_^_", arith_bin_op, compile_xor);
@ -1171,22 +1183,22 @@ void define_builtins() {
define_builtin_func("^_+=_", arith_bin_op, compile_add);
define_builtin_func("^_-=_", arith_bin_op, compile_sub);
define_builtin_func("^_*=_", arith_bin_op, compile_mul);
define_builtin_func("^_/=_", arith_bin_op, std::bind(compile_div, _1, _2, -1));
define_builtin_func("^_~/=_", arith_bin_op, std::bind(compile_div, _1, _2, 0));
define_builtin_func("^_^/=_", arith_bin_op, std::bind(compile_div, _1, _2, 1));
define_builtin_func("^_%=_", arith_bin_op, std::bind(compile_mod, _1, _2, -1));
define_builtin_func("^_~%=_", arith_bin_op, std::bind(compile_mod, _1, _2, 0));
define_builtin_func("^_^%=_", arith_bin_op, std::bind(compile_mod, _1, _2, 1));
define_builtin_func("^_/=_", arith_bin_op, std::bind(compile_div, _1, _2, _3, -1));
define_builtin_func("^_~/=_", arith_bin_op, std::bind(compile_div, _1, _2, _3, 0));
define_builtin_func("^_^/=_", arith_bin_op, std::bind(compile_div, _1, _2, _3, 1));
define_builtin_func("^_%=_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, -1));
define_builtin_func("^_~%=_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, 0));
define_builtin_func("^_^%=_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, 1));
define_builtin_func("^_<<=_", arith_bin_op, compile_lshift);
define_builtin_func("^_>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, -1));
define_builtin_func("^_~>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, 0));
define_builtin_func("^_^>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, 1));
define_builtin_func("^_>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, -1));
define_builtin_func("^_~>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, 0));
define_builtin_func("^_^>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, 1));
define_builtin_func("^_&=_", arith_bin_op, compile_and);
define_builtin_func("^_|=_", arith_bin_op, compile_or);
define_builtin_func("^_^=_", arith_bin_op, compile_xor);
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, -1));
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 0));
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 1));
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, -1));
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, 0));
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, 1));
define_builtin_func("muldivmod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2));
define_builtin_func("_==_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 2));
define_builtin_func("_!=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 5));
@ -1232,16 +1244,18 @@ void define_builtins() {
AsmOp::Custom("s0 DUMP", 1, 1), true);
define_builtin_func("~strdump", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))),
AsmOp::Custom("STRDUMP", 1, 1), true);
define_builtin_func("run_method0", TypeExpr::new_map(Int, Unit),
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 0, false); }, true);
define_builtin_func("run_method1", TypeExpr::new_forall({X}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X}), Unit)),
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 1, false); }, {1, 0}, {}, true);
define_builtin_func(
"run_method0", TypeExpr::new_map(Int, Unit),
[](AsmOpList& a, auto b, auto c) { return compile_run_method(a, b, c, 0, false); }, true);
define_builtin_func(
"run_method1", TypeExpr::new_forall({X}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X}), Unit)),
[](AsmOpList& a, auto b, auto c) { return compile_run_method(a, b, c, 1, false); }, {1, 0}, {}, true);
define_builtin_func(
"run_method2", TypeExpr::new_forall({X, Y}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X, Y}), Unit)),
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 2, false); }, {1, 2, 0}, {}, true);
[](AsmOpList& a, auto b, auto c) { return compile_run_method(a, b, c, 2, false); }, {1, 2, 0}, {}, true);
define_builtin_func(
"run_method3", TypeExpr::new_forall({X, Y, Z}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X, Y, Z}), Unit)),
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 3, false); }, {1, 2, 3, 0}, {}, true);
[](AsmOpList& a, auto b, auto c) { return compile_run_method(a, b, c, 3, false); }, {1, 2, 3, 0}, {}, true);
}
} // namespace funC

View file

@ -276,7 +276,6 @@ bool Op::generate_code_step(Stack& stack) {
stack.opt_show();
stack.drop_vars_except(var_info);
stack.opt_show();
const auto& next_var_info = next->var_info;
bool inline_func = stack.mode & Stack::_InlineFunc;
switch (cl) {
case _Nop:
@ -291,7 +290,7 @@ bool Op::generate_code_step(Stack& stack) {
return false;
}
case _IntConst: {
auto p = next_var_info[left[0]];
auto p = next->var_info[left[0]];
if (!p || p->is_unused()) {
return true;
}
@ -307,7 +306,7 @@ bool Op::generate_code_step(Stack& stack) {
return true;
}
case _SliceConst: {
auto p = next_var_info[left[0]];
auto p = next->var_info[left[0]];
if (!p || p->is_unused()) {
return true;
}
@ -319,7 +318,7 @@ bool Op::generate_code_step(Stack& stack) {
if (dynamic_cast<const SymValGlobVar*>(fun_ref->value)) {
bool used = false;
for (auto i : left) {
auto p = next_var_info[i];
auto p = next->var_info[i];
if (p && !p->is_unused()) {
used = true;
}
@ -339,7 +338,7 @@ bool Op::generate_code_step(Stack& stack) {
return true;
} else {
assert(left.size() == 1);
auto p = next_var_info[left[0]];
auto p = next->var_info[left[0]];
if (!p || p->is_unused() || disabled()) {
return true;
}
@ -360,7 +359,7 @@ bool Op::generate_code_step(Stack& stack) {
for (int i = 0; i < wr; i++) {
args0.emplace_back(0);
}
func->compile(stack.o, res, args0); // compile res := f (args0)
func->compile(stack.o, res, args0, where); // compile res := f (args0)
} else {
std::string name = sym::symbols.get_name(fun_ref->sym_idx);
stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size());
@ -377,7 +376,7 @@ bool Op::generate_code_step(Stack& stack) {
active.reserve(left.size());
for (std::size_t k = 0; k < left.size(); k++) {
var_idx_t y = left[k]; // "y" = "x"
auto p = next_var_info[y];
auto p = next->var_info[y];
active.push_back(p && !p->is_unused());
}
for (std::size_t k = 0; k < left.size(); k++) {
@ -489,7 +488,7 @@ bool Op::generate_code_step(Stack& stack) {
for (var_idx_t i : left) {
res.emplace_back(i);
}
func->compile(stack.o, res, args); // compile res := f (args)
func->compile(stack.o, res, args, where); // compile res := f (args)
} else {
auto fv = dynamic_cast<const SymValCodeFunc*>(fun_ref->value);
std::string name = sym::symbols.get_name(fun_ref->sym_idx);

View file

@ -109,7 +109,7 @@ int main(int argc, char* const argv[]) {
std::unique_ptr<std::fstream> fs;
if (!output_filename.empty()) {
fs = std::make_unique<std::fstream>(output_filename, fs->trunc | fs->out);
fs = std::make_unique<std::fstream>(output_filename, std::fstream::trunc | std::fstream::out);
if (!fs->is_open()) {
std::cerr << "failed to create output file " << output_filename << '\n';
return 2;

View file

@ -39,7 +39,7 @@ extern std::string generated_from;
constexpr int optimize_depth = 20;
const std::string func_version{"0.4.1"};
const std::string func_version{"0.4.2"};
enum Keyword {
_Eof = -1,
@ -505,7 +505,7 @@ class ListIterator {
ptr = ptr->next.get();
return *this;
}
ListIterator& operator++(int) {
ListIterator operator++(int) {
T* z = ptr;
ptr = ptr->next.get();
return ListIterator{z};
@ -1631,11 +1631,11 @@ struct Stack {
*
*/
typedef std::function<AsmOp(std::vector<VarDescr>&, std::vector<VarDescr>&)> simple_compile_func_t;
typedef std::function<AsmOp(std::vector<VarDescr>&, std::vector<VarDescr>&, const SrcLocation)> simple_compile_func_t;
typedef std::function<bool(AsmOpList&, std::vector<VarDescr>&, std::vector<VarDescr>&)> compile_func_t;
inline simple_compile_func_t make_simple_compile(AsmOp op) {
return [op](std::vector<VarDescr>& out, std::vector<VarDescr>& in) -> AsmOp { return op; };
return [op](std::vector<VarDescr>& out, std::vector<VarDescr>& in, const SrcLocation&) -> AsmOp { return op; };
}
inline compile_func_t make_ext_compile(std::vector<AsmOp> ops) {
@ -1674,7 +1674,7 @@ struct SymValAsmFunc : SymValFunc {
std::initializer_list<int> ret_order = {}, bool impure = false)
: SymValFunc(-1, ft, arg_order, ret_order, impure), ext_compile(std::move(_compile)) {
}
bool compile(AsmOpList& dest, std::vector<VarDescr>& out, std::vector<VarDescr>& in) const;
bool compile(AsmOpList& dest, std::vector<VarDescr>& out, std::vector<VarDescr>& in, const SrcLocation& where) const;
};
// defined in builtins.cpp

View file

@ -487,7 +487,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
Expr* res = new Expr{Expr::_Const, lex.cur().loc};
res->flags = Expr::_IsRvalue;
res->intval = td::string_to_int256(lex.cur().str);
if (res->intval.is_null()) {
if (res->intval.is_null() || !res->intval->signed_fits_bits(257)) {
lex.cur().error_at("invalid integer constant `", "`");
}
res->e_type = TypeExpr::new_atomic(_Int);

860
crypto/smartcont/mathlib.fc Normal file
View file

@ -0,0 +1,860 @@
{-
-
- FunC fixed-point mathematical library
-
-}
{---------------- HIGH-LEVEL FUNCTION DECLARATIONS -----------------}
{-
Most functions declared here work either with integers or with fixed-point numbers of type `fixed248`.
`fixedNNN` informally denotes an alias for type `int` used to represent fixed-point numbers with scale 2^NNN.
Prefix `fixedNNN::` is prepended to the names of high-level functions that accept arguments and return values of type `fixedNNN`.
-}
{- function declarations have been commented out, otherwise they are not inlined by the current FunC compiler
;; nearest integer to sqrt(a*b) for non-negative integers or fixed-point numbers a and b
int geom_mean(int a, int b) inline_ref;
;; integer square root
int sqrt(int a) inline;
;; fixed-point square root
;; fixed248 sqrt(fixed248 x)
int fixed248::sqrt(int x) inline;
int fixed248::sqr(int x) inline;
const int fixed248::One;
;; log(2) as fixed248
int fixed248::log2_const() inline;
;; Pi as fixed248
int fixed248::Pi_const() inline;
;; fixed248 exp(fixed248 x)
int fixed248::exp(int x) inline_ref;
;; fixed248 exp2(fixed248 x)
int fixed248::exp2(int x) inline_ref;
;; fixed248 log(fixed248 x)
int fixed248::log(int x) inline_ref;
;; fixed248 log2(fixed248 x)
int fixed248::log2(int x) inline;
;; fixed248 pow(fixed248 x, fixed248 y)
int fixed248::pow(int x, int y) inline_ref;
;; (fixed248, fixed248) sincos(fixed248 x);
(int, int) fixed248::sincos(int x) inline_ref;
;; fixed248 sin(fixed248 x);
int fixed248::sin(int x) inline;
;; fixed248 cos(fixed248 x);
int fixed248::cos(int x) inline;
;; fixed248 tan(fixed248 x);
int fixed248::tan(int x) inline_ref;
;; fixed248 cot(fixed248 x);
int fixed248::cot(int x) inline_ref;
;; fixed248 asin(fixed248 x);
int fixed248::asin(int x) inline;
;; fixed248 acos(fixed248 x);
int fixed248::acos(int x) inline;
;; fixed248 atan(fixed248 x);
int fixed248::atan(int x) inline_ref;
;; fixed248 acot(fixed248 x);
int fixed248::acot(int x) inline_ref;
-} ;; end (declarations)
{-------------------- INTERMEDIATE FUNCTIONS -----------------------}
{-
Intermediate functions are used in the implementations of high-level `fixedNNN::...` functions
if necessary, they can be used to define additional high-level functions for other fixed-point types, such as fixed128, outside this library. They can be also used in a hypothetical floating-point FunC library.
For these reasons, the declarations of these functions are collected here.
-}
{- function declarations have been commented out, otherwise they are not inlined by the current FunC compiler
;; fixed258 tanh(fixed258 x, int steps);
int tanh_f258(int x, int n);
;; computes exp(x)-1 for |x| <= log(2)/2.
;; fixed257 expm1(fixed257 x);
int expm1_f257(int x);
;; computes (sin(x+xe),-cos(x+xe)) for |x| <= Pi/4, xe very small
;; this function is very accurate, error less than 0.7 ulp (consumes ~ 5500 gas)
;; (fixed256, fixed256) sincosn(fixed256 x, fixed259 xe)
(int, int) sincosn_f256(int x, int xe);
;; compute (sin(x),1-cos(x)) in fixed256 for |x| < 16*atan(1/16) = 0.9987
;; (fixed256, fixed257) sincosm1_f256(fixed256 x);
;; slightly less accurate than sincosn_f256() (error up to 3/2^256), but faster (~ 4k gas) and shorter
(int, int) sincosm1_f256(int x);
;; compute (p, q) such that p/q = tan(x) for |x|<2*atan(1/2)=1899/2048=0.927
;; (int, int) tan_aux(fixed256 x);
(int, int) tan_aux_f256(int x);
;; returns (y, s) such that log(x) = y/2^256 + s*log(2) for positive integer x
;; this function is very precise (error less than 0.6 ulp) and consumes < 7k gas
;; (fixed256, int) log_aux_f256(int x);
(int, int) log_aux_f256(int x);
;; returns (y, s) such that log2(x) = y/2^256 + s for positive integer x
;; this function is very precise (error less than 0.6 ulp) and consumes < 7k gas
;; (fixed256, int) log2_aux_f256(int x);
(int, int) log2_aux_f256(int x);
;; compute (q, z) such that atan(x)=q*atan(1/32)+z for -1 <= x < 1
;; this function is reasonably accurate (error < 7 ulp with ulp = 2^-261), but it consumes >7k gas
;; this is sufficient for most purposes
;; (int, fixed261) atan_aux(fixed256 x)
(int, int) atan_aux_f256(int x);
;; fixed255 atan(fixed255 x);
int atan_f255(int x);
;; for -1 <= x < 1 only
;; fixed256 atan_small(fixed256 x);
int atan_f256_small(int x);
;; fixed255 asin(fixed255 x);
int asin_f255(int x);
;; fixed254 acos(fixed255 x);
int acos_f255(int x);
-} ;; end (declarations)
{---------------- MISSING OPERATIONS AND BUILT-INS -----------------}
int sgn(int x) asm "SGN";
int abs(int x) asm "ABS";
int min(int x, int y) asm "MIN";
;; compute floor(log2(x))+1
int log2_floor_p1(int x) asm "UBITSIZE";
;; FunC compiler emits MULDIVC instruction, but Asm.fif usually does not know it
;; add the following line to your Asm.fif if necessary
;; x{A986} @Defop MULDIVC
;; the following instructions might have been emitted by muldivmod() and muldivmodr() builtins, but FunC does not have these
;; x{A9A5} @Defop MULRSHIFTR
int mulrshiftr(int x, int y, int s) asm "MULRSHIFTR";
;; x{A9B5} @Defop(8u+1) MULRSHIFTR#
int mulrshiftr256(int x, int y) asm "256 MULRSHIFTR#";
;; x{A9BC} @Defop(8u+1) MULRSHIFT#MOD
(int, int) mulrshift256mod(int x, int y) asm "256 MULRSHIFT#MOD";
;; x{A9BD} @Defop(8u+1) MULRSHIFTR#MOD
(int, int) mulrshiftr256mod(int x, int y) asm "256 MULRSHIFTR#MOD";
(int, int) mulrshiftr255mod(int x, int y) asm "255 MULRSHIFTR#MOD";
(int, int) mulrshiftr248mod(int x, int y) asm "248 MULRSHIFTR#MOD";
(int, int) mulrshiftr5mod(int x, int y) asm "5 MULRSHIFTR#MOD";
(int, int) mulrshiftr6mod(int x, int y) asm "6 MULRSHIFTR#MOD";
(int, int) mulrshiftr7mod(int x, int y) asm "7 MULRSHIFTR#MOD";
;; these instructions might have been emitted by muldivmodr(..., 1 << N, ...) built-ins
;; x{A9D5} @Defop(8u+1) LSHIFT#DIVR
int lshift256divr(int x, int y) asm "256 LSHIFT#DIVR";
;; x{A9DD} @Defop(8u+1) LSHIFT#DIVMODR
(int, int) lshift256divmodr(int x, int y) asm "256 LSHIFT#DIVMODR";
(int, int) lshift255divmodr(int x, int y) asm "255 LSHIFT#DIVMODR";
(int, int) lshift2divmodr(int x, int y) asm "2 LSHIFT#DIVMODR";
(int, int) lshift7divmodr(int x, int y) asm "7 LSHIFT#DIVMODR";
;; x{A9CD} @Defop LSHIFTDIVMODR
(int, int) lshiftdivmodr(int x, int y, int s) asm "LSHIFTDIVMODR";
;; these instructions might have been emitted by divmodr(..., 1 << NN) or divmod(..., 1 << N) built-ins
;; but FunC does not have divmodr(), and divmod() always compiles to "DIVMOD"
;; x{A93D} @Defop(8u+1) RSHIFTR#MOD
(int, int) rshiftr256mod(int x) asm "256 RSHIFTR#MOD";
(int, int) rshiftr248mod(int x) asm "248 RSHIFTR#MOD";
(int, int) rshiftr4mod(int x) asm "4 RSHIFTR#MOD";
;; x{A93C} @Defop(8u+1) RSHIFT#MOD
(int, int) rshift3mod(int x) asm "3 RSHIFT#MOD";
;; computes y - x (FunC compiler does not try to use this by itself)
int sub_rev(int x, int y) asm "SUBR";
{------------------------ SQUARE ROOTS ----------------------------}
;; computes sqrt(a*b) exactly rounded to the nearest integer
;; for all 0 <= a, b <= 2^256-1
;; may be used with b=1 or b=scale of fixed-point numbers
int geom_mean(int a, int b) inline_ref {
if (min(a, b) <= 0) {
return 0;
}
int s = log2_floor_p1(a);
int t = log2_floor_p1(b);
;; NB: (a-b)/2+b == (a+b)/2, but without overflow for large a and b
int x = (s == t ? (a - b) / 2 + b : 1 << ((s + t) / 2));
do {
;; if always used with b=2^const, may be optimized to "const LSHIFTDIVC#"
;; it is important to use `muldivc` here, not `muldiv` or `muldivr`
int q = (muldivc(a, b, x) - x) / 2;
x += q;
} until (q == 0);
return x;
}
;; integer square root, computes round(sqrt(a)) for all a>=0.
;; note: `inline` is better than `inline_ref` for such simple functions
int sqrt(int a) inline {
return geom_mean(a, 1);
}
;; version for fixed248 = fixed-point numbers with scale 2^248
;; fixed248 sqrt(fixed248 x)
int fixed248::sqrt(int x) inline {
return geom_mean(x, 1 << 248);
}
;; fixed255 sqrt(fixed255 x)
int fixed255::sqrt(int x) inline {
return geom_mean(x, 1 << 255);
}
;; fixed248 sqr(fixed248 x);
int fixed248::sqr(int x) inline {
return muldivr(x, x, 1 << 248);
}
;; fixed255 sqr(fixed255 x);
int fixed255::sqr(int x) inline {
return muldivr(x, x, 1 << 255);
}
const int fixed248::One = (1 << 248);
const int fixed255::One = (1 << 255);
{-------------------- USEFUL CONSTANTS --------------------}
;; store huge constants in inline_ref functions for reuse
;; (y,z) where y=round(log(2)*2^256), z=round((log(2)*2^256-y)*2^128)
;; then log(2) = y/2^256 + z/2^384
(int, int) log2_xconst_f256() inline_ref {
return (80260960185991308862233904206310070533990667611589946606122867505419956976172, -32272921378999278490133606779486332143);
}
;; (y,z) where Pi = y/2^254 + z/2^382
(int, int) Pi_xconst_f254() inline_ref {
return (90942894222941581070058735694432465663348344332098107489693037779484723616546, 108051869516004014909778934258921521947);
}
;; atan(1/16) as fixed260
int Atan1_16_f260() inline_ref {
return 115641670674223639132965820642403718536242645001775371762318060545014644837101; ;; true value is ...101.0089...
}
;; atan(1/8) as fixed259
int Atan1_8_f259() inline_ref {
return 115194597005316551477397594802136977648153890007566736408151129975021336532841; ;; correction -0.1687...
}
;; atan(1/32) as fixed261
int Atan1_32_f261() inline_ref {
return 115754418570128574501879331591757054405465733718902755858991306434399246026247; ;; correction 0.395...
}
;; inline is better than inline_ref for such very small functions
int log2_const_f256() inline {
(int c, _) = log2_xconst_f256();
return c;
}
int fixed248::log2_const() inline {
return log2_const_f256() ~>> 8;
}
int Pi_const_f254() inline {
(int c, _) = Pi_xconst_f254();
return c;
}
int fixed248::Pi_const() inline {
return Pi_const_f254() ~>> 6;
}
{--------------- HYPERBOLIC TANGENT AND EXPONENT -------------------}
;; hyperbolic tangent of small x via n+2 terms of Lambert's continued fraction
;; n=17: good for |x| < log(2)/4 = 0.173
;; fixed258 tanh_f258(fixed258 x, int n)
int tanh_f258(int x, int n) inline_ref {
int x2 = muldivr(x, x, 1 << 255); ;; x^2 as fixed261
int c = int a = (2 * n + 5) << 250; ;; a=2n+5 as fixed250
int Two = (1 << 251); ;; 2. as fixed250
repeat (n) {
a = (c -= Two) + muldivr(x2, 1 << 239, a); ;; a := 2k+1+x^2/a as fixed250, k=n+1,n,...,2
}
a = (touch(3) << 254) + muldivr(x2, 1 << 243, a); ;; a := 3+x^2/a as fixed254
;; y = x/(1+a') = x - x*a'/(1+a') = x - x*x^2/(a+x^2) where a' = x^2/a
return x - (muldivr(x, x2, a + (x2 ~>> 7)) ~>> 7);
}
;; fixed257 expm1_f257(fixed257 x)
;; computes exp(x)-1 for small x via 19 terms of Lambert's continued fraction for tanh(x/2)
;; good for |x| < log(2)/2 = 0.347 (n=17); consumes ~3500 gas
int expm1_f257(int x) inline_ref {
;; (almost) compute tanh(x/2) first; x/2 as fixed258 = x as fixed257
int x2 = muldivr(x, x, 1 << 255); ;; x^2 as fixed261
int Two = (1 << 251); ;; 2. as fixed250
int c = int a = touch(39) << 250; ;; a=2n+5 as fixed250
repeat (17) {
a = (c -= Two) + muldivr(x2, 1 << 239, a); ;; a := 2k+1+x^2/a as fixed250, k=n+1,n,...,2
}
a = (touch(3) << 254) + muldivr(x2, 1 << 243, a); ;; a := 3+x^2/a as fixed254
;; now tanh(x/2) = x/(1+a') where a'=x^2/a ; apply exp(x)-1=2*tanh(x/2)/(1-tanh(x/2))
int t = (x ~>> 4) - a; ;; t:=x-a as fixed254
return x - muldivr(x2, t / 2, a + mulrshiftr256(x, t) ~/ 4) ~/ 4; ;; x - x^2 * (x-a) / (a + x*(x-a))
}
;; used to avoid broken optimisations in older versions of FunC
int minus_one() asm "-1 PUSHINT";
;; expm1_f257() may be used to implement specific fixed-point exponentials
;; example:
;; fixed248 exp(fixed248 x)
int fixed248::exp(int x) inline_ref {
var (l2c, l2d) = log2_xconst_f256();
;; divide x by log(2) and convert to fixed257
;; (int q, x) = muldivmodr(x, 256, l2c); ;; unfortunately, no such built-in
(int q, x) = lshiftdivmodr(x, l2c, 8);
x = 2 * x - muldivr(q, l2d, 1 << 127);
int y = expm1_f257(x);
;; result is (1 + y) * (2^q) --> ((1 << 257) + y) >> (9 - q)
return (y ~>> (9 - q)) - (minus_one() << (248 + q));
;; (-1 << (248 + q)) is compiled into non-existent instruction NEGPOW2
;; note that (y ~>> (9 - q)) + (1 << (248 + q)) leads to overflow when q=8
}
;; compute 2^x in fixed248
;; fixed248 exp2(fixed248 x)
int fixed248::exp2(int x) inline_ref {
;; (int q, x) = divmodr(x, 1 << 248); ;; no such built-in
(int q, x) = rshiftr248mod(x);
x = muldivr(x, log2_const_f256(), 1 << 247);
int y = expm1_f257(x);
return (y ~>> (9 - q)) - (minus_one() << (248 + q));
}
{--------------------- TRIGONOMETRIC FUNCTIONS -----------------------}
;; fixed260 tan(fixed260 x);
;; computes tan(x) for small |x|<atan(1/16) via 16 terms of Lambert's continued fraction
int tan_f260_inlined(int x) inline {
int x2 = mulrshiftr256(x, x); ;; x^2 as fixed264
int Two = (1 << 251); ;; 2. as fixed250
int c = int a = touch(33) << 250; ;; a=2n+5 as fixed250
repeat (14) {
a = (c -= Two) - muldivr(x2, 1 << 236, a); ;; a := 2k+1-x^2/a as fixed250, k=n+1,n,...,2
}
a = (touch(3) << 254) - muldivr(x2, 1 << 240, a); ;; a := 3-x^2/a as fixed254
;; y = x/(1-a') = x + x*a'/(1-a') = x + x*x^2/(a-x^2) where a' = x^2/a
return x + (muldivr(x / 2, x2, a - (x2 ~>> 10)) ~>> 9);
}
;; fixed260 tan(fixed260 x);
int tan_f260(int x) inline_ref {
return tan_f260_inlined(x);
}
;; fixed258 tan(fixed258 x);
;; computes tan(x) for small |x|<atan(1/4) via 20 terms of Lambert's continued fraction
int tan_f258_inlined(int x) inline {
int x2 = mulrshiftr256(x, x); ;; x^2 as fixed260
int Two = (1 << 251); ;; 2. as fixed250
int c = int a = touch(41) << 250; ;; a=2n+5 as fixed250
repeat (18) {
a = (c -= Two) - muldivr(x2, 1 << 240, a); ;; a := 2k+1-x^2/a as fixed250, k=n+1,n,...,2
}
a = (touch(3) << 254) - muldivr(x2, 1 << 244, a); ;; a := 3-x^2/a as fixed254
;; y = x/(1-a') = x + x*a'/(1-a') = x + x*x^2/(a-x^2) where a' = x^2/a
return x + (muldivr(x / 2, x2, a - (x2 ~>> 6)) ~>> 5);
}
;; fixed258 tan(fixed258 x);
int tan_f258(int x) inline_ref {
return tan_f258_inlined(x);
}
;; (fixed259, fixed263) sincosm1(fixed259 x)
;; computes (sin(x), 1-cos(x)) for small |x|<2*atan(1/16)
(int, int) sincosm1_f259_inlined(int x) inline {
int t = tan_f260_inlined(x); ;; t=tan(x/2) as fixed260
int tt = mulrshiftr256(t, t); ;; t^2 as fixed264
int y = tt ~/ 512 + (1 << 255); ;; 1+t^2 as fixed255
;; 2*t/(1+t^2) as fixed259 and 2*t^2/(1+t^2) as fixed263
;; return (muldivr(t, 1 << 255, y), muldivr(tt, 1 << 255, y));
return (t - muldivr(t / 2, tt, y) ~/ 256, tt - muldivr(tt / 2, tt, y) ~/ 256);
}
(int, int) sincosm1_f259(int x) inline_ref {
return sincosm1_f259_inlined(x);
}
;; computes (sin(x+xe),-cos(x+xe)) for |x| <= Pi/4, xe very small
;; this function is very accurate, error less than 0.7 ulp (consumes ~ 5500 gas)
;; (fixed256, fixed256) sincosn(fixed256 x, fixed259 xe)
(int, int) sincosn_f256(int x, int xe) inline_ref {
;; var (q, x1) = muldivmodr(x, 8, Atan1_8_f259()); ;; no muldivmodr() builtin
var (q, x1) = lshift2divmodr(abs(x), Atan1_8_f259()); ;; reduce mod theta where theta=2*atan(1/8)
var (si, co) = sincosm1_f259(x1 * 2 + xe);
var (a, b, c) = (-1, 0, 1);
repeat (q) { ;; (a+b*I) *= (8+I)^2 = 63+16*I
(a, b, c) = (63 * a - 16 * b, 16 * a + 63 * b, 65 * c);
}
;; now a/c = cos(q*theta), b/c = sin(q*theta) exactly(!)
;; compute (a+b*I)*(1-co+si*I)/c
;; (b, a) = (lshift256divr(b, c), lshift256divr(a, c));
(b, int br) = lshift256divmodr(b, c); br = muldivr(br, 128, c);
(a, int ar) = lshift256divmodr(a, c); ar = muldivr(ar, 128, c);
return (sgn(x) * (((mulrshiftr256(b, co) - br) ~/ 16 - mulrshiftr256(a, si)) ~/ 8 - b),
a - ((mulrshiftr256(a, co) - ar) ~/ 16 + mulrshiftr256(b, si)) ~/ 8);
}
;; compute (sin(x),1-cos(x)) in fixed256 for |x| < 16*atan(1/16) = 0.9987
;; (fixed256, fixed257) sincosm1_f256(fixed256 x);
;; slightly less accurate than sincosn_f256() (error up to 3/2^256), but faster (~ 4k gas) and shorter
(int, int) sincosm1_f256(int x) inline_ref {
var (si, co) = sincosm1_f259_inlined(x); ;; compute (sin,1-cos)(x/8) in (fixed259,fixed263)
int r = 7;
repeat (r / 2) {
;; 1-cos(2*x) = 2*sin(x)^2, sin(2*x) = 2*sin(x)*cos(x)
(co, si) = (mulrshiftr256(si, si), si - (mulrshiftr256(si, co) ~>> r));
r -= 2;
}
return (si, co);
}
;; compute (p, q) such that p/q = tan(x) for |x|<2*atan(1/2)=1899/2048=0.927
;; (int, int) tan_aux(fixed256 x);
(int, int) tan_aux_f256(int x) inline_ref {
int t = tan_f258_inlined(x); ;; t=tan(x/4) as fixed258
;; t:=2*t/(1-t^2)=2*(t-t^3/(t^2-1))
int tt = mulrshiftr256(t, t); ;; t^2 as fixed260
t = muldivr(t, tt, tt ~/ 16 + (-1 << 256)) ~/ 16 - t; ;; now t=-tan(x/2) as fixed259
return (t, mulrshiftr256(t, t) ~/ 4 + (-1 << 256)); ;; return (2*t, t^2-1) as fixed256
}
;; sincosm1_f256() and sincosn_f256() may be used to implement trigonometric functions for different fixed-point types
;; example:
;; (fixed248, fixed248) sincos(fixed248 x);
(int, int) fixed248::sincos(int x) inline_ref {
var (Pic, Pid) = Pi_xconst_f254();
;; (int q, x) = muldivmodr(x, 128, Pic); ;; no muldivmodr() builtin
(int q, x) = lshift7divmodr(x, Pic); ;; reduce mod Pi/2
x = 2 * x - muldivr(q, Pid, 1 << 127);
(int si, int co) = sincosm1_f256(x); ;; doesn't make sense to use more accurate sincosn_f256()
co = (1 << 248) - (co ~>> 9);
si ~>>= 8;
repeat (q & 3) {
(si, co) = (co, - si);
}
return (si, co);
}
;; fixed248 sin(fixed248 x);
;; inline is better than inline_ref for such simple functions
int fixed248::sin(int x) inline {
(int si, _) = fixed248::sincos(x);
return si;
}
;; fixed248 cos(fixed248 x);
int fixed248::cos(int x) inline {
(_, int co) = fixed248::sincos(x);
return co;
}
;; similarly, tan_aux_f256() may be used to implement tan() and cot() for specific fixed-point formats
;; fixed248 tan(fixed248 x);
;; not very accurate when |tan(x)| is very large (difficult to do better without floating-point numbers)
;; however, the relative accuracy is approximately 2^-247 in all cases, which is good enough for arguments given up to 2^-249
int fixed248::tan(int x) inline_ref {
var (Pic, Pid) = Pi_xconst_f254();
;; (int q, x) = muldivmodr(x, 128, Pic); ;; no muldivmodr() builtin
(int q, x) = lshift7divmodr(x, Pic); ;; reduce mod Pi/2
x = 2 * x - muldivr(q, Pid, 1 << 127);
var (a, b) = tan_aux_f256(x); ;; now a/b = tan(x')
if (q & 1) {
(a, b) = (b, - a);
}
return muldivr(a, 1 << 248, b); ;; either -b/a or a/b as fixed248
}
;; fixed248 cot(fixed248 x);
int fixed248::cot(int x) inline_ref {
var (Pic, Pid) = Pi_xconst_f254();
(int q, x) = lshift7divmodr(x, Pic); ;; reduce mod Pi/2
x = 2 * x - muldivr(q, Pid, 1 << 127);
var (b, a) = tan_aux_f256(x); ;; now b/a = tan(x')
if (q & 1) {
(a, b) = (b, - a);
}
return muldivr(a, 1 << 248, b); ;; either -b/a or a/b as fixed248
}
{----------------- INVERSE HYPERBOLIC TANGENT AND LOGARITHMS -----------------}
;; inverse hyperbolic tangent of small x, evaluated by means of n terms of the continued fraction
;; valid for |x| < 2^-2.5 ~ 0.18 if n=37 (slightly less accurate with n=36)
;; |x| < 1/8 if n=32; |x| < 2^-3.5 if n=28; |x| < 1/16 if n=25
;; |x| < 2^-4.5 if n=23; |x| < 1/32 if n=21; |x| < 1/64 if n=18
;; fixed258 atanh(fixed258 x);
int atanh_f258(int x, int n) inline_ref {
int x2 = mulrshiftr256(x, x); ;; x^2 as fixed260
int One = (1 << 254);
int a = One ~/ n + (1 << 255); ;; a := 2 + 1/n as fixed254
repeat (n - 1) {
;; a := 1 + (1 - x^2 / a)(1 + 1/n) as fixed254
int t = One - muldivr(x2, 1 << 248, a); ;; t := 1 - x^2 / a
a = muldivr(t, n, (int n1 = n - 1)) + One;
n = n1;
}
;; x / (1 - x^2 / a) = x / (1 - d) = x + x * d / (1 - d) for d = x^2 / a
;; int d = muldivr(x2, 1 << 255, a - (x2 ~>> 6)); ;; d/(1-d) = x^2/(a-x^2) as fixed261
;; return x + (mulrshiftr256(x, d) ~>> 5);
return x + muldivr(x, x2 / 2, a - x2 ~/ 64) ~/ 32;
}
;; number of terms n should be chosen as for atanh_f258()
;; fixed261 atanh(fixed261 x);
int atanh_f261_inlined(int x, int n) inline {
int x2 = mulrshiftr256(x, x); ;; x^2 as fixed266
int One = (1 << 254);
int a = One ~/ n + (1 << 255); ;; a := 2 + 1/n as fixed254
repeat (n - 1) {
;; a := 1 + (1 - x^2 / a)(1 + 1/n) as fixed254
int t = One - muldivr(x2, 1 << 242, a); ;; t := 1 - x^2 / a
a = muldivr(t, n, (int n1 = n - 1)) + One;
n = n1;
}
;; x / (1 - x^2 / a) = x / (1 - d) = x + x * d / (1 - d) for d = x^2 / a
;; int d = muldivr(x2, 1 << 255, a - (x2 ~>> 12)); ;; d/(1-d) = x^2/(a-x^2) as fixed267
;; return x + (mulrshiftr256(x, d) ~>> 11);
return x + muldivr(x, x2, a - x2 ~/ 4096) ~/ 4096;
}
;; fixed261 atanh(fixed261 x);
int atanh_f261(int x, int n) inline_ref {
return atanh_f261_inlined(x, n);
}
;; returns (y, s) such that log(x) = y/2^257 + s*log(2) for positive integer x
;; (fixed257, int) log_aux(int x)
(int, int) log_aux_f257(int x) inline_ref {
int s = log2_floor_p1(x);
x <<= 256 - s;
int t = touch(-1 << 256);
if ((x >> 249) <= 90) {
;; t~touch();
t >>= 1;
s -= 1;
}
x += t;
int 2x = 2 * x;
int y = lshift256divr(2x, (x >> 1) - t);
;; y = 2x - (mulrshiftr256(2x, y) ~>> 2); ;; this line could improve precision on very rare occasions
return (atanh_f258(y, 36), s);
}
;; computes 33^m for small m
int pow33(int m) inline {
int t = 1;
repeat (m) { t *= 33; }
return t;
}
;; computes 33^m for small 0<=m<=22
;; slightly faster than pow33()
int pow33b(int m) inline {
(int mh, int ml) = m /% 5;
int t = 1;
repeat (ml) { t *= 33; }
repeat (mh) { t *= 33 * 33 * 33 * 33 * 33; }
return t;
}
;; returns (s, q, y) such that log(x) = s*log(2) + q*log(33/32) + y/2^260 for positive integer x
;; (int, int, fixed260) log_auxx_f260(int x);
(int, int, int) log_auxx_f260(int x) inline_ref {
int s = log2_floor_p1(x) - 1;
x <<= 255 - s; ;; rescale to 1 <= x < 2 as fixed255
int t = touch(2873) << 244; ;; ~ (33/32)^11 ~ sqrt(2) as fixed255
int x1 = (x - t) >> 1;
int q = muldivr(x1, 65, x1 + t) + 11; ;; crude approximation to round(log(x)/log(33/32))
;; t = 1; repeat (q) { t *= 33; } ;; t:=33^q, 0<=q<=22
t = pow33b(q);
t <<= (51 - q) * 5; ;; t:=(33/32)^q as fixed255, nearest power of 33/32 to x
x -= t;
int y = lshift256divr(x << 4, (x >> 1) + t); ;; y = (x-t)/(x+t) as fixed261
y = atanh_f261(y, 18); ;; atanh((x-t)/(x+t)) as fixed261, or log(x/t) as fixed260
return (s, q, y);
}
;; returns (y, s) such that log(x) = y/2^256 + s*log(2) for positive integer x
;; this function is very precise (error less than 0.6 ulp) and consumes < 7k gas
;; (fixed256, int) log_aux_f256(int x);
(int, int) log_aux_f256(int x) inline_ref {
var (s, q, y) = log_auxx_f260(x);
var (yh, yl) = rshiftr4mod(y); ;; y ~/% 16 , but FunC does not optimize this to RSHIFTR#MOD
;; int Log33_32 = 3563114646320977386603103333812068872452913448227778071188132859183498739150; ;; log(33/32) as fixed256
;; int Log33_32_l = -3769; ;; log(33/32) = Log33_32 / 2^256 + Log33_32_l / 2^269
yh += (yl * 512 + q * -3769) ~>> 13; ;; compensation, may be removed if slightly worse accuracy is acceptable
int Log33_32 = 3563114646320977386603103333812068872452913448227778071188132859183498739150; ;; log(33/32) as fixed256
return (yh + q * Log33_32, s);
}
;; returns (y, s) such that log2(x) = y/2^256 + s for positive integer x
;; this function is very precise (error less than 0.6 ulp) and consumes < 7k gas
;; (fixed256, int) log2_aux_f256(int x);
(int, int) log2_aux_f256(int x) inline_ref {
var (s, q, y) = log_auxx_f260(x);
y = lshift256divr(y, log2_const_f256()) ~>> 4; ;; y/log(2) as fixed256
int Log33_32 = 5140487830366106860412008603913034462883915832139695448455767612111363481357; ;; log_2(33/32) as fixed256
;; Log33_32/2^256 happens to be a very precise approximation to log_2(33/32), no compensation required
return (y + q * Log33_32, s);
}
;; functions log_aux_f256() and log2_aux_f256() may be used to implement specific fixed-point instances of log() and log2()
;; fixed248 log(fixed248 x)
int fixed248::log(int x) inline_ref {
var (y, s) = log_aux_f256(x);
return muldivr(s - 248, log2_const_f256(), 1 << 8) + (y ~>> 8);
;; return muldivr(s - 248, 80260960185991308862233904206310070533990667611589946606122867505419956976172, 1 << 8) + (y ~>> 8);
}
;; fixed248 log2(fixed248 x)
int fixed248::log2(int x) inline {
var (y, s) = log2_aux_f256(x);
return ((s - 248) << 248) + (y ~>> 8);
}
;; computes x^y as exp(y*log(x)), x >= 0
;; fixed248 pow(fixed248 x, fixed248 y);
int fixed248::pow(int x, int y) inline_ref {
ifnot (y) {
return 1 << 248; ;; x^0 = 1
}
if (x <= 0) {
int bad = (x | y) < 0;
return 0 >> bad; ;; 0^y = 0 if x=0 and y>=0; "out of range" exception otherwise
}
var (l, s) = log2_aux_f256(x);
s -= 248; ;; log_2(x) = s+l, l is fixed256, 0<=l<1
;; compute (s+l)*y = q+ll
var (q1, r1) = mulrshiftr248mod(s, y); ;; muldivmodr(s, y, 1 << 248)
var (q2, r2) = mulrshift256mod(l, y);
r2 >>= 247;
var (q3, r3) = rshiftr248mod(q2); ;; divmodr(q2, 1 << 248);
var (q, ll) = rshiftr248mod(r1 + r3);
ll = 512 * ll + r2;
q += q1 + q3;
;; now log_2(x^y) = y*log_2(x) = q + ll, ss integer, ll fixed257, -1/2<=ll<1/2
int sq = q + 248;
if (sq <= 0) {
return - (sq == 0); ;; underflow
}
int y = expm1_f257(mulrshiftr256(ll, log2_const_f256()));
return (y ~>> (9 - q)) - (minus_one() << sq);
}
{--------------------- INVERSE TRIGONOMETRIC FUNCTIONS -------------------}
;; number of terms n should be chosen as for atanh_f258()
;; fixed259 atan(fixed259 x);
int atan_f259(int x, int n) inline_ref {
int x2 = mulrshiftr256(x, x); ;; x^2 as fixed262
int One = (1 << 254);
int a = One ~/ n + (1 << 255); ;; a := 2 + 1/n as fixed254
repeat (n - 1) {
;; a := 1 + (1 + x^2 / a)(1 + 1/n) as fixed254
int t = One + muldivr(x2, 1 << 246, a); ;; t := 1 + x^2 / a
a = muldivr(t, n, (int n1 = n - 1)) + One;
n = n1;
}
;; x / (1 + x^2 / a) = x / (1 + d) = x - x * d / (1 + d) = x - x * x^2/(a+x^2) for d = x^2 / a
return x - muldivr(x, x2, a + x2 ~/ 256) ~/ 256;
}
;; number of terms n should be chosen as for atanh_f261()
;; fixed261 atan(fixed261 x);
int atan_f261_inlined(int x, int n) inline {
int x2 = mulrshiftr256(x, x); ;; x^2 as fixed266
int One = (1 << 254);
int a = One ~/ n + (1 << 255); ;; a := 2 + 1/n as fixed254
repeat (n - 1) {
;; a := 1 + (1 + x^2 / a)(1 + 1/n) as fixed254
int t = One + muldivr(x2, 1 << 242, a); ;; t := 1 + x^2 / a
a = muldivr(t, n, (int n1 = n - 1)) + One;
n = n1;
}
;; x / (1 + x^2 / a) = x / (1 + d) = x - x * d / (1 + d) = x - x * x^2/(a+x^2) for d = x^2 / a
return x - muldivr(x, x2, a + x2 ~/ 4096) ~/ 4096;
}
;; fixed261 atan(fixed261 x);
int atan_f261(int x, int n) inline_ref {
return atan_f261_inlined(x, n);
}
;; computes (q,a,b) such that q is approximately atan(x)/atan(1/32) and a+b*I=(1+I/32)^q as fixed255
;; then b/a=atan(q*atan(1/32)) exactly, and (a,b) is almost a unit vector pointing in the direction of (1,x)
;; must have |x|<1.1, x is fixed24
;; (int, fixed255, fixed255) atan_aux_prereduce(fixed24 x);
(int, int, int) atan_aux_prereduce(int x) inline_ref {
int xu = abs(x);
int tc = 7214596; ;; tan(13*theta) as fixed24 where theta=atan(1/32)
int t1 = muldivr(xu - tc, 1 << 88, xu * tc + (1 << 48)); ;; tan(x') as fixed64 where x'=atan(x)-13*theta
;; t1/(3+t1^2) * 3073/32 = x'/3 * 3072/32 = x' / (96/3072) = x' / theta
int q = muldivr(t1 * 3073, 1 << 59, t1 * t1 + (touch(3) << 128)) + 13; ;; approximately round(atan(x)/theta), 0<=q<=25
var (pa, pb) = (33226912, 5232641); ;; (32+I)^5
var (qh, ql) = q /% 5;
var (a, b) = (1 << (5 * (51 - q)), 0); ;; (1/32^q, 0) as fixed255
repeat (ql) { ;; a+b*I *= 32+I
(a, b) = (sub_rev(touch(b), 32 * a), a + 32 * b); ;; same as (32 * a - b, 32 * b + a), but more efficient
}
repeat (qh) { ;; a+b*I *= (32+I)^5 = pa + pb*I
(a, b) = (a * pa - b * pb, a * pb + b * pa);
}
int xs = sgn(x);
return (xs * q, a, xs * b);
}
;; compute (q, z) such that atan(x)=q*atan(1/32)+z for -1 <= x < 1
;; this function is reasonably accurate (error < 7 ulp with ulp = 2^-261), but it consumes >7k gas
;; this is sufficient for most purposes
;; (int, fixed261) atan_aux(fixed256 x)
(int, int) atan_aux_f256(int x) inline_ref {
var (q, a, b) = atan_aux_prereduce(x ~>> 232); ;; convert x to fixed24
;; now b/a = tan(q*atan(1/32)) exactly, where q is near atan(x)/atan(1/32); so b/a is near x
;; compute y = u/v = (a*x-b)/(a+b*x) as fixed261 ; then |y|<0.0167 = 1.07/64 and atan(x)=atan(y)+q*atan(1/32)
var (u, ul) = mulrshiftr256mod(a, x);
u = (ul ~>> 250) + ((u - b) << 6); ;; |u| < 1/32, convert fixed255 -> fixed261
int v = a + mulrshiftr256(b, x); ;; v is scalar product of (a,b) and (1,x), it is approximately in [1..sqrt(2)] as fixed255
int y = muldivr(u, 1 << 255, v); ;; y = u/v as fixed261
int z = atan_f261_inlined(y, 18); ;; z = atan(x)-q*atan(1/32)
return (q, z);
}
;; compute (q, z) such that atan(x)=q*atan(1/32)+z for -1 <= x < 1
;; this function is very accurate (error < 2 ulp), but it consumes >7k gas
;; in most cases, faster function atan_aux_f256() should be used
;; (int, fixed261) atan_auxx(fixed256 x)
(int, int) atan_auxx_f256(int x) inline_ref {
var (q, a, b) = atan_aux_prereduce(x ~>> 232); ;; convert x to fixed24
;; now b/a = tan(q*atan(1/32)) exactly, where q is near atan(x)/atan(1/32); so b/a is near x
;; compute y = (a*x-b)/(a+b*x) as fixed261 ; then |y|<0.0167 = 1.07/64 and atan(x)=atan(y)+q*atan(1/32)
;; use sort of double precision arithmetic for this
var (u, ul) = mulrshiftr256mod(a, x);
ul /= 2;
u -= b; ;; |u| < 1/32 as fixed255
var (v, vl) = mulrshiftr256mod(b, x);
vl /= 2;
v += a; ;; v is scalar product of (a,b) and (1,x), it is approximately in [1..sqrt(2)] as fixed255
;; y = (u + ul*eps) / (v + vl*eps) = u/v + (ul - vl * u/v)/v * eps where eps=1/2^255
var (y, r) = lshift255divmodr(u, v); ;; y = u/v as fixed255
int yl = muldivr(ul + r, 1 << 255, v) - muldivr(vl, y, v); ;; y/2^255 + yl/2^510 represent u/v
y = (yl ~>> 249) + (y << 6); ;; convert y to fixed261
int z = atan_f261_inlined(y, 18); ;; z = atan(x)-q*atan(1/32)
return (q, z);
}
;; consumes ~ 8k gas
;; fixed255 atan(fixed255 x);
int atan_f255(int x) inline_ref {
int s = (x ~>> 256);
touch(x);
if (s) {
x = lshift256divr(-1 << 255, x); ;; x:=-1/x as fixed256
} else {
x *= 2; ;; convert to fixed256
}
var (q, z) = atan_aux_f256(x);
;; now atan(x) = z + q*atan(1/32) + s*(Pi/2), z is fixed261
var (Pi_h, Pi_l) = Pi_xconst_f254(); ;; Pi/2 as fixed255 + fixed383
var (qh, ql) = mulrshiftr6mod (q, Atan1_32_f261());
return qh + s * Pi_h + (z + ql + muldivr(s, Pi_l, 1 << 122)) ~/ 64;
}
;; computes atan(x) for -1 <= x < 1 only
;; fixed256 atan_small(fixed256 x);
int atan_f256_small(int x) inline_ref {
var (q, z) = atan_aux_f256(x);
;; now atan(x) = z + q*atan(1/32), z is fixed261
var (qh, ql) = mulrshiftr5mod (q, Atan1_32_f261());
return qh + (z + ql) ~/ 32;
}
;; fixed255 asin(fixed255 x);
int asin_f255(int x) inline_ref {
int a = fixed255::One - fixed255::sqr(x); ;; a:=1-x^2
if (a <= 0) {
return sgn(x) * Pi_const_f254(); ;; Pi/2 or -Pi/2
}
int y = fixed255::sqrt(a); ;; sqrt(1-x^2)
int t = - lshift256divr(x, (-1 << 255) - y); ;; t = x/(1+sqrt(1-x^2)) avoiding overflow
return atan_f256_small(t); ;; asin(x)=2*atan(t)
}
;; fixed254 acos(fixed255 x);
int acos_f255(int x) inline_ref {
int Pi = Pi_const_f254();
if (x <= (-1 << 255)) {
return Pi; ;; acos(-1) = Pi
}
Pi /= 2;
int y = fixed255::sqrt(fixed255::One - fixed255::sqr(x)); ;; sqrt(1-x^2)
int t = lshift256divr(x, (-1 << 255) - y); ;; t = -x/(1+sqrt(1-x^2)) avoiding overflow
return Pi + atan_f256_small(t) ~/ 2; ;; acos(x)=Pi/2 + 2*atan(t)
}
;; consumes ~ 10k gas
;; fixed248 asin(fixed248 x)
int fixed248::asin(int x) inline {
return asin_f255(x << 7) ~>> 7;
}
;; consumes ~ 10k gas
;; fixed248 acos(fixed248 x)
int fixed248::acos(int x) inline {
return acos_f255(x << 7) ~>> 6;
}
;; consumes ~ 7500 gas
;; fixed248 atan(fixed248 x);
int fixed248::atan(int x) inline_ref {
int s = (x ~>> 249);
touch(x);
if (s) {
s = sgn(s);
x = lshift256divr(-1 << 248, x); ;; x:=-1/x as fixed256
} else {
x <<= 8; ;; convert to fixed256
}
var (q, z) = atan_aux_f256(x);
;; now atan(x) = z + q*atan(1/32) + s*(Pi/2), z is fixed261
return (z ~/ 64 + s * Pi_const_f254() + muldivr(q, Atan1_32_f261(), 64)) ~/ 128; ;; compute in fixed255, then convert
}
;; fixed248 acot(fixed248 x);
int fixed248::acot(int x) inline_ref {
int s = (x ~>> 249);
touch(x);
if (s) {
x = lshift256divr(-1 << 248, x); ;; x:=-1/x as fixed256
s = 0;
} else {
x <<= 8; ;; convert to fixed256
s = sgn(x);
}
var (q, z) = atan_aux_f256(x);
;; now acot(x) = - z - q*atan(1/32) + s*(Pi/2), z is fixed261
return (s * Pi_const_f254() - z ~/ 64 - muldivr(q, Atan1_32_f261(), 64)) ~/ 128; ;; compute in fixed255, then convert
}

View file

@ -310,7 +310,7 @@ cell preload_ref(slice s) asm "PLDREF";
;;; Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`.
;; slice preload_bits(slice s, int len) asm "PLDSLICEX";
;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`).
;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^120 - 1`).
(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS";
(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS";
@ -426,7 +426,7 @@ builder store_ref(builder b, cell c) asm(c b) "STREF";
;;; Stores `slice` [s] into `builder` [b]
builder store_slice(builder b, slice s) asm "STSLICER";
;;; Stores (serializes) an integer [x] in the range `0..2^128 1` into `builder` [b].
;;; Stores (serializes) an integer [x] in the range `0..2^120 1` into `builder` [b].
;;; The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`,
;;; which is the smallest integer `l ≥ 0`, such that `x < 2^8l`,
;;; followed by an `8l`-bit unsigned big-endian representation of [x].

View file

@ -0,0 +1,100 @@
{-------------------------- TESTS for mathlib.fc ----------------------------}
;; computes 1-acos(x)/Pi by a very simple, extremely slow (~70k gas) and imprecise method
;; fixed256 acos_prepare_slow(fixed255 x);
int acos_prepare_slow_f255(int x) inline {
x -= (x == 0);
int t = 1;
repeat (255) {
t = t * sgn(x) * 2 + 1; ;; decode Gray code (sgn(x_0), sgn(x_1), ...)
x = (-1 << 255) - muldivr(x, - x, 1 << 254); ;; iterate x := 2*x^2 - 1 = cos(2*acos(x))
}
return abs(t);
}
;; extremely slow (~70k gas) and somewhat imprecise (very imprecise when x is small), for testing only
;; fixed254 acos_slow(fixed255 x);
int acos_slow_f255(int x) inline_ref {
int t = acos_prepare_slow_f255(x);
return - mulrshiftr256(t + (-1 << 256), Pi_const_f254());
}
;; fixed255 asin_slow(fixed255 x);
int asin_slow_f255(int x) inline_ref {
int t = acos_prepare_slow_f255(abs(x)) % (1 << 255);
return muldivr(t, Pi_const_f254(), 1 << 255) * sgn(x);
}
_ main() {
int One = 1;
;; repeat(76 / 4) { One *= 10000; }
int sqrt2 = geom_mean(One, 2 * One);
int sqrt3 = geom_mean(One, 3 * One);
;; return geom_mean((1 << 255) - 1 + (1 << 255), (1 << 255) - 1);
;; return geom_mean((1 << 255) - 1, (1 << 255) - 2);
;; return (sqrt2, geom_mean(sqrt2, One)); ;; (sqrt(2), 2^(1/4))
;; return (sqrt3, geom_mean(sqrt3, One)); ;; (sqrt(3), 3^(1/4))
;; return geom_mean(3 << 254, 1 << 254);
;; return tan_f260(115641670674223639132965820642403718536242645001775371762318060545014644837101 - 1);
;; return tan_f260(15 << 252); ;; tan(15/256) * 2^260
;; return sincosm1_f259(1 << 255); ;; (sin,1-cos)(1/16) * 2^259
;; return sincosm1_f259(115641670674223639132965820642403718536242645001775371762318060545014644837101 - 1);
;; return sincosm1_f256((1 << 255) - 1 + (1 << 255)); ;; (sin,1-cos)(1-2^(-256))
;; return sincosm1_f256(Pi_const_f254()); ;; (sin,1-cos)(Pi/4)
;; return sincosn_f256(Pi_const_f254(), 0); ;; (sin,-cos)(Pi/4)
;; return sincosn_f256((1 << 255) + 1, 0); ;; (sin,-cos)(1/2+1/2^256)
;; return sincosn_f256(1 << 254, 0);
;; return sincosn_f256(touch(15) << 252, 0); ;; (sin,-cos)(15/16)
;; return sincosm1_f256(touch(15) << 252); ;; (sin,1-cos)(15/16)
;; return sincosn_f256(60628596148627720713372490462954977108898896221398738326462025186323149077698, 0); ;; (sin,-cos)(Pi/6)
;; return sincosm1_f256(60628596148627720713372490462954977108898896221398738326462025186323149077698); ;; (sin,1-cos)(Pi/6)
;; return tan_aux_f256(1899 << 245); ;; (p,q) such that p/q=tan(1899/2048)
;; return fixed248::tan(11 << 248); ;; tan(11)
;; return atanh_alt_f258(1 << 252); ;; atanh(1/64) * 2^258
;; return atanh_f258(1 << 252, 18); ;; atanh(1/64) * 2^258
;; return atanh_f261(muldivr(64, 1 << 255, 55), 18); ;; atanh(1/55) * 2^261
;; return log2_aux_f256(1 << 255);
;; return log2_aux_f256(-1 - (-1 << 256)); ;; log2(2-1/2^255))*2^256 ~ 2^256 - 1.43
;; return log_aux_f256(-1 - (-1 << 256));
;; return log_aux_f256(3); ;; log(3/2)*2^256
;; return fixed248::pow(3 << 248, 3 << 248); ;; 3^3
;; return fixed248::exp(fixed248::log(5 << 248) ~/ 7); ;; exp(log(5)/7) = 5^(1/7)
;; return fixed248::log(Pi_const_f254() ~>> 6); ;; log(Pi)
;; return atanh_alt_f258(1 << 255); ;; atanh(1/8) * 2^258
;; return atanh_f258(1 << 255, 37); ;; atanh(1/8) * 2^258
;; return log_aux_f257(Pi_const_f254()); ;; log(Pi/4)
;; return log_aux_f257(3 << 254); ;; log(3)
;; return atanh_alt_f258(81877371507464127617551201542979628307507432471243237061821853600756754782485); ;; atanh(sqrt(2)/8) * 2^258
;; return atanh_f258(81877371507464127617551201542979628307507432471243237061821853600756754782485, 36); ;; atanh(sqrt(2)/8) * 2^258
;; return fixed248::sincos(Pi_const_f254() ~/ (64 * 3)); ;; (sin,cos)(Pi/3)
;; return fixed248::exp(3 << 248); ;; exp(3)*2^248
;; return fixed248::exp2((1 << 248) ~/ 5); ;; 2^(1/5)*2^248
;; return fixed248::pow(3 << 248, -3 << 247); ;; 3^(-1.5)
;; return fixed248::pow(10 << 248, -70 << 248); ;; 10^(-70)
;; return fixed248::exp(fixed248::log(fixed248::Pi_const()) * 3); ;; Pi^3 ~ 31.006
;; return fixed248::pow(fixed248::Pi_const(), touch(3) << 248); ;; Pi^3 ~ 31.006, computed more precisely
;; return fixed248::exp(muldivr(fixed248::log(fixed248::Pi_const()), fixed248::Pi_const(), 1 << 248)); ;; Pi^Pi
;; return fixed248::pow(fixed248::Pi_const(), fixed248::Pi_const()); ;; Pi^Pi, more precisely
;; return fixed248::sin(fixed248::log(fixed248::exp(fixed248::Pi_const()))); ;; sin(log(e^Pi))
;; return expm1_f257(1 << 255); ;; (exp(1/4)-1)*2^256
;; return expm1_f257(-1 << 256); ;; (exp(-1/2)-1)*2^256 (argument out of range, will overflow)
;; return expm1_f257(log2_const_f256()); ;; (exp(log(2)/2)-1)*2^256
;; return expm1_f257(- log2_const_f256()); ;; (exp(-log(2)/2)-1)*2^256
;; return tanh_f258(log2_const_f256(), 17); ;; tanh(log(2)/4)*2^258
;; return atan_f255(0xa0 << 247);
;; return atan_f259(1 << 255, 26); ;; atan(1/16)
;; return atan_f259(touch(2273) << 244, 26); ;; atan(2273/2^15)
;; return atan_aux_f256(0xa0 << 248);
;; return atan_aux_f256(-1 - (-1 << 256));
;; return atan_aux_f256(-1 << 256);
;; return atan_aux_f256(1); ;; atan(1/2^256)*2^261 = 32
int One = touch(1 << 255);
;; return asin_f255(-2 * One ~/ -3);
int arg = muldivr(12, One, 17); ;; 12/17
;; return [ asin_slow_f255(arg), asin_f255(arg) ];
;; return [ acos_slow_f255(arg), acos_f255(arg) ];
return 4 * atan_f255(One ~/ 5) - atan_f255(One ~/ 239); ;; 4 * atan(1/5) - atan(1/239) = Pi/4 as fixed255
int One = touch(1 << 248);
;; return fixed248::atan(One) ~/ 5); ;; atan(1/5)
;; return fixed248::acot(One ~/ 239); ;; atan(1/5)
}

View file

@ -54,7 +54,11 @@ td::Ref<vm::Stack> prepare_vm_stack(td::RefInt256 amount, td::Ref<vm::CellSlice>
td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
td::BitArray<256> rand_seed;
rand_seed.as_slice().fill(0);
if (args.rand_seed) {
rand_seed = args.rand_seed.unwrap();
} else {
rand_seed.as_slice().fill(0);
}
td::RefInt256 rand_seed_int{true};
rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false);
@ -96,7 +100,7 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
}
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
vm::GasLimits gas, bool ignore_chksig, td::Ref<vm::Cell> libraries) {
vm::GasLimits gas, bool ignore_chksig, td::Ref<vm::Cell> libraries, int vm_log_verbosity) {
auto gas_credit = gas.gas_credit;
vm::init_op_cp0();
vm::DictionaryBase::get_empty_dictionary();
@ -109,15 +113,12 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
std::string res;
};
Logger logger;
vm::VmLog log{&logger, td::LogOptions::plain()};
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
log.log_options.level = 4;
log.log_options.fix_newlines = true;
log.log_mask |= vm::VmLog::DumpStack;
} else {
log.log_options.level = 0;
log.log_mask = 0;
vm::VmLog log{&logger, td::LogOptions(VERBOSITY_NAME(DEBUG), true, false)};
if (vm_log_verbosity > 1) {
log.log_mask |= vm::VmLog::ExecLocation;
if (vm_log_verbosity > 2) {
log.log_mask |= vm::VmLog::DumpStack | vm::VmLog::GasRemaining;
}
}
SmartContract::Answer res;
@ -137,13 +138,13 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
} catch (...) {
LOG(FATAL) << "catch unhandled exception";
}
td::ConstBitPtr mlib = vm.get_missing_library();
res.new_state = std::move(state);
res.stack = vm.get_stack_ref();
gas = vm.get_gas_limits();
res.gas_used = gas.gas_consumed();
res.accepted = gas.gas_credit == 0;
res.success = (res.accepted && (unsigned)res.code <= 1);
res.vm_log = logger.res;
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
LOG(DEBUG) << "VM log\n" << logger.res;
std::ostringstream os;
@ -153,6 +154,7 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
LOG(DEBUG) << "VM accepted: " << res.accepted;
LOG(DEBUG) << "VM success: " << res.success;
}
td::ConstBitPtr mlib = vm.get_missing_library();
if (!mlib.is_null()) {
LOG(DEBUG) << "Missing library: " << mlib.to_hex(256);
res.missing_library = mlib;
@ -219,7 +221,7 @@ SmartContract::Answer SmartContract::run_method(Args args) {
args.stack.value().write().push_smallint(args.method_id.unwrap());
auto res =
run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig,
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{});
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{}, args.vm_log_verbosity_level);
state_ = res.new_state;
return res;
}
@ -237,7 +239,7 @@ SmartContract::Answer SmartContract::run_get_method(Args args) const {
CHECK(args.method_id);
args.stack.value().write().push_smallint(args.method_id.unwrap());
return run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig,
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{});
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{}, args.vm_log_verbosity_level);
}
SmartContract::Answer SmartContract::run_get_method(td::Slice method, Args args) const {

View file

@ -50,6 +50,7 @@ class SmartContract : public td::CntObject {
td::int32 code;
td::int64 gas_used;
td::ConstBitPtr missing_library{0};
std::string vm_log;
static int output_actions_count(td::Ref<vm::Cell> list);
};
@ -59,9 +60,11 @@ class SmartContract : public td::CntObject {
td::optional<td::Ref<vm::Tuple>> c7;
td::optional<td::Ref<vm::Stack>> stack;
td::optional<td::int32> now;
td::optional<td::BitArray<256>> rand_seed;
bool ignore_chksig{false};
td::uint64 amount{0};
td::uint64 balance{0};
int vm_log_verbosity_level{0};
td::optional<block::StdAddress> address;
td::optional<std::shared_ptr<const block::Config>> config;
@ -100,6 +103,10 @@ class SmartContract : public td::CntObject {
this->stack = std::move(stack);
return std::move(*this);
}
Args&& set_rand_seed(td::BitArray<256> rand_seed) {
this->rand_seed = std::move(rand_seed);
return std::move(*this);
}
Args&& set_ignore_chksig(bool ignore_chksig) {
this->ignore_chksig = ignore_chksig;
return std::move(*this);
@ -124,6 +131,10 @@ class SmartContract : public td::CntObject {
this->libraries = libraries;
return std::move(*this);
}
Args&& set_vm_verbosity_level(int vm_log_verbosity_level) {
this->vm_log_verbosity_level = vm_log_verbosity_level;
return std::move(*this);
}
td::Result<td::int32> get_method_id() const {
if (!method_id) {

View file

@ -289,7 +289,7 @@ struct MixedRadix {
}
explicit operator long long() const {
long long acc = 0.;
unsigned long long acc = 0;
for (int i = N - 1; i >= 0; --i) {
acc = acc * mod[i] + a[i];
}
@ -903,7 +903,7 @@ struct ModArray {
}
for (; i < size; i++) {
pow += 8;
acc = (acc << 8) + arr[i];
acc = (acc * 256) + arr[i];
if (pow >= 56) {
lshift_add(pow, acc);
acc = pow = 0;

View file

@ -186,7 +186,7 @@ td::RefInt256 make_special_int(int x, BInt* ptr = nullptr, unsigned char bin[64]
int acc = b, r = ord;
for (int i = 63; i >= 0; --i) {
if (r < 8) {
acc += (a << r);
acc += ((unsigned)a << r);
r = 1024;
}
r -= 8;
@ -215,7 +215,7 @@ int randexp(int max = 63, int min = 0) {
}
void bin_add_small(unsigned char bin[64], long long val, int shift = 0) {
val <<= shift & 7;
val *= (1 << (shift & 7));
for (int i = 63 - (shift >> 3); i >= 0 && val; --i) {
val += bin[i];
bin[i] = (unsigned char)val;

View file

@ -1008,27 +1008,40 @@ td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> roots
*
*/
bool CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
unsigned skip_count_root) {
clear();
return add_used_storage(std::move(cs_ref), kill_dup, skip_count_root) && clear_seen();
TRY_RESULT(res, add_used_storage(std::move(cs_ref), kill_dup, skip_count_root));
clear_seen();
return res;
}
bool CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup,
unsigned skip_count_root) {
clear();
return add_used_storage(cs, kill_dup, skip_count_root) && clear_seen();
TRY_RESULT(res, add_used_storage(cs, kill_dup, skip_count_root));
clear_seen();
return res;
}
bool CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup,
unsigned skip_count_root) {
clear();
return add_used_storage(std::move(cs), kill_dup, skip_count_root) && clear_seen();
TRY_RESULT(res, add_used_storage(std::move(cs), kill_dup, skip_count_root));
clear_seen();
return res;
}
bool CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup,
unsigned skip_count_root) {
clear();
return add_used_storage(std::move(cell), kill_dup, skip_count_root) && clear_seen();
TRY_RESULT(res, add_used_storage(std::move(cell), kill_dup, skip_count_root));
clear_seen();
return res;
}
bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
unsigned skip_count_root) {
if (cs_ref->is_unique()) {
return add_used_storage(std::move(cs_ref.unique_write()), kill_dup, skip_count_root);
} else {
@ -1036,56 +1049,67 @@ bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
}
}
bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup,
unsigned skip_count_root) {
if (!(skip_count_root & 1)) {
++cells;
if (cells > limit_cells) {
return false;
return td::Status::Error("too many cells");
}
}
if (!(skip_count_root & 2)) {
bits += cs.size();
if (bits > limit_bits) {
return false;
return td::Status::Error("too many bits");
}
}
CellInfo res;
for (unsigned i = 0; i < cs.size_refs(); i++) {
if (!add_used_storage(cs.prefetch_ref(i), kill_dup)) {
return false;
}
TRY_RESULT(child, add_used_storage(cs.prefetch_ref(i), kill_dup));
res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth);
}
return true;
if (cs.special_type() == CellTraits::SpecialType::MerkleProof ||
cs.special_type() == CellTraits::SpecialType::MerkleUpdate) {
++res.max_merkle_depth;
}
return res;
}
bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup,
unsigned skip_count_root) {
if (!(skip_count_root & 1)) {
++cells;
if (cells > limit_cells) {
return false;
return td::Status::Error("too many cells");
}
}
if (!(skip_count_root & 2)) {
bits += cs.size();
if (bits > limit_bits) {
return false;
return td::Status::Error("too many bits");
}
}
CellInfo res;
while (cs.size_refs()) {
if (!add_used_storage(cs.fetch_ref(), kill_dup)) {
return false;
}
TRY_RESULT(child, add_used_storage(cs.fetch_ref(), kill_dup));
res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth);
}
return true;
if (cs.special_type() == CellTraits::SpecialType::MerkleProof ||
cs.special_type() == CellTraits::SpecialType::MerkleUpdate) {
++res.max_merkle_depth;
}
return res;
}
bool CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup,
unsigned skip_count_root) {
if (cell.is_null()) {
return false;
return td::Status::Error("cell is null");
}
if (kill_dup) {
auto ins = seen.insert(cell->get_hash());
auto ins = seen.emplace(cell->get_hash(), CellInfo{});
if (!ins.second) {
return true;
return ins.first->second;
}
}
vm::CellSlice cs{vm::NoVm{}, std::move(cell)};

View file

@ -18,6 +18,7 @@
*/
#pragma once
#include <set>
#include <map>
#include "vm/db/DynamicBagOfCellsDb.h"
#include "vm/cells.h"
#include "td/utils/Status.h"
@ -108,12 +109,14 @@ struct CellStorageStat {
unsigned long long cells;
unsigned long long bits;
unsigned long long public_cells;
std::set<vm::Cell::Hash> seen;
struct CellInfo {
td::uint32 max_merkle_depth = 0;
};
std::map<vm::Cell::Hash, CellInfo> seen;
CellStorageStat() : cells(0), bits(0), public_cells(0) {
}
bool clear_seen() {
void clear_seen() {
seen.clear();
return true;
}
void clear() {
cells = bits = public_cells = 0;
@ -124,15 +127,16 @@ struct CellStorageStat {
limit_cells = std::numeric_limits<unsigned long long>::max();
limit_bits = std::numeric_limits<unsigned long long>::max();
}
bool compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
bool compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true,
unsigned skip_count_root = 0);
td::Result<CellInfo> compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
bool add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
bool add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
td::Result<CellInfo> add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
unsigned long long limit_cells = std::numeric_limits<unsigned long long>::max();
unsigned long long limit_bits = std::numeric_limits<unsigned long long>::max();

View file

@ -39,7 +39,13 @@ class MerkleProofImpl {
dfs_usage_tree(cell, usage_tree_->root_id());
is_prunned_ = [this](const Ref<Cell> &cell) { return visited_cells_.count(cell->get_hash()) == 0; };
}
return dfs(cell, cell->get_level());
try {
return dfs(cell, cell->get_level());
} catch (CellBuilder::CellWriteError &) {
return {};
} catch (CellBuilder::CellCreateError &) {
return {};
}
}
private:
@ -119,6 +125,9 @@ Ref<Cell> MerkleProof::generate(Ref<Cell> cell, CellUsageTree *usage_tree) {
return {};
}
auto raw = generate_raw(std::move(cell), usage_tree);
if (raw.is_null()) {
return {};
}
return CellBuilder::create_merkle_proof(std::move(raw));
}
@ -384,21 +393,29 @@ bool MerkleProofBuilder::clear() {
return true;
}
Ref<Cell> MerkleProofBuilder::extract_proof() const {
return MerkleProof::generate(orig_root, usage_tree.get());
td::Result<Ref<Cell>> MerkleProofBuilder::extract_proof() const {
Ref<Cell> proof = MerkleProof::generate(orig_root, usage_tree.get());
if (proof.is_null()) {
return td::Status::Error("cannot create Merkle proof");
}
return proof;
}
bool MerkleProofBuilder::extract_proof_to(Ref<Cell> &proof_root) const {
return orig_root.not_null() && (proof_root = extract_proof()).not_null();
if (orig_root.is_null()) {
return false;
}
auto R = extract_proof();
if (R.is_error()) {
return false;
}
proof_root = R.move_as_ok();
return true;
}
td::Result<td::BufferSlice> MerkleProofBuilder::extract_proof_boc() const {
Ref<Cell> proof_root = extract_proof();
if (proof_root.is_null()) {
return td::Status::Error("cannot create Merkle proof");
} else {
return std_boc_serialize(std::move(proof_root));
}
TRY_RESULT(proof_root, extract_proof());
return std_boc_serialize(std::move(proof_root));
}
} // namespace vm

View file

@ -63,7 +63,7 @@ class MerkleProofBuilder {
Ref<Cell> root() const {
return usage_root;
}
Ref<Cell> extract_proof() const;
td::Result<Ref<Cell>> extract_proof() const;
bool extract_proof_to(Ref<Cell> &proof_root) const;
td::Result<td::BufferSlice> extract_proof_boc() const;
};

View file

@ -221,6 +221,9 @@ Ref<Cell> MerkleUpdate::generate(Ref<Cell> from, Ref<Cell> to, CellUsageTree *us
return {};
}
auto res = generate_raw(std::move(from), std::move(to), usage_tree);
if (res.first.is_null() || res.second.is_null()) {
return {};
}
return CellBuilder::create_merkle_update(res.first, res.second);
}

View file

@ -31,7 +31,7 @@ namespace vm {
struct VmLog {
td::LogInterface *log_interface{td::log_interface};
td::LogOptions log_options{td::log_options};
enum { DumpStack = 2 };
enum { DumpStack = 2, ExecLocation = 4, GasRemaining = 8 };
int log_mask{1};
static VmLog Null() {
VmLog res;

View file

@ -433,18 +433,24 @@ void VmState::change_gas_limit(long long new_limit) {
int VmState::step() {
CHECK(code.not_null() && stack.not_null());
//VM_LOG(st) << "stack:"; stack->dump(VM_LOG(st));
//VM_LOG(st) << "; cr0.refcnt = " << get_c0()->get_refcnt() - 1 << std::endl;
if (log.log_mask & vm::VmLog::DumpStack) {
std::stringstream ss;
stack->dump(ss, 3);
VM_LOG(this) << "stack:" << ss.str();
}
if (stack_trace) {
stack->dump(std::cerr, 3);
}
++steps;
if (code->size()) {
VM_LOG_MASK(this, vm::VmLog::ExecLocation) << "code cell hash: " << code->get_base_cell()->get_hash().to_hex() << " offset: " << code->cur_pos();
return dispatch->dispatch(this, code.write());
} else if (code->size_refs()) {
VM_LOG(this) << "execute implicit JMPREF";
auto ref_cell = code->prefetch_ref();
VM_LOG_MASK(this, vm::VmLog::ExecLocation) << "code cell hash: " << ref_cell->get_hash().to_hex() << " offset: 0";
gas.consume_chk(implicit_jmpref_gas_price);
Ref<Continuation> cont = Ref<OrdCont>{true, load_cell_slice_ref(code->prefetch_ref()), get_cp()};
Ref<Continuation> cont = Ref<OrdCont>{true, load_cell_slice_ref(std::move(ref_cell)), get_cp()};
return jump(std::move(cont));
} else {
VM_LOG(this) << "execute implicit RET";
@ -465,6 +471,7 @@ int VmState::run() {
try {
try {
res = step();
VM_LOG_MASK(this, vm::VmLog::GasRemaining) << "gas remaining: " << gas.gas_remaining;
gas.check();
} catch (vm::CellBuilder::CellWriteError) {
throw VmError{Excno::cell_ov};

View file

@ -44,7 +44,7 @@ class DhtQuery : public td::actor::Actor {
bool client_only_;
public:
DhtQuery(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, DhtNodesList list, td::uint32 k,
DhtQuery(DhtKeyId key, DhtMember::PrintId print_id, adnl::AdnlNodeIdShort src, td::uint32 k,
td::uint32 a, td::int32 our_network_id, DhtNode self, bool client_only, td::actor::ActorId<DhtMember> node,
td::actor::ActorId<adnl::Adnl> adnl)
: key_(key)
@ -57,7 +57,6 @@ class DhtQuery : public td::actor::Actor {
, our_network_id_(our_network_id)
, node_(node)
, adnl_(adnl) {
add_nodes(std::move(list));
}
DhtMember::PrintId print_id() const {
return print_id_;
@ -112,8 +111,9 @@ class DhtQueryFindNodes : public DhtQuery {
td::uint32 k, td::uint32 a, td::int32 our_network_id, DhtNode self, bool client_only,
td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl,
td::Promise<DhtNodesList> promise)
: DhtQuery(key, print_id, src, std::move(list), k, a, our_network_id, std::move(self), client_only, node, adnl)
: DhtQuery(key, print_id, src, k, a, our_network_id, std::move(self), client_only, node, adnl)
, promise_(std::move(promise)) {
add_nodes(std::move(list));
}
void send_one_query(adnl::AdnlNodeIdShort id) override;
void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);
@ -132,8 +132,9 @@ class DhtQueryFindValue : public DhtQuery {
td::uint32 k, td::uint32 a, td::int32 our_network_id, DhtNode self, bool client_only,
td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl,
td::Promise<DhtValue> promise)
: DhtQuery(key, print_id, src, std::move(list), k, a, our_network_id, std::move(self), client_only, node, adnl)
: DhtQuery(key, print_id, src, k, a, our_network_id, std::move(self), client_only, node, adnl)
, promise_(std::move(promise)) {
add_nodes(std::move(list));
}
void send_one_query(adnl::AdnlNodeIdShort id) override;
void send_one_query_nodes(adnl::AdnlNodeIdShort id);
@ -219,11 +220,12 @@ class DhtQueryRequestReversePing : public DhtQuery {
td::uint32 a, td::int32 our_network_id, DhtNode self, bool client_only,
td::actor::ActorId<DhtMember> node, td::actor::ActorId<adnl::Adnl> adnl,
td::Promise<td::Unit> promise)
: DhtQuery(DhtMember::get_reverse_connection_key(client).compute_key_id(), print_id, src, std::move(list), k, a,
our_network_id, std::move(self), client_only, node, adnl)
: DhtQuery(DhtMember::get_reverse_connection_key(client).compute_key_id(), print_id, src, k, a, our_network_id,
std::move(self), client_only, node, adnl)
, promise_(std::move(promise))
, query_(create_serialize_tl_object<ton_api::dht_requestReversePing>(target.tl(), std::move(signature),
client.bits256_value(), k)) {
add_nodes(std::move(list));
}
void send_one_query(adnl::AdnlNodeIdShort id) override;
void on_result(td::Result<td::BufferSlice> R, adnl::AdnlNodeIdShort dst);

55
emulator/CMakeLists.txt Normal file
View file

@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
if (NOT OPENSSL_FOUND)
find_package(OpenSSL REQUIRED)
endif()
set(EMULATOR_STATIC_SOURCE
transaction-emulator.cpp
tvm-emulator.hpp
)
set(EMULATOR_HEADERS
transaction-emulator.h
emulator-extern.h
)
set(EMULATOR_SOURCE
emulator-extern.cpp
)
set(EMULATOR_EMSCRIPTEN_SOURCE
emulator-emscripten.cpp
)
include(GenerateExportHeader)
add_library(emulator_static STATIC ${EMULATOR_STATIC_SOURCE})
target_link_libraries(emulator_static PUBLIC ton_crypto ton_block smc-envelope)
add_library(emulator STATIC ${EMULATOR_SOURCE} ${EMULATOR_HEADERS})
target_link_libraries(emulator PUBLIC emulator_static)
generate_export_header(emulator EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/emulator_export.h)
target_include_directories(emulator PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
if (APPLE)
set_target_properties(emulator PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/emulator_export_list")
endif()
if (USE_EMSCRIPTEN)
add_executable(emulator-emscripten ${EMULATOR_EMSCRIPTEN_SOURCE})
target_link_libraries(emulator-emscripten PUBLIC emulator)
target_link_options(emulator-emscripten PRIVATE -sEXPORTED_RUNTIME_METHODS=_malloc,free,UTF8ToString,stringToUTF8,allocate,ALLOC_NORMAL,lengthBytesUTF8)
target_link_options(emulator-emscripten PRIVATE -sEXPORTED_FUNCTIONS=_emulate,_free,_run_get_method)
target_link_options(emulator-emscripten PRIVATE -sEXPORT_NAME=EmulatorModule)
target_link_options(emulator-emscripten PRIVATE -sERROR_ON_UNDEFINED_SYMBOLS=0)
target_link_options(emulator-emscripten PRIVATE -Oz)
target_link_options(emulator-emscripten PRIVATE -sIGNORE_MISSING_MAIN=1)
target_link_options(emulator-emscripten PRIVATE -sAUTO_NATIVE_LIBRARIES=0)
target_link_options(emulator-emscripten PRIVATE -sMODULARIZE=1)
target_link_options(emulator-emscripten PRIVATE -sENVIRONMENT=web)
target_link_options(emulator-emscripten PRIVATE -sFILESYSTEM=0)
target_link_options(emulator-emscripten PRIVATE -fexceptions)
target_compile_options(emulator-emscripten PRIVATE -fexceptions)
endif()

32
emulator/README.md Normal file
View file

@ -0,0 +1,32 @@
# Emulator
Emulator is a shared library containing the following functionality:
- Emulating blockchain transactions
- Emulating TVM - get methods and sending external and internal messages.
## Transaction Emulator
To emulate transaction you need the following data:
- Account state of type *ShardAccount*.
- Global config of type *(Hashmap 32 ^Cell)*.
- Inbound message of type *MessageAny*.
Optionally you can set emulation parameters:
- *ignore_chksig* - whether CHKSIG instructions are set to always succeed. Default: *false*
- *lt* - logical time of emulation. Default: next block's lt after the account's last transaction block.
- *unixtime* - unix time of emulation. Default: current system time
- *rand_seed* - random seed. Default: generated randomly
- *libs* - shared libraries. If your smart contract uses shared libraries (located in masterchain), you should set this parameter.
Emulator output contains:
- Transaction object (*Transaction*)
- New account state (*ShardAccount*)
- Actions cell (*OutList n*)
- TVM log
## TVM Emulator
TVM emulator is intended to run get methods or emulate sending message on TVM level. It is initialized with smart contract code and data cells.
- To run get method you pass *initial stack* and *method id* (as integer).
- To emulate sending message you pass *message body* and in case of internal message *amount* in nanograms.

27
emulator/StringLog.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef TON_STRINGLOG_H
#define TON_STRINGLOG_H
#include "td/utils/logging.h"
#include <thread>
class StringLog : public td::LogInterface {
public:
StringLog() {
}
void append(td::CSlice new_slice, int log_level) override {
str.append(new_slice.str());
}
void rotate() override {
}
std::string get_string() const {
return str;
}
private:
std::string str;
};
#endif //TON_STRINGLOG_H

View file

@ -0,0 +1,189 @@
#include "emulator-extern.h"
#include "td/utils/logging.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/misc.h"
#include "td/utils/optional.h"
#include "StringLog.h"
#include <iostream>
#include "crypto/common/bitstring.h"
struct TransactionEmulationParams {
uint32_t utime;
uint64_t lt;
td::optional<std::string> rand_seed_hex;
bool ignore_chksig;
};
td::Result<TransactionEmulationParams> decode_transaction_emulation_params(const char* json) {
TransactionEmulationParams params;
std::string json_str(json);
TRY_RESULT(input_json, td::json_decode(td::MutableSlice(json_str)));
auto &obj = input_json.get_object();
TRY_RESULT(utime_field, td::get_json_object_field(obj, "utime", td::JsonValue::Type::Number, false));
TRY_RESULT(utime, td::to_integer_safe<td::uint32>(utime_field.get_number()));
params.utime = utime;
TRY_RESULT(lt_field, td::get_json_object_field(obj, "lt", td::JsonValue::Type::String, false));
TRY_RESULT(lt, td::to_integer_safe<td::uint64>(lt_field.get_string()));
params.lt = lt;
TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", true));
if (rand_seed_str.size() > 0) {
params.rand_seed_hex = rand_seed_str;
}
TRY_RESULT(ignore_chksig, td::get_json_object_bool_field(obj, "ignore_chksig", false));
params.ignore_chksig = ignore_chksig;
return params;
}
struct GetMethodParams {
std::string code;
std::string data;
int verbosity;
td::optional<std::string> libs;
std::string address;
uint32_t unixtime;
uint64_t balance;
std::string rand_seed_hex;
int64_t gas_limit;
int method_id;
};
td::Result<GetMethodParams> decode_get_method_params(const char* json) {
GetMethodParams params;
std::string json_str(json);
TRY_RESULT(input_json, td::json_decode(td::MutableSlice(json_str)));
auto &obj = input_json.get_object();
TRY_RESULT(code, td::get_json_object_string_field(obj, "code", false));
params.code = code;
TRY_RESULT(data, td::get_json_object_string_field(obj, "data", false));
params.data = data;
TRY_RESULT(verbosity, td::get_json_object_int_field(obj, "verbosity", false));
params.verbosity = verbosity;
TRY_RESULT(libs, td::get_json_object_string_field(obj, "libs", true));
if (libs.size() > 0) {
params.libs = libs;
}
TRY_RESULT(address, td::get_json_object_string_field(obj, "address", false));
params.address = address;
TRY_RESULT(unixtime_field, td::get_json_object_field(obj, "unixtime", td::JsonValue::Type::Number, false));
TRY_RESULT(unixtime, td::to_integer_safe<td::uint32>(unixtime_field.get_number()));
params.unixtime = unixtime;
TRY_RESULT(balance_field, td::get_json_object_field(obj, "balance", td::JsonValue::Type::String, false));
TRY_RESULT(balance, td::to_integer_safe<td::uint64>(balance_field.get_string()));
params.balance = balance;
TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", false));
params.rand_seed_hex = rand_seed_str;
TRY_RESULT(gas_limit_field, td::get_json_object_field(obj, "gas_limit", td::JsonValue::Type::String, false));
TRY_RESULT(gas_limit, td::to_integer_safe<td::uint64>(gas_limit_field.get_string()));
params.gas_limit = gas_limit;
TRY_RESULT(method_id, td::get_json_object_int_field(obj, "method_id", false));
params.method_id = method_id;
return params;
}
extern "C" {
const char *emulate(const char *config, const char* libs, int verbosity, const char* account, const char* message, const char* params) {
StringLog logger;
td::log_interface = &logger;
SET_VERBOSITY_LEVEL(verbosity_DEBUG);
auto decoded_params_res = decode_transaction_emulation_params(params);
if (decoded_params_res.is_error()) {
return strdup(R"({"fail":true,"message":"Can't decode other params"})");
}
auto decoded_params = decoded_params_res.move_as_ok();
auto em = transaction_emulator_create(config, verbosity);
bool rand_seed_set = true;
if (decoded_params.rand_seed_hex) {
rand_seed_set = transaction_emulator_set_rand_seed(em, decoded_params.rand_seed_hex.unwrap().c_str());
}
if (!transaction_emulator_set_libs(em, libs) ||
!transaction_emulator_set_lt(em, decoded_params.lt) ||
!transaction_emulator_set_unixtime(em, decoded_params.utime) ||
!transaction_emulator_set_ignore_chksig(em, decoded_params.ignore_chksig) ||
!rand_seed_set) {
transaction_emulator_destroy(em);
return strdup(R"({"fail":true,"message":"Can't set params"})");
}
auto tx = transaction_emulator_emulate_transaction(em, account, message);
transaction_emulator_destroy(em);
const char* output = nullptr;
{
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("output", td::JsonRaw(td::Slice(tx)));
json_obj("logs", logger.get_string());
json_obj.leave();
output = strdup(jb.string_builder().as_cslice().c_str());
}
free((void*) tx);
return output;
}
const char *run_get_method(const char *params, const char* stack, const char* config) {
StringLog logger;
td::log_interface = &logger;
SET_VERBOSITY_LEVEL(verbosity_DEBUG);
auto decoded_params_res = decode_get_method_params(params);
if (decoded_params_res.is_error()) {
return strdup(R"({"fail":true,"message":"Can't decode params"})");
}
auto decoded_params = decoded_params_res.move_as_ok();
auto tvm = tvm_emulator_create(decoded_params.code.c_str(), decoded_params.data.c_str(), decoded_params.verbosity);
if ((decoded_params.libs && !tvm_emulator_set_libraries(tvm, decoded_params.libs.value().c_str())) ||
!tvm_emulator_set_c7(tvm, decoded_params.address.c_str(), decoded_params.unixtime,
decoded_params.balance, decoded_params.rand_seed_hex.c_str(), config) ||
(decoded_params.gas_limit > 0 && !tvm_emulator_set_gas_limit(tvm, decoded_params.gas_limit))) {
tvm_emulator_destroy(tvm);
return strdup(R"({"fail":true,"message":"Can't set params"})");
}
auto res = tvm_emulator_run_get_method(tvm, decoded_params.method_id, stack);
tvm_emulator_destroy(tvm);
const char* output = nullptr;
{
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("output", td::JsonRaw(td::Slice(res)));
json_obj("logs", logger.get_string());
json_obj.leave();
output = strdup(jb.string_builder().as_cslice().c_str());
}
free((void*) res);
return output;
}
}

View file

@ -0,0 +1,435 @@
#include "emulator-extern.h"
#include "td/utils/base64.h"
#include "td/utils/Status.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
#include "td/utils/Variant.h"
#include "td/utils/overloaded.h"
#include "transaction-emulator.h"
#include "tvm-emulator.hpp"
#include "crypto/vm/stack.hpp"
td::Result<td::Ref<vm::Cell>> boc_b64_to_cell(const char *boc) {
TRY_RESULT_PREFIX(boc_decoded, td::base64_decode(td::Slice(boc)), "Can't decode base64 boc: ");
return vm::std_boc_deserialize(boc_decoded);
}
td::Result<std::string> cell_to_boc_b64(td::Ref<vm::Cell> cell) {
TRY_RESULT_PREFIX(boc, vm::std_boc_serialize(std::move(cell), vm::BagOfCells::Mode::WithCRC32C), "Can't serialize cell: ");
return td::base64_encode(boc.as_slice());
}
const char *success_response(std::string&& transaction, std::string&& new_shard_account, std::string&& vm_log, td::optional<std::string>&& actions) {
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("success", td::JsonTrue());
json_obj("transaction", std::move(transaction));
json_obj("shard_account", std::move(new_shard_account));
json_obj("vm_log", std::move(vm_log));
if (actions) {
json_obj("actions", actions.unwrap());
} else {
json_obj("actions", td::JsonNull());
}
json_obj.leave();
return strdup(jb.string_builder().as_cslice().c_str());
}
const char *error_response(std::string&& error) {
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("success", td::JsonFalse());
json_obj("error", std::move(error));
json_obj.leave();
return strdup(jb.string_builder().as_cslice().c_str());
}
const char *external_not_accepted_response(std::string&& vm_log, int vm_exit_code) {
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("success", td::JsonFalse());
json_obj("error", "External message not accepted by smart contract");
json_obj("vm_log", std::move(vm_log));
json_obj("vm_exit_code", vm_exit_code);
json_obj.leave();
return strdup(jb.string_builder().as_cslice().c_str());
}
#define ERROR_RESPONSE(error) return error_response(error)
td::Result<block::Config> decode_config(const char* config_boc) {
TRY_RESULT_PREFIX(config_params_cell, boc_b64_to_cell(config_boc), "Can't deserialize config params boc: ");
auto global_config = block::Config(config_params_cell, td::Bits256::zero(), block::Config::needWorkchainInfo | block::Config::needSpecialSmc | block::Config::needCapabilities);
TRY_STATUS_PREFIX(global_config.unpack(), "Can't unpack config params: ");
return global_config;
}
void *transaction_emulator_create(const char *config_params_boc, int vm_log_verbosity) {
auto global_config_res = decode_config(config_params_boc);
if (global_config_res.is_error()) {
LOG(ERROR) << global_config_res.move_as_error().message();
return nullptr;
}
return new emulator::TransactionEmulator(global_config_res.move_as_ok(), vm_log_verbosity);
}
const char *transaction_emulator_emulate_transaction(void *transaction_emulator, const char *shard_account_boc, const char *message_boc) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
auto message_cell_r = boc_b64_to_cell(message_boc);
if (message_cell_r.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't deserialize message boc: " << message_cell_r.move_as_error());
}
auto message_cell = message_cell_r.move_as_ok();
auto message_cs = vm::load_cell_slice(message_cell);
int msg_tag = block::gen::t_CommonMsgInfo.get_tag(message_cs);
auto shard_account_cell = boc_b64_to_cell(shard_account_boc);
if (shard_account_cell.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't deserialize shard account boc: " << shard_account_cell.move_as_error());
}
auto shard_account_slice = vm::load_cell_slice(shard_account_cell.ok_ref());
block::gen::ShardAccount::Record shard_account;
if (!tlb::unpack(shard_account_slice, shard_account)) {
ERROR_RESPONSE(PSTRING() << "Can't unpack shard account cell");
}
td::Ref<vm::CellSlice> addr_slice;
auto account_slice = vm::load_cell_slice(shard_account.account);
if (block::gen::t_Account.get_tag(account_slice) == block::gen::Account::account_none) {
if (msg_tag == block::gen::CommonMsgInfo::ext_in_msg_info) {
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
if (!tlb::unpack(message_cs, info)) {
ERROR_RESPONSE(PSTRING() << "Can't unpack inbound external message");
}
addr_slice = std::move(info.dest);
}
else if (msg_tag == block::gen::CommonMsgInfo::int_msg_info) {
block::gen::CommonMsgInfo::Record_int_msg_info info;
if (!tlb::unpack(message_cs, info)) {
ERROR_RESPONSE(PSTRING() << "Can't unpack inbound internal message");
}
addr_slice = std::move(info.dest);
} else {
ERROR_RESPONSE(PSTRING() << "Only ext in and int message are supported");
}
} else {
block::gen::Account::Record_account account_record;
if (!tlb::unpack(account_slice, account_record)) {
ERROR_RESPONSE(PSTRING() << "Can't unpack account cell");
}
addr_slice = std::move(account_record.addr);
}
ton::WorkchainId wc;
ton::StdSmcAddress addr;
if (!block::tlb::t_MsgAddressInt.extract_std_address(addr_slice, wc, addr)) {
ERROR_RESPONSE(PSTRING() << "Can't extract account address");
}
auto account = block::Account(wc, addr.bits());
ton::UnixTime now = (unsigned)std::time(nullptr);
bool is_special = wc == ton::masterchainId && emulator->get_config().is_special_smartcontract(addr);
if (!account.unpack(vm::load_cell_slice_ref(shard_account_cell.move_as_ok()), td::Ref<vm::CellSlice>(), now, is_special)) {
ERROR_RESPONSE(PSTRING() << "Can't unpack shard account");
}
auto result = emulator->emulate_transaction(std::move(account), message_cell, 0, 0, block::transaction::Transaction::tr_ord);
if (result.is_error()) {
ERROR_RESPONSE(PSTRING() << "Emulate transaction failed: " << result.move_as_error());
}
auto emulation_result = result.move_as_ok();
auto external_not_accepted = dynamic_cast<emulator::TransactionEmulator::EmulationExternalNotAccepted *>(emulation_result.get());
if (external_not_accepted) {
return external_not_accepted_response(std::move(external_not_accepted->vm_log), external_not_accepted->vm_exit_code);
}
auto emulation_success = dynamic_cast<emulator::TransactionEmulator::EmulationSuccess&>(*emulation_result);
auto trans_boc_b64 = cell_to_boc_b64(std::move(emulation_success.transaction));
if (trans_boc_b64.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't serialize Transaction to boc " << trans_boc_b64.move_as_error());
}
auto new_shard_account_cell = vm::CellBuilder().store_ref(emulation_success.account.total_state)
.store_bits(emulation_success.account.last_trans_hash_.as_bitslice())
.store_long(emulation_success.account.last_trans_lt_).finalize();
auto new_shard_account_boc_b64 = cell_to_boc_b64(std::move(new_shard_account_cell));
if (new_shard_account_boc_b64.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't serialize ShardAccount to boc " << new_shard_account_boc_b64.move_as_error());
}
td::optional<td::string> actions_boc_b64;
if (emulation_success.actions.not_null()) {
auto actions_boc_b64_result = cell_to_boc_b64(std::move(emulation_success.actions));
if (actions_boc_b64_result.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't serialize actions list cell to boc " << actions_boc_b64_result.move_as_error());
}
actions_boc_b64 = actions_boc_b64_result.move_as_ok();
}
return success_response(trans_boc_b64.move_as_ok(), new_shard_account_boc_b64.move_as_ok(), std::move(emulation_success.vm_log), std::move(actions_boc_b64));
}
bool transaction_emulator_set_unixtime(void *transaction_emulator, uint32_t unixtime) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
emulator->set_unixtime(unixtime);
return true;
}
bool transaction_emulator_set_lt(void *transaction_emulator, uint64_t lt) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
emulator->set_lt(lt);
return true;
}
bool transaction_emulator_set_rand_seed(void *transaction_emulator, const char* rand_seed_hex) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
auto rand_seed_hex_slice = td::Slice(rand_seed_hex);
if (rand_seed_hex_slice.size() != 64) {
LOG(ERROR) << "Rand seed expected as 64 characters hex string";
return false;
}
auto rand_seed_bytes = td::hex_decode(rand_seed_hex_slice);
if (rand_seed_bytes.is_error()) {
LOG(ERROR) << "Can't decode hex rand seed";
return false;
}
td::BitArray<256> rand_seed;
rand_seed.as_slice().copy_from(rand_seed_bytes.move_as_ok());
emulator->set_rand_seed(rand_seed);
return true;
}
bool transaction_emulator_set_ignore_chksig(void *transaction_emulator, bool ignore_chksig) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
emulator->set_ignore_chksig(ignore_chksig);
return true;
}
bool transaction_emulator_set_config(void *transaction_emulator, const char* config_boc) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
auto global_config_res = decode_config(config_boc);
if (global_config_res.is_error()) {
LOG(ERROR) << global_config_res.move_as_error().message();
return false;
}
emulator->set_config(global_config_res.move_as_ok());
return true;
}
bool transaction_emulator_set_libs(void *transaction_emulator, const char* shardchain_libs_boc) {
auto emulator = static_cast<emulator::TransactionEmulator *>(transaction_emulator);
if (shardchain_libs_boc != nullptr) {
auto shardchain_libs_cell = boc_b64_to_cell(shardchain_libs_boc);
if (shardchain_libs_cell.is_error()) {
LOG(ERROR) << "Can't deserialize shardchain libraries boc: " << shardchain_libs_cell.move_as_error();
return false;
}
emulator->set_libs(vm::Dictionary(shardchain_libs_cell.move_as_ok(), 256));
}
return true;
}
void transaction_emulator_destroy(void *transaction_emulator) {
delete static_cast<emulator::TransactionEmulator *>(transaction_emulator);
}
bool emulator_set_verbosity_level(int verbosity_level) {
if (0 <= verbosity_level && verbosity_level <= VERBOSITY_NAME(NEVER)) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + verbosity_level);
return true;
}
return false;
}
void *tvm_emulator_create(const char *code, const char *data, int vm_log_verbosity) {
auto code_cell = boc_b64_to_cell(code);
if (code_cell.is_error()) {
LOG(ERROR) << "Can't deserialize code boc: " << code_cell.move_as_error();
return nullptr;
}
auto data_cell = boc_b64_to_cell(data);
if (data_cell.is_error()) {
LOG(ERROR) << "Can't deserialize code boc: " << data_cell.move_as_error();
return nullptr;
}
auto emulator = new emulator::TvmEmulator(code_cell.move_as_ok(), data_cell.move_as_ok());
emulator->set_vm_verbosity_level(vm_log_verbosity);
return emulator;
}
bool tvm_emulator_set_libraries(void *tvm_emulator, const char *libs_boc) {
vm::Dictionary libs{256};
auto libs_cell = boc_b64_to_cell(libs_boc);
if (libs_cell.is_error()) {
LOG(ERROR) << "Can't deserialize libraries boc: " << libs_cell.move_as_error();
return false;
}
libs = vm::Dictionary(libs_cell.move_as_ok(), 256);
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
emulator->set_libraries(std::move(libs));
return true;
}
bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config_boc) {
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
auto std_address = block::StdAddress::parse(td::Slice(address));
if (std_address.is_error()) {
LOG(ERROR) << "Can't parse address: " << std_address.move_as_error();
return false;
}
auto config_params_cell = boc_b64_to_cell(config_boc);
if (config_params_cell.is_error()) {
LOG(ERROR) << "Can't deserialize config params boc: " << config_params_cell.move_as_error();
return false;
}
auto global_config = std::make_shared<block::Config>(config_params_cell.move_as_ok(), td::Bits256::zero(), block::Config::needWorkchainInfo | block::Config::needSpecialSmc);
auto unpack_res = global_config->unpack();
if (unpack_res.is_error()) {
LOG(ERROR) << "Can't unpack config params";
return false;
}
auto rand_seed_hex_slice = td::Slice(rand_seed_hex);
if (rand_seed_hex_slice.size() != 64) {
LOG(ERROR) << "Rand seed expected as 64 characters hex string";
return false;
}
auto rand_seed_bytes = td::hex_decode(rand_seed_hex_slice);
if (rand_seed_bytes.is_error()) {
LOG(ERROR) << "Can't decode hex rand seed";
return false;
}
td::BitArray<256> rand_seed;
rand_seed.as_slice().copy_from(rand_seed_bytes.move_as_ok());
emulator->set_c7(std_address.move_as_ok(), unixtime, balance, rand_seed, std::const_pointer_cast<const block::Config>(global_config));
return true;
}
bool tvm_emulator_set_gas_limit(void *tvm_emulator, int64_t gas_limit) {
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
emulator->set_gas_limit(gas_limit);
return true;
}
const char *tvm_emulator_run_get_method(void *tvm_emulator, int method_id, const char *stack_boc) {
auto stack_cell = boc_b64_to_cell(stack_boc);
if (stack_cell.is_error()) {
ERROR_RESPONSE(PSTRING() << "Couldn't deserialize stack cell: " << stack_cell.move_as_error().to_string());
}
auto stack_cs = vm::load_cell_slice(stack_cell.move_as_ok());
td::Ref<vm::Stack> stack;
if (!vm::Stack::deserialize_to(stack_cs, stack)) {
ERROR_RESPONSE(PSTRING() << "Couldn't deserialize stack");
}
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
auto result = emulator->run_get_method(method_id, stack);
vm::CellBuilder stack_cb;
if (!result.stack->serialize(stack_cb)) {
ERROR_RESPONSE(PSTRING() << "Couldn't serialize stack");
}
auto result_stack_boc = cell_to_boc_b64(stack_cb.finalize());
if (result_stack_boc.is_error()) {
ERROR_RESPONSE(PSTRING() << "Couldn't serialize stack cell: " << result_stack_boc.move_as_error().to_string());
}
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("success", td::JsonTrue());
json_obj("stack", result_stack_boc.move_as_ok());
json_obj("gas_used", std::to_string(result.gas_used));
json_obj("vm_exit_code", result.code);
json_obj("vm_log", result.vm_log);
if (result.missing_library.is_null()) {
json_obj("missing_library", td::JsonNull());
} else {
json_obj("missing_library", td::Bits256(result.missing_library).to_hex());
}
json_obj.leave();
return strdup(jb.string_builder().as_cslice().c_str());
}
const char *tvm_emulator_send_external_message(void *tvm_emulator, const char *message_body_boc) {
auto message_body_cell = boc_b64_to_cell(message_body_boc);
if (message_body_cell.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't deserialize message body boc: " << message_body_cell.move_as_error());
}
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
auto result = emulator->send_external_message(message_body_cell.move_as_ok());
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("success", td::JsonTrue());
json_obj("gas_used", std::to_string(result.gas_used));
json_obj("vm_exit_code", result.code);
json_obj("accepted", td::JsonBool(result.accepted));
json_obj("vm_log", result.vm_log);
if (result.missing_library.is_null()) {
json_obj("missing_library", td::JsonNull());
} else {
json_obj("missing_library", td::Bits256(result.missing_library).to_hex());
}
json_obj("actions", cell_to_boc_b64(result.actions).move_as_ok());
json_obj("new_code", cell_to_boc_b64(result.new_state.code).move_as_ok());
json_obj("new_data", cell_to_boc_b64(result.new_state.data).move_as_ok());
json_obj.leave();
return strdup(jb.string_builder().as_cslice().c_str());
}
const char *tvm_emulator_send_internal_message(void *tvm_emulator, const char *message_body_boc, uint64_t amount) {
auto message_body_cell = boc_b64_to_cell(message_body_boc);
if (message_body_cell.is_error()) {
ERROR_RESPONSE(PSTRING() << "Can't deserialize message body boc: " << message_body_cell.move_as_error());
}
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
auto result = emulator->send_internal_message(message_body_cell.move_as_ok(), amount);
td::JsonBuilder jb;
auto json_obj = jb.enter_object();
json_obj("success", td::JsonTrue());
json_obj("gas_used", std::to_string(result.gas_used));
json_obj("vm_exit_code", result.code);
json_obj("accepted", td::JsonBool(result.accepted));
json_obj("vm_log", result.vm_log);
if (result.missing_library.is_null()) {
json_obj("missing_library", td::JsonNull());
} else {
json_obj("missing_library", td::Bits256(result.missing_library).to_hex());
}
json_obj("actions", cell_to_boc_b64(result.actions).move_as_ok());
json_obj("new_code", cell_to_boc_b64(result.new_state.code).move_as_ok());
json_obj("new_data", cell_to_boc_b64(result.new_state.data).move_as_ok());
json_obj.leave();
return strdup(jb.string_builder().as_cslice().c_str());
}
void tvm_emulator_destroy(void *tvm_emulator) {
delete static_cast<emulator::TvmEmulator *>(tvm_emulator);
}

216
emulator/emulator-extern.h Normal file
View file

@ -0,0 +1,216 @@
#pragma once
#include <stdint.h>
#include "emulator_export.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Creates TransactionEmulator object
* @param config_params_boc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
* @param vm_log_verbosity Verbosity level of VM log. 0 - log truncated to last 256 characters. 1 - unlimited length log.
* 2 - for each command prints its cell hash and offset. 3 - for each command log prints all stack values.
* @return Pointer to TransactionEmulator or nullptr in case of error
*/
EMULATOR_EXPORT void *transaction_emulator_create(const char *config_params_boc, int vm_log_verbosity);
/**
* @brief Set unixtime for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param unixtime Unix timestamp
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool transaction_emulator_set_unixtime(void *transaction_emulator, uint32_t unixtime);
/**
* @brief Set lt for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param lt Logical time
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool transaction_emulator_set_lt(void *transaction_emulator, uint64_t lt);
/**
* @brief Set rand seed for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param rand_seed_hex Hex string of length 64
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool transaction_emulator_set_rand_seed(void *transaction_emulator, const char* rand_seed_hex);
/**
* @brief Set ignore_chksig flag for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param ignore_chksig Whether emulation should always succeed on CHKSIG operation
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool transaction_emulator_set_ignore_chksig(void *transaction_emulator, bool ignore_chksig);
/**
* @brief Set unixtime for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param config_boc Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool transaction_emulator_set_config(void *transaction_emulator, const char* config_boc);
/**
* @brief Set unixtime for emulation
* @param transaction_emulator Pointer to TransactionEmulator object
* @param libs_boc Base64 encoded BoC serialized shared libraries dictionary (HashmapE 256 ^Cell).
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool transaction_emulator_set_libs(void *transaction_emulator, const char* libs_boc);
/**
* @brief Emulate transaction
* @param transaction_emulator Pointer to TransactionEmulator object
* @param shard_account_boc Base64 encoded BoC serialized ShardAccount
* @param message_boc Base64 encoded BoC serialized inbound Message (internal or external)
* @return Json object with error:
* {
* "success": false,
* "error": "Error description"
* // and optional fields "vm_exit_code" and "vm_log" in case external message was not accepted.
* }
* Or success:
* {
* "success": true,
* "transaction": "Base64 encoded Transaction boc",
* "shard_account": "Base64 encoded new ShardAccount boc",
* "vm_log": "execute DUP...",
* "actions": "Base64 encoded compute phase actions boc (OutList n)"
* }
*/
EMULATOR_EXPORT const char *transaction_emulator_emulate_transaction(void *transaction_emulator, const char *shard_account_boc, const char *message_boc);
/**
* @brief Destroy TransactionEmulator object
* @param transaction_emulator Pointer to TransactionEmulator object
*/
EMULATOR_EXPORT void transaction_emulator_destroy(void *transaction_emulator);
/**
* @brief Set global verbosity level of the library
* @param verbosity_level New verbosity level (0 - never, 1 - error, 2 - warning, 3 - info, 4 - debug)
*/
EMULATOR_EXPORT bool emulator_set_verbosity_level(int verbosity_level);
/**
* @brief Create TVM emulator
* @param code_boc Base64 encoded BoC serialized smart contract code cell
* @param data_boc Base64 encoded BoC serialized smart contract data cell
* @param vm_log_verbosity Verbosity level of VM log
* @return Pointer to TVM emulator object
*/
EMULATOR_EXPORT void *tvm_emulator_create(const char *code_boc, const char *data_boc, int vm_log_verbosity);
/**
* @brief Set libraries for TVM emulator
* @param libs_boc Base64 encoded BoC serialized libraries dictionary (HashmapE 256 ^Cell).
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool tvm_emulator_set_libraries(void *tvm_emulator, const char *libs_boc);
/**
* @brief Set c7 parameters
* @param tvm_emulator Pointer to TVM emulator
* @param address Adress of smart contract
* @param unixtime Unix timestamp
* @param balance Smart contract balance
* @param rand_seed_hex Random seed as hex string of length 64
* @param config Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config);
/**
* @brief Set TVM gas limit
* @param tvm_emulator Pointer to TVM emulator
* @param gas_limit Gas limit
* @return true in case of success, false in case of error
*/
EMULATOR_EXPORT bool tvm_emulator_set_gas_limit(void *tvm_emulator, int64_t gas_limit);
/**
* @brief Run get method
* @param tvm_emulator Pointer to TVM emulator
* @param method_id Integer method id
* @param stack_boc Base64 encoded BoC serialized stack (VmStack)
* @return Json object with error:
* {
* "success": false,
* "error": "Error description"
* }
* Or success:
* {
* "success": true
* "vm_log": "...",
* "vm_exit_code": 0,
* "stack": "Base64 encoded BoC serialized stack (VmStack)",
* "missing_library": null,
* "gas_used": 1212
* }
*/
EMULATOR_EXPORT const char *tvm_emulator_run_get_method(void *tvm_emulator, int method_id, const char *stack_boc);
/**
* @brief Send external message
* @param tvm_emulator Pointer to TVM emulator
* @param message_body_boc Base64 encoded BoC serialized message body cell.
* @return Json object with error:
* {
* "success": false,
* "error": "Error description"
* }
* Or success:
* {
* "success": true,
* "new_code": "Base64 boc decoded new code cell",
* "new_data": "Base64 boc decoded new data cell",
* "accepted": true,
* "vm_exit_code": 0,
* "vm_log": "...",
* "missing_library": null,
* "gas_used": 1212,
* "actions": "Base64 boc decoded actions cell of type (OutList n)"
* }
*/
EMULATOR_EXPORT const char *tvm_emulator_send_external_message(void *tvm_emulator, const char *message_body_boc);
/**
* @brief Send internal message
* @param tvm_emulator Pointer to TVM emulator
* @param message_body_boc Base64 encoded BoC serialized message body cell.
* @param amount Amount of nanograms attached with internal message.
* @return Json object with error:
* {
* "success": false,
* "error": "Error description"
* }
* Or success:
* {
* "success": true,
* "new_code": "Base64 boc decoded new code cell",
* "new_data": "Base64 boc decoded new data cell",
* "accepted": true,
* "vm_exit_code": 0,
* "vm_log": "...",
* "missing_library": null,
* "gas_used": 1212,
* "actions": "Base64 boc decoded actions cell of type (OutList n)"
* }
*/
EMULATOR_EXPORT const char *tvm_emulator_send_internal_message(void *tvm_emulator, const char *message_body_boc, uint64_t amount);
/**
* @brief Destroy TVM emulator object
* @param tvm_emulator Pointer to TVM emulator object
*/
EMULATOR_EXPORT void tvm_emulator_destroy(void *tvm_emulator);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -0,0 +1,17 @@
_transaction_emulator_create
_transaction_emulator_set_lt
_transaction_emulator_set_rand_seed
_transaction_emulator_set_ignore_chksig
_transaction_emulator_set_config
_transaction_emulator_set_libs
_transaction_emulator_emulate_transaction
_transaction_emulator_destroy
_emulator_set_verbosity_level
_tvm_emulator_create
_tvm_emulator_set_libraries
_tvm_emulator_set_c7
_tvm_emulator_set_gas_limit
_tvm_emulator_run_get_method
_tvm_emulator_send_external_message
_tvm_emulator_send_internal_message
_tvm_emulator_destroy

View file

@ -0,0 +1,255 @@
#include <string>
#include "transaction-emulator.h"
#include "crypto/common/refcnt.hpp"
#include "vm/cp0.h"
using td::Ref;
using namespace std::string_literals;
namespace emulator {
td::Result<std::unique_ptr<TransactionEmulator::EmulationResult>> TransactionEmulator::emulate_transaction(
block::Account&& account, td::Ref<vm::Cell> msg_root, ton::UnixTime utime, ton::LogicalTime lt, int trans_type) {
td::Ref<vm::Cell> old_mparams;
std::vector<block::StoragePrices> storage_prices;
block::StoragePhaseConfig storage_phase_cfg{&storage_prices};
block::ComputePhaseConfig compute_phase_cfg;
block::ActionPhaseConfig action_phase_cfg;
td::RefInt256 masterchain_create_fee, basechain_create_fee;
if (!utime) {
utime = unixtime_;
}
if (!utime) {
utime = (unsigned)std::time(nullptr);
}
auto fetch_res = block::FetchConfigParams::fetch_config_params(config_, &old_mparams,
&storage_prices, &storage_phase_cfg,
&rand_seed_, &compute_phase_cfg,
&action_phase_cfg, &masterchain_create_fee,
&basechain_create_fee, account.workchain, utime);
if(fetch_res.is_error()) {
return fetch_res.move_as_error_prefix("cannot fetch config params ");
}
vm::init_op_cp0();
if (!lt) {
lt = lt_;
}
if (!lt) {
lt = (account.last_trans_lt_ / block::ConfigInfo::get_lt_align() + 1) * block::ConfigInfo::get_lt_align(); // next block after account_.last_trans_lt_
}
compute_phase_cfg.libraries = std::make_unique<vm::Dictionary>(libraries_);
compute_phase_cfg.ignore_chksig = ignore_chksig_;
compute_phase_cfg.with_vm_log = true;
compute_phase_cfg.vm_log_verbosity = vm_log_verbosity_;
auto res = create_transaction(msg_root, &account, utime, lt, trans_type,
&storage_phase_cfg, &compute_phase_cfg,
&action_phase_cfg);
if(res.is_error()) {
return res.move_as_error_prefix("cannot run message on account ");
}
std::unique_ptr<block::transaction::Transaction> trans = res.move_as_ok();
if (!trans->compute_phase->accepted && trans->in_msg_extern) {
auto vm_log = trans->compute_phase->vm_log;
auto vm_exit_code = trans->compute_phase->exit_code;
return std::make_unique<TransactionEmulator::EmulationExternalNotAccepted>(std::move(vm_log), vm_exit_code);
}
if (!trans->serialize()) {
return td::Status::Error(-669,"cannot serialize new transaction for smart contract "s + trans->account.addr.to_hex());
}
auto trans_root = trans->commit(account);
if (trans_root.is_null()) {
return td::Status::Error(PSLICE() << "cannot commit new transaction for smart contract");
}
return std::make_unique<TransactionEmulator::EmulationSuccess>(std::move(trans_root), std::move(account), std::move(trans->compute_phase->vm_log), std::move(trans->compute_phase->actions));
}
td::Result<TransactionEmulator::EmulationSuccess> TransactionEmulator::emulate_transaction(block::Account&& account, td::Ref<vm::Cell> original_trans) {
block::gen::Transaction::Record record_trans;
if (!tlb::unpack_cell(original_trans, record_trans)) {
return td::Status::Error("Failed to unpack Transaction");
}
ton::LogicalTime lt = record_trans.lt;
ton::UnixTime utime = record_trans.now;
account.now_ = utime;
account.block_lt = record_trans.lt - record_trans.lt % block::ConfigInfo::get_lt_align();
td::Ref<vm::Cell> msg_root = record_trans.r1.in_msg->prefetch_ref();
int tag = block::gen::t_TransactionDescr.get_tag(vm::load_cell_slice(record_trans.description));
int trans_type = block::transaction::Transaction::tr_none;
switch (tag) {
case block::gen::TransactionDescr::trans_ord: {
trans_type = block::transaction::Transaction::tr_ord;
break;
}
case block::gen::TransactionDescr::trans_storage: {
trans_type = block::transaction::Transaction::tr_storage;
break;
}
case block::gen::TransactionDescr::trans_tick_tock: {
block::gen::TransactionDescr::Record_trans_tick_tock tick_tock;
if (!tlb::unpack_cell(record_trans.description, tick_tock)) {
return td::Status::Error("Failed to unpack tick tock transaction description");
}
trans_type = tick_tock.is_tock ? block::transaction::Transaction::tr_tock : block::transaction::Transaction::tr_tick;
break;
}
case block::gen::TransactionDescr::trans_split_prepare: {
trans_type = block::transaction::Transaction::tr_split_prepare;
break;
}
case block::gen::TransactionDescr::trans_split_install: {
trans_type = block::transaction::Transaction::tr_split_install;
break;
}
case block::gen::TransactionDescr::trans_merge_prepare: {
trans_type = block::transaction::Transaction::tr_merge_prepare;
break;
}
case block::gen::TransactionDescr::trans_merge_install: {
trans_type = block::transaction::Transaction::tr_merge_install;
break;
}
}
TRY_RESULT(emulation, emulate_transaction(std::move(account), msg_root, utime, lt, trans_type));
auto emulation_result = dynamic_cast<EmulationSuccess&>(*emulation);
if (td::Bits256(emulation_result.transaction->get_hash().bits()) != td::Bits256(original_trans->get_hash().bits())) {
return td::Status::Error("transaction hash mismatch");
}
if (!check_state_update(emulation_result.account, record_trans)) {
return td::Status::Error("account hash mismatch");
}
return emulation_result;
}
td::Result<TransactionEmulator::EmulationChain> TransactionEmulator::emulate_transactions_chain(block::Account&& account, std::vector<td::Ref<vm::Cell>>&& original_transactions) {
std::vector<td::Ref<vm::Cell>> emulated_transactions;
for (const auto& original_trans : original_transactions) {
if (original_trans.is_null()) {
continue;
}
TRY_RESULT(emulation_result, emulate_transaction(std::move(account), original_trans));
emulated_transactions.push_back(std::move(emulation_result.transaction));
account = std::move(emulation_result.account);
}
return TransactionEmulator::EmulationChain{ std::move(emulated_transactions), std::move(account) };
}
bool TransactionEmulator::check_state_update(const block::Account& account, const block::gen::Transaction::Record& trans) {
block::gen::HASH_UPDATE::Record hash_update;
return tlb::type_unpack_cell(trans.state_update, block::gen::t_HASH_UPDATE_Account, hash_update) &&
hash_update.new_hash == account.total_state->get_hash().bits();
}
td::Result<std::unique_ptr<block::transaction::Transaction>> TransactionEmulator::create_transaction(
td::Ref<vm::Cell> msg_root, block::Account* acc,
ton::UnixTime utime, ton::LogicalTime lt, int trans_type,
block::StoragePhaseConfig* storage_phase_cfg,
block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg) {
bool external{false}, ihr_delivered{false}, need_credit_phase{false};
if (msg_root.not_null()) {
auto cs = vm::load_cell_slice(msg_root);
external = block::gen::t_CommonMsgInfo.get_tag(cs);
}
if (trans_type == block::transaction::Transaction::tr_ord) {
need_credit_phase = !external;
} else if (trans_type == block::transaction::Transaction::tr_merge_install) {
need_credit_phase = true;
}
std::unique_ptr<block::transaction::Transaction> trans =
std::make_unique<block::transaction::Transaction>(*acc, trans_type, lt, utime, msg_root);
if (msg_root.not_null() && !trans->unpack_input_msg(ihr_delivered, action_phase_cfg)) {
if (external) {
// inbound external message was not accepted
return td::Status::Error(-701,"inbound external message rejected by account "s + acc->addr.to_hex() +
" before smart-contract execution");
}
return td::Status::Error(-669,"cannot unpack input message for a new transaction");
}
if (trans->bounce_enabled) {
if (!trans->prepare_storage_phase(*storage_phase_cfg, true)) {
return td::Status::Error(-669,"cannot create storage phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (need_credit_phase && !trans->prepare_credit_phase()) {
return td::Status::Error(-669,"cannot create credit phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
} else {
if (need_credit_phase && !trans->prepare_credit_phase()) {
return td::Status::Error(-669,"cannot create credit phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (!trans->prepare_storage_phase(*storage_phase_cfg, true, need_credit_phase)) {
return td::Status::Error(-669,"cannot create storage phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
}
if (!trans->prepare_compute_phase(*compute_phase_cfg)) {
return td::Status::Error(-669,"cannot create compute phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (!trans->compute_phase->accepted) {
if (!external && trans->compute_phase->skip_reason == block::ComputePhase::sk_none) {
return td::Status::Error(-669,"new ordinary transaction for smart contract "s + acc->addr.to_hex() +
" has not been accepted by the smart contract (?)");
}
}
if (trans->compute_phase->success && !trans->prepare_action_phase(*action_phase_cfg)) {
return td::Status::Error(-669,"cannot create action phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (trans->bounce_enabled && !trans->compute_phase->success && !trans->prepare_bounce_phase(*action_phase_cfg)) {
return td::Status::Error(-669,"cannot create bounce phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
return trans;
}
void TransactionEmulator::set_unixtime(ton::UnixTime unixtime) {
unixtime_ = unixtime;
}
void TransactionEmulator::set_lt(ton::LogicalTime lt) {
lt_ = lt;
}
void TransactionEmulator::set_rand_seed(td::BitArray<256>& rand_seed) {
rand_seed_ = rand_seed;
}
void TransactionEmulator::set_ignore_chksig(bool ignore_chksig) {
ignore_chksig_ = ignore_chksig;
}
void TransactionEmulator::set_config(block::Config &&config) {
config_ = std::forward<block::Config>(config);
}
void TransactionEmulator::set_libs(vm::Dictionary &&libs) {
libraries_ = std::forward<vm::Dictionary>(libs);
}
} // namespace emulator

View file

@ -0,0 +1,83 @@
#pragma once
#include "crypto/common/refcnt.hpp"
#include "ton/ton-types.h"
#include "crypto/vm/cells.h"
#include "block/transaction.h"
#include "block/block-auto.h"
#include "block/block-parse.h"
#include "block/mc-config.h"
namespace emulator {
class TransactionEmulator {
block::Config config_;
vm::Dictionary libraries_;
int vm_log_verbosity_;
ton::UnixTime unixtime_;
ton::LogicalTime lt_;
td::BitArray<256> rand_seed_;
bool ignore_chksig_;
public:
TransactionEmulator(block::Config&& config, int vm_log_verbosity = 0) :
config_(std::move(config)), libraries_(256), vm_log_verbosity_(vm_log_verbosity),
unixtime_(0), lt_(0), rand_seed_(td::BitArray<256>::zero()), ignore_chksig_(false) {
}
struct EmulationResult {
std::string vm_log;
EmulationResult(std::string vm_log_) : vm_log(vm_log_) {}
virtual ~EmulationResult() = default;
};
struct EmulationSuccess: EmulationResult {
td::Ref<vm::Cell> transaction;
block::Account account;
td::Ref<vm::Cell> actions;
EmulationSuccess(td::Ref<vm::Cell> transaction_, block::Account account_, std::string vm_log_, td::Ref<vm::Cell> actions_) :
EmulationResult(vm_log_), transaction(transaction_), account(account_) , actions(actions_)
{}
};
struct EmulationExternalNotAccepted: EmulationResult {
int vm_exit_code;
EmulationExternalNotAccepted(std::string vm_log_, int vm_exit_code_) :
EmulationResult(vm_log_), vm_exit_code(vm_exit_code_)
{}
};
struct EmulationChain {
std::vector<td::Ref<vm::Cell>> transactions;
block::Account account;
};
const block::Config& get_config() {
return config_;
}
td::Result<std::unique_ptr<EmulationResult>> emulate_transaction(
block::Account&& account, td::Ref<vm::Cell> msg_root, ton::UnixTime utime, ton::LogicalTime lt, int trans_type);
td::Result<EmulationSuccess> emulate_transaction(block::Account&& account, td::Ref<vm::Cell> original_trans);
td::Result<EmulationChain> emulate_transactions_chain(block::Account&& account, std::vector<td::Ref<vm::Cell>>&& original_transactions);
void set_unixtime(ton::UnixTime unixtime);
void set_lt(ton::LogicalTime lt);
void set_rand_seed(td::BitArray<256>& rand_seed);
void set_ignore_chksig(bool ignore_chksig);
void set_config(block::Config &&config);
void set_libs(vm::Dictionary &&libs);
private:
bool check_state_update(const block::Account& account, const block::gen::Transaction::Record& trans);
td::Result<std::unique_ptr<block::transaction::Transaction>> create_transaction(
td::Ref<vm::Cell> msg_root, block::Account* acc,
ton::UnixTime utime, ton::LogicalTime lt, int trans_type,
block::StoragePhaseConfig* storage_phase_cfg,
block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg);
};
} // namespace emulator

46
emulator/tvm-emulator.hpp Normal file
View file

@ -0,0 +1,46 @@
#pragma once
#include "smc-envelope/SmartContract.h"
namespace emulator {
class TvmEmulator {
ton::SmartContract smc_;
ton::SmartContract::Args args_;
public:
using Answer = ton::SmartContract::Answer;
TvmEmulator(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data): smc_({code, data}) {
}
void set_vm_verbosity_level(int vm_log_verbosity) {
args_.set_vm_verbosity_level(vm_log_verbosity);
}
void set_libraries(vm::Dictionary&& libraries) {
args_.set_libraries(libraries);
}
void set_gas_limit(int64_t limit) {
args_.set_limits(vm::GasLimits(limit));
}
void set_c7(block::StdAddress address, uint32_t unixtime, uint64_t balance, td::BitArray<256> rand_seed, std::shared_ptr<const block::Config> config) {
args_.set_address(address);
args_.set_now(unixtime);
args_.set_balance(balance);
args_.set_rand_seed(rand_seed);
args_.set_config(config);
}
Answer run_get_method(int method_id, td::Ref<vm::Stack> stack) {
return smc_.run_get_method(args_.set_stack(stack).set_method_id(method_id));
}
Answer send_external_message(td::Ref<vm::Cell> message_body) {
return smc_.send_external_message(message_body, args_);
}
Answer send_internal_message(td::Ref<vm::Cell> message_body, uint64_t amount) {
return smc_.send_internal_message(message_body, args_.set_amount(amount));
}
};
}

View file

@ -34,7 +34,7 @@ add_library( # Sets the name of the library.
list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/crypto/${ANDROID_ARCH_NAME}")
set(TON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_subdirectory(${TON_DIR} ton EXCLUDE_FROM_ALL)
target_link_libraries(native-lib tonlibjson_static)
target_link_libraries(native-lib tonlibjson)
target_link_libraries(native-lib tonlib)
#target_sources(native-lib PRIVATE ${ALL_TEST_SOURCE})

View file

@ -33,7 +33,7 @@ mkdir -p build-$ARCH
cd build-$ARCH
cmake .. -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DANDROID_ABI=${ABI} -DOPENSSL_ROOT_DIR=${OPENSSL_DIR}/${ARCH} -DTON_ARCH="" -DTON_ONLY_TONLIB=ON || exit 1
cmake .. -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DANDROID_ABI=${ABI} -DOPENSSL_ROOT_DIR=${OPENSSL_DIR}/${ARCH} -DTON_ARCH="" -DTON_ONLY_TONLIB=ON -DBUILD_SHARED_LIBS=OFF || exit 1
ninja native-lib || exit 1
popd

View file

@ -2,7 +2,7 @@
pushd .
mkdir -p build_native
cd build_native
cmake -DTON_ONLY_TONLIB=ON .. || exit 1
cmake -DTON_ONLY_TONLIB=ON -DBUILD_SHARED_LIBS=OFF .. || exit 1
cmake --build . --target prepare_cross_compiling || exit 2
#cmake --build . --target tl_generate_java || exit 1
popd

76
flake.lock Normal file
View file

@ -0,0 +1,76 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1650374568,
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1652776076,
"narHash": "sha256-gzTw/v1vj4dOVbpBSJX4J0DwUR6LIyXo7/SuuTJp1kM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "04c1b180862888302ddfb2e3ad9eaa63afc60cf8",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1659445012,
"narHash": "sha256-n8/7npmp3hLbPSTRHPW8EPO8qh9vJ10RgkRM3Ve4vfc=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a9f66ae640146ac16b6e33d2359e9171b27b0993",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-22.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-trunk": {
"locked": {
"lastModified": 1659597264,
"narHash": "sha256-aI/r4XEZwMJnuDjIMnSiDm34vVXP6TPaWgqPIF/65SI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "2b22614150a727a8aeedc10395dbd2ff6430841b",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"nixpkgs-stable": "nixpkgs-stable",
"nixpkgs-trunk": "nixpkgs-trunk"
}
}
},
"root": "root",
"version": 7
}

137
flake.nix Normal file
View file

@ -0,0 +1,137 @@
{
inputs = {
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-22.05";
nixpkgs-trunk.url = "github:nixos/nixpkgs";
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs-stable, nixpkgs-trunk, flake-compat, flake-utils }:
let
ton = { host, pkgs ? host, stdenv ? pkgs.stdenv, staticGlibc ? false
, staticMusl ? false, staticExternalDeps ? staticGlibc }:
with host.lib;
stdenv.mkDerivation {
pname = "ton";
version = "dev";
src = ./.;
nativeBuildInputs = with host;
[ cmake ninja pkg-config git ] ++
optionals stdenv.isLinux [ dpkg rpm createrepo_c pacman ];
buildInputs = with pkgs;
# at some point nixpkgs' pkgsStatic will build with static glibc
# then we can skip these manual overrides
# and switch between pkgsStatic and pkgsStatic.pkgsMusl for static glibc and musl builds
if !staticExternalDeps then [
openssl_1_1
zlib
libmicrohttpd
] else
[
(openssl_1_1.override { static = true; }).dev
(zlib.override { shared = false; }).dev
pkgsStatic.libmicrohttpd.dev
] ++ optional staticGlibc glibc.static;
cmakeFlags = [ "-DTON_USE_ABSEIL=OFF" "-DNIX=ON" ] ++ optionals staticMusl [
"-DCMAKE_CROSSCOMPILING=OFF" # pkgsStatic sets cross
] ++ optionals (staticGlibc || staticMusl) [
"-DCMAKE_LINK_SEARCH_START_STATIC=ON"
"-DCMAKE_LINK_SEARCH_END_STATIC=ON"
];
LDFLAGS = optional staticExternalDeps (concatStringsSep " " [
(optionalString stdenv.cc.isGNU "-static-libgcc")
"-static-libstdc++"
]);
postInstall = ''
moveToOutput bin "$bin"
'';
outputs = [ "bin" "out" ];
};
hostPkgs = system:
import nixpkgs-stable {
inherit system;
overlays = [
(self: super: {
zchunk = nixpkgs-trunk.legacyPackages.${system}.zchunk;
})
];
};
in with flake-utils.lib;
(nixpkgs-stable.lib.recursiveUpdate
(eachSystem (with system; [ x86_64-linux aarch64-linux ]) (system:
let
host = hostPkgs system;
# look out for https://github.com/NixOS/nixpkgs/issues/129595 for progress on better infra for this
#
# nixos 19.09 ships with glibc 2.27
# we could also just override glibc source to a particular release
# but then we'd need to port patches as well
nixos1909 = (import (builtins.fetchTarball {
url = "https://channels.nixos.org/nixos-19.09/nixexprs.tar.xz";
sha256 = "1vp1h2gkkrckp8dzkqnpcc6xx5lph5d2z46sg2cwzccpr8ay58zy";
}) { inherit system; });
glibc227 = nixos1909.glibc // { pname = "glibc"; };
stdenv227 = let
cc = host.wrapCCWith {
cc = nixos1909.buildPackages.gcc-unwrapped;
libc = glibc227;
bintools = host.binutils.override { libc = glibc227; };
};
in (host.overrideCC host.stdenv cc);
in rec {
packages = rec {
ton-normal = ton { inherit host; };
ton-static = ton {
inherit host;
stdenv = host.makeStatic host.stdenv;
staticGlibc = true;
};
ton-musl =
let pkgs = nixpkgs-stable.legacyPackages.${system}.pkgsStatic;
in ton {
inherit host;
inherit pkgs;
stdenv =
pkgs.gcc12Stdenv; # doesn't build on aarch64-linux w/default GCC 9
staticMusl = true;
};
ton-oldglibc = (ton {
inherit host;
stdenv = stdenv227;
staticExternalDeps = true;
});
ton-oldglibc_staticbinaries = host.symlinkJoin {
name = "ton";
paths = [ ton-musl.bin ton-oldglibc.out ];
};
};
devShells.default =
host.mkShell { inputsFrom = [ packages.ton-normal ]; };
})) (eachSystem (with system; [ x86_64-darwin aarch64-darwin ]) (system:
let host = hostPkgs system;
in rec {
packages = rec {
ton-normal = ton { inherit host; };
ton-static = ton {
inherit host;
stdenv = host.makeStatic host.stdenv;
staticExternalDeps = true;
};
ton-staticbin-dylib = host.symlinkJoin {
name = "ton";
paths = [ ton-static.bin ton-normal.out ];
};
};
devShells.default =
host.mkShell { inputsFrom = [ packages.ton-normal ]; };
})));
}

View file

@ -23,3 +23,5 @@ target_link_libraries(tonhttp PUBLIC tdactor ton_crypto tl_api tdnet )
add_executable(http-proxy http-proxy.cpp)
target_include_directories(http-proxy PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(http-proxy PRIVATE tonhttp git)
install(TARGETS http-proxy RUNTIME DESTINATION bin)

View file

@ -2,4 +2,6 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
add_executable(rldp-http-proxy rldp-http-proxy.cpp DNSResolver.h DNSResolver.cpp)
target_include_directories(rldp-http-proxy PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(rldp-http-proxy PRIVATE tonhttp rldp dht tonlib git)
target_link_libraries(rldp-http-proxy PRIVATE tonhttp rldp rldp2 dht tonlib git)
install(TARGETS rldp-http-proxy RUNTIME DESTINATION bin)

View file

@ -45,6 +45,7 @@
#include "adnl/adnl.h"
#include "rldp/rldp.h"
#include "rldp2/rldp.h"
#include "dht/dht.h"
#include <algorithm>
@ -63,6 +64,53 @@
class RldpHttpProxy;
class RldpDispatcher : public ton::adnl::AdnlSenderInterface {
public:
RldpDispatcher(td::actor::ActorId<ton::rldp::Rldp> rldp, td::actor::ActorId<ton::rldp2::Rldp> rldp2)
: rldp_(std::move(rldp)), rldp2_(std::move(rldp2)) {
}
void send_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data) override {
td::actor::send_closure(dispatch(dst), &ton::adnl::AdnlSenderInterface::send_message, src, dst, std::move(data));
}
void send_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) override {
td::actor::send_closure(dispatch(dst), &ton::adnl::AdnlSenderInterface::send_query, src, dst, std::move(name),
std::move(promise), timeout, std::move(data));
}
void send_query_ex(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data,
td::uint64 max_answer_size) override {
td::actor::send_closure(dispatch(dst), &ton::adnl::AdnlSenderInterface::send_query_ex, src, dst, std::move(name),
std::move(promise), timeout, std::move(data), max_answer_size);
}
void get_conn_ip_str(ton::adnl::AdnlNodeIdShort l_id, ton::adnl::AdnlNodeIdShort p_id,
td::Promise<td::string> promise) override {
td::actor::send_closure(rldp_, &ton::adnl::AdnlSenderInterface::get_conn_ip_str, l_id, p_id, std::move(promise));
}
void set_supports_rldp2(ton::adnl::AdnlNodeIdShort dst, bool supports) {
if (supports) {
supports_rldp2_.insert(dst);
} else {
supports_rldp2_.erase(dst);
}
}
private:
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<ton::rldp2::Rldp> rldp2_;
std::set<ton::adnl::AdnlNodeIdShort> supports_rldp2_;
td::actor::ActorId<ton::adnl::AdnlSenderInterface> dispatch(ton::adnl::AdnlNodeIdShort dst) const {
if (supports_rldp2_.count(dst)) {
return rldp2_;
}
return rldp_;
}
};
class HttpRemote : public td::actor::Actor {
public:
struct Query {
@ -137,6 +185,8 @@ const std::string PROXY_SITE_VERISON_HEADER_NAME = "Ton-Proxy-Site-Version";
const std::string PROXY_ENTRY_VERISON_HEADER_NAME = "Ton-Proxy-Entry-Version";
const std::string PROXY_VERSION_HEADER = PSTRING() << "Commit: " << GitMetadata::CommitSHA1()
<< ", Date: " << GitMetadata::CommitDate();
const td::uint64 CAPABILITY_RLDP2 = 1;
const td::uint64 CAPABILITIES = 1;
using RegisteredPayloadSenderGuard =
std::unique_ptr<std::pair<td::actor::ActorId<RldpHttpProxy>, td::Bits256>,
@ -146,8 +196,8 @@ class HttpRldpPayloadReceiver : public td::actor::Actor {
public:
HttpRldpPayloadReceiver(std::shared_ptr<ton::http::HttpPayload> payload, td::Bits256 transfer_id,
ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort local_id,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::actor::ActorId<ton::rldp::Rldp> rldp,
bool is_tunnel = false)
td::actor::ActorId<ton::adnl::Adnl> adnl,
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp, bool is_tunnel = false)
: payload_(std::move(payload))
, id_(transfer_id)
, src_(src)
@ -204,8 +254,8 @@ class HttpRldpPayloadReceiver : public td::actor::Actor {
auto f = ton::create_serialize_tl_object<ton::ton_api::http_getNextPayloadPart>(
id_, seqno_++, static_cast<td::int32>(chunk_size()));
auto timeout = td::Timestamp::in(is_tunnel_ ? 60.0 : 15.0);
td::actor::send_closure(rldp_, &ton::rldp::Rldp::send_query_ex, local_id_, src_, "payload part", std::move(P),
timeout, std::move(f), 2 * chunk_size() + 1024);
td::actor::send_closure(rldp_, &ton::adnl::AdnlSenderInterface::send_query_ex, local_id_, src_, "payload part",
std::move(P), timeout, std::move(f), 2 * chunk_size() + 1024);
}
void add_data(td::BufferSlice data) {
@ -265,7 +315,7 @@ class HttpRldpPayloadReceiver : public td::actor::Actor {
ton::adnl::AdnlNodeIdShort src_;
ton::adnl::AdnlNodeIdShort local_id_;
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp_;
bool sent_ = false;
td::int32 seqno_ = 0;
@ -276,8 +326,8 @@ class HttpRldpPayloadSender : public td::actor::Actor {
public:
HttpRldpPayloadSender(std::shared_ptr<ton::http::HttpPayload> payload, td::Bits256 transfer_id,
ton::adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ton::adnl::Adnl> adnl,
td::actor::ActorId<ton::rldp::Rldp> rldp, td::actor::ActorId<RldpHttpProxy> proxy,
bool is_tunnel = false)
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp,
td::actor::ActorId<RldpHttpProxy> proxy, bool is_tunnel = false)
: payload_(std::move(payload))
, id_(transfer_id)
, local_id_(local_id)
@ -407,7 +457,7 @@ class HttpRldpPayloadSender : public td::actor::Actor {
ton::adnl::AdnlNodeIdShort local_id_;
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp_;
td::actor::ActorId<RldpHttpProxy> proxy_;
size_t cur_query_size_;
@ -424,9 +474,8 @@ class TcpToRldpRequestSender : public td::actor::Actor {
std::shared_ptr<ton::http::HttpPayload> request_payload,
td::Promise<std::pair<std::unique_ptr<ton::http::HttpResponse>, std::shared_ptr<ton::http::HttpPayload>>> promise,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::actor::ActorId<ton::dht::Dht> dht,
td::actor::ActorId<ton::rldp::Rldp> rldp, td::actor::ActorId<RldpHttpProxy> proxy,
td::actor::ActorId<DNSResolver> dns_resolver,
ton::adnl::AdnlNodeIdShort storage_gateway)
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp, td::actor::ActorId<RldpHttpProxy> proxy,
td::actor::ActorId<DNSResolver> dns_resolver, ton::adnl::AdnlNodeIdShort storage_gateway)
: local_id_(local_id)
, host_(std::move(host))
, request_(std::move(request))
@ -447,26 +496,7 @@ class TcpToRldpRequestSender : public td::actor::Actor {
}
void resolve(std::string host);
void resolved(ton::adnl::AdnlNodeIdShort id) {
dst_ = id;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::got_result, R.move_as_ok());
}
});
td::actor::create_actor<HttpRldpPayloadSender>("HttpPayloadSender", request_payload_, id_, local_id_, adnl_, rldp_,
proxy_, is_tunnel())
.release();
auto f = ton::serialize_tl_object(request_tl_, true);
td::actor::send_closure(rldp_, &ton::rldp::Rldp::send_query_ex, local_id_, dst_, "http request over rldp",
std::move(P), td::Timestamp::in(30.0), std::move(f), 16 << 10);
}
void resolved(ton::adnl::AdnlNodeIdShort id);
void got_result(td::BufferSlice data) {
auto F = ton::fetch_tl_object<ton::ton_api::http_response>(data, true);
@ -548,7 +578,7 @@ class TcpToRldpRequestSender : public td::actor::Actor {
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::dht::Dht> dht_;
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp_;
td::actor::ActorId<RldpHttpProxy> proxy_;
td::actor::ActorId<DNSResolver> dns_resolver_;
ton::adnl::AdnlNodeIdShort storage_gateway_ = ton::adnl::AdnlNodeIdShort::zero();
@ -562,7 +592,7 @@ class TcpToRldpRequestSender : public td::actor::Actor {
class RldpTcpTunnel : public td::actor::Actor, private td::ObserverBase {
public:
RldpTcpTunnel(td::Bits256 transfer_id, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort local_id,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::actor::ActorId<ton::rldp::Rldp> rldp,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp,
td::actor::ActorId<RldpHttpProxy> proxy, td::SocketFd fd)
: id_(transfer_id)
, src_(src)
@ -599,8 +629,8 @@ class RldpTcpTunnel : public td::actor::Actor, private td::ObserverBase {
auto f = ton::create_serialize_tl_object<ton::ton_api::http_getNextPayloadPart>(id_, out_seqno_++,
(1 << 21) - (1 << 11));
td::actor::send_closure(rldp_, &ton::rldp::Rldp::send_query_ex, local_id_, src_, "payload part", std::move(P),
td::Timestamp::in(60.0), std::move(f), (1 << 21) + 1024);
td::actor::send_closure(rldp_, &ton::adnl::AdnlSenderInterface::send_query_ex, local_id_, src_, "payload part",
std::move(P), td::Timestamp::in(60.0), std::move(f), (1 << 21) + 1024);
}
void receive_query(ton::tl_object_ptr<ton::ton_api::http_getNextPayloadPart> f,
@ -727,7 +757,7 @@ class RldpTcpTunnel : public td::actor::Actor, private td::ObserverBase {
ton::adnl::AdnlNodeIdShort src_;
ton::adnl::AdnlNodeIdShort local_id_;
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp_;
td::actor::ActorId<RldpHttpProxy> proxy_;
td::BufferedFd<td::SocketFd> fd_;
@ -746,7 +776,8 @@ class RldpToTcpRequestSender : public td::actor::Actor {
RldpToTcpRequestSender(td::Bits256 id, ton::adnl::AdnlNodeIdShort local_id, ton::adnl::AdnlNodeIdShort dst,
std::unique_ptr<ton::http::HttpRequest> request,
std::shared_ptr<ton::http::HttpPayload> request_payload, td::Promise<td::BufferSlice> promise,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::actor::ActorId<ton::rldp::Rldp> rldp,
td::actor::ActorId<ton::adnl::Adnl> adnl,
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp,
td::actor::ActorId<RldpHttpProxy> proxy, td::actor::ActorId<HttpRemote> remote)
: id_(id)
, local_id_(local_id)
@ -806,7 +837,7 @@ class RldpToTcpRequestSender : public td::actor::Actor {
td::Promise<td::BufferSlice> promise_;
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<ton::adnl::AdnlSenderInterface> rldp_;
td::actor::ActorId<RldpHttpProxy> proxy_;
td::actor::ActorId<HttpRemote> remote_;
@ -1032,35 +1063,58 @@ class RldpHttpProxy : public td::actor::Actor {
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
for (auto &serv_id : server_ids_) {
class AdnlCb : public ton::adnl::Adnl::Callback {
public:
AdnlCb(td::actor::ActorId<RldpHttpProxy> id) : self_id_(id) {
}
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(self_id_, &RldpHttpProxy::receive_rldp_request, src, dst, std::move(data),
std::move(promise));
}
class AdnlCapabilitiesCb : public ton::adnl::Adnl::Callback {
public:
AdnlCapabilitiesCb(td::actor::ActorId<RldpHttpProxy> id) : self_id_(id) {
}
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
TRY_RESULT_PROMISE(promise, query, ton::fetch_tl_object<ton::ton_api::http_proxy_getCapabilities>(data, true));
promise.set_result(ton::create_serialize_tl_object<ton::ton_api::http_proxy_capabilities>(CAPABILITIES));
td::actor::send_closure(self_id_, &RldpHttpProxy::update_peer_capabilities, src, query->capabilities_);
}
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
class AdnlServerCb : public ton::adnl::Adnl::Callback {
public:
AdnlServerCb(td::actor::ActorId<RldpHttpProxy> id) : self_id_(id) {
}
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(self_id_, &RldpHttpProxy::receive_rldp_request, src, dst, std::move(data),
std::move(promise));
}
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
for (auto &serv_id : server_ids_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, serv_id,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_request::ID),
std::make_unique<AdnlCb>(actor_id(this)));
std::make_unique<AdnlServerCb>(actor_id(this)));
if (local_id_ != serv_id) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, serv_id,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_getNextPayloadPart::ID),
std::make_unique<AdnlPayloadCb>(actor_id(this)));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, serv_id,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_proxy_getCapabilities::ID),
std::make_unique<AdnlCapabilitiesCb>(actor_id(this)));
}
}
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, local_id_,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_getNextPayloadPart::ID),
std::make_unique<AdnlPayloadCb>(actor_id(this)));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, local_id_,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_proxy_getCapabilities::ID),
std::make_unique<AdnlCapabilitiesCb>(actor_id(this)));
rldp_ = ton::rldp::Rldp::create(adnl_.get());
td::actor::send_closure(rldp_, &ton::rldp::Rldp::set_default_mtu, 16 << 10);
@ -1069,6 +1123,15 @@ class RldpHttpProxy : public td::actor::Actor {
td::actor::send_closure(rldp_, &ton::rldp::Rldp::add_id, serv_id);
}
rldp2_ = ton::rldp2::Rldp::create(adnl_.get());
td::actor::send_closure(rldp2_, &ton::rldp2::Rldp::set_default_mtu, 16 << 10);
td::actor::send_closure(rldp2_, &ton::rldp2::Rldp::add_id, local_id_);
for (auto &serv_id : server_ids_) {
td::actor::send_closure(rldp2_, &ton::rldp2::Rldp::add_id, serv_id);
}
rldp_dispatcher_ = td::actor::create_actor<RldpDispatcher>("RldpDispatcher", rldp_.get(), rldp2_.get());
store_dht();
}
@ -1107,7 +1170,7 @@ class RldpHttpProxy : public td::actor::Actor {
}
std::transform(host.begin(), host.end(), host.begin(), [](unsigned char c) { return std::tolower(c); });
bool allow = proxy_all_;
for (const char* suffix : {".adnl", ".ton", ".bag"}) {
for (const char *suffix : {".adnl", ".ton", ".bag"}) {
if (td::ends_with(host, td::Slice(suffix))) {
allow = true;
}
@ -1117,9 +1180,9 @@ class RldpHttpProxy : public td::actor::Actor {
return;
}
td::actor::create_actor<TcpToRldpRequestSender>("outboundreq", local_id_, host, std::move(request),
std::move(payload), std::move(promise), adnl_.get(), dht_.get(),
rldp_.get(), actor_id(this), dns_resolver_.get(), storage_gateway_)
td::actor::create_actor<TcpToRldpRequestSender>(
"outboundreq", local_id_, host, std::move(request), std::move(payload), std::move(promise), adnl_.get(),
dht_.get(), rldp_dispatcher_.get(), actor_id(this), dns_resolver_.get(), storage_gateway_)
.release();
}
@ -1127,6 +1190,7 @@ class RldpHttpProxy : public td::actor::Actor {
td::Promise<td::BufferSlice> promise) {
LOG(INFO) << "got HTTP request over rldp from " << src;
TRY_RESULT_PROMISE(promise, f, ton::fetch_tl_object<ton::ton_api::http_request>(data, true));
ask_peer_capabilities(src);
std::unique_ptr<ton::http::HttpRequest> request;
auto S = [&]() {
TRY_RESULT_ASSIGN(request, ton::http::HttpRequest::create(f->method_, f->url_, f->http_version_));
@ -1214,8 +1278,8 @@ class RldpHttpProxy : public td::actor::Actor {
LOG(INFO) << "starting HTTP over RLDP request";
td::actor::create_actor<RldpToTcpRequestSender>("inboundreq", f->id_, dst, src, std::move(request),
payload.move_as_ok(), std::move(promise), adnl_.get(), rldp_.get(),
actor_id(this), server.http_remote_.get())
payload.move_as_ok(), std::move(promise), adnl_.get(),
rldp_dispatcher_.get(), actor_id(this), server.http_remote_.get())
.release();
}
@ -1227,7 +1291,7 @@ class RldpHttpProxy : public td::actor::Actor {
return;
}
td::actor::create_actor<RldpTcpTunnel>(td::actor::ActorOptions().with_name("tunnel").with_poll(), id, src, local_id,
adnl_.get(), rldp_.get(), actor_id(this), fd.move_as_ok())
adnl_.get(), rldp_dispatcher_.get(), actor_id(this), fd.move_as_ok())
.release();
std::vector<ton::tl_object_ptr<ton::ton_api::http_header>> headers;
headers.push_back(
@ -1291,6 +1355,47 @@ class RldpHttpProxy : public td::actor::Actor {
storage_gateway_ = id;
}
void update_peer_capabilities(ton::adnl::AdnlNodeIdShort peer, td::uint64 capabilities) {
auto &c = peer_capabilities_[peer];
if (c.capabilities != capabilities) {
LOG(DEBUG) << "Update capabilities of peer " << peer << " : " << capabilities;
}
c.capabilities = capabilities;
c.received = true;
td::actor::send_closure(rldp_dispatcher_, &RldpDispatcher::set_supports_rldp2, peer,
capabilities & CAPABILITY_RLDP2);
}
void ask_peer_capabilities(ton::adnl::AdnlNodeIdShort peer) {
auto &c = peer_capabilities_[peer];
if (!c.received && c.retry_at.is_in_past()) {
c.retry_at = td::Timestamp::in(30.0);
auto send_query = [&, this, SelfId = actor_id(this)](const ton::adnl::AdnlNodeIdShort &local_id) {
td::actor::send_closure(
adnl_, &ton::adnl::Adnl::send_query, local_id, peer, "q",
[SelfId, peer](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
return;
}
auto r_obj = ton::fetch_tl_object<ton::ton_api::http_proxy_capabilities>(R.move_as_ok(), true);
if (r_obj.is_error()) {
return;
}
td::actor::send_closure(SelfId, &RldpHttpProxy::update_peer_capabilities, peer,
r_obj.ok()->capabilities_);
},
td::Timestamp::in(3.0),
ton::create_serialize_tl_object<ton::ton_api::http_proxy_getCapabilities>(CAPABILITIES));
};
for (const ton::adnl::AdnlNodeIdShort &local_id : server_ids_) {
if (local_id != local_id_) {
send_query(local_id);
}
}
send_query(local_id_);
}
}
private:
struct Host {
struct Server {
@ -1320,6 +1425,8 @@ class RldpHttpProxy : public td::actor::Actor {
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
td::actor::ActorOwn<ton::dht::Dht> dht_;
td::actor::ActorOwn<ton::rldp::Rldp> rldp_;
td::actor::ActorOwn<ton::rldp2::Rldp> rldp2_;
td::actor::ActorOwn<RldpDispatcher> rldp_dispatcher_;
std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config_;
@ -1333,6 +1440,13 @@ class RldpHttpProxy : public td::actor::Actor {
std::map<td::Bits256,
std::function<void(ton::tl_object_ptr<ton::ton_api::http_getNextPayloadPart>, td::Promise<td::BufferSlice>)>>
payload_senders_;
struct PeerCapabilities {
td::uint64 capabilities = 0;
bool received = false;
td::Timestamp retry_at = td::Timestamp::now();
};
std::map<ton::adnl::AdnlNodeIdShort, PeerCapabilities> peer_capabilities_;
};
void TcpToRldpRequestSender::resolve(std::string host) {
@ -1355,7 +1469,7 @@ void TcpToRldpRequestSender::resolve(std::string host) {
}
request_tl_->url_ = (PSTRING() << "/gateway/" << bag_id << url);
host = storage_gateway_.serialize() + ".adnl";
for (auto& header : request_tl_->headers_) {
for (auto &header : request_tl_->headers_) {
if (td::to_lower(header->name_) == "host") {
header->value_ = host;
break;
@ -1390,6 +1504,27 @@ void TcpToRldpRequestSender::resolve(std::string host) {
});
}
void TcpToRldpRequestSender::resolved(ton::adnl::AdnlNodeIdShort id) {
dst_ = id;
td::actor::send_closure(proxy_, &RldpHttpProxy::ask_peer_capabilities, id);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::got_result, R.move_as_ok());
}
});
td::actor::create_actor<HttpRldpPayloadSender>("HttpPayloadSender", request_payload_, id_, local_id_, adnl_, rldp_,
proxy_, is_tunnel())
.release();
auto f = ton::serialize_tl_object(request_tl_, true);
td::actor::send_closure(rldp_, &ton::adnl::AdnlSenderInterface::send_query_ex, local_id_, dst_,
"http request over rldp", std::move(P), td::Timestamp::in(30.0), std::move(f), 16 << 10);
}
void HttpRldpPayloadSender::start_up() {
td::actor::send_closure(
proxy_, &RldpHttpProxy::register_payload_sender, id_,

View file

@ -92,6 +92,8 @@ class RldpIn : public RldpImpl {
void get_conn_ip_str(adnl::AdnlNodeIdShort l_id, adnl::AdnlNodeIdShort p_id, td::Promise<td::string> promise) override;
void set_default_mtu(td::uint64 mtu) override;
RldpIn(td::actor::ActorId<adnl::AdnlPeerTable> adnl) : adnl_(adnl) {
}
@ -107,6 +109,8 @@ class RldpIn : public RldpImpl {
std::set<adnl::AdnlNodeIdShort> local_ids_;
td::optional<td::uint64> custom_default_mtu_;
td::actor::ActorId<RldpConnectionActor> create_connection(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst);
};

View file

@ -44,6 +44,9 @@ class RldpConnectionActor : public td::actor::Actor, private ConnectionCallback
connection_.receive_raw(std::move(data));
yield();
}
void set_default_mtu(td::uint64 mtu) {
connection_.set_default_mtu(mtu);
}
private:
td::actor::ActorId<RldpIn> rldp_;
@ -129,6 +132,9 @@ td::actor::ActorId<RldpConnectionActor> RldpIn::create_connection(adnl::AdnlNode
return it->second.get();
}
auto connection = td::actor::create_actor<RldpConnectionActor>("RldpConnection", actor_id(this), src, dst, adnl_);
if (custom_default_mtu_) {
td::actor::send_closure(connection, &RldpConnectionActor::set_default_mtu, custom_default_mtu_.value());
}
auto res = connection.get();
connections_[std::make_pair(src, dst)] = std::move(connection);
return res;
@ -221,6 +227,13 @@ void RldpIn::get_conn_ip_str(adnl::AdnlNodeIdShort l_id, adnl::AdnlNodeIdShort p
td::actor::send_closure(adnl_, &adnl::AdnlPeerTable::get_conn_ip_str, l_id, p_id, std::move(promise));
}
void RldpIn::set_default_mtu(td::uint64 mtu) {
custom_default_mtu_ = mtu;
for (auto &connection : connections_) {
td::actor::send_closure(connection.second, &RldpConnectionActor::set_default_mtu, mtu);
}
}
std::unique_ptr<adnl::Adnl::Callback> RldpIn::make_adnl_callback() {
class Callback : public adnl::Adnl::Callback {
private:

View file

@ -37,6 +37,8 @@ class Rldp : public adnl::AdnlSenderInterface {
virtual void send_message_ex(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::Timestamp timeout,
td::BufferSlice data) = 0;
virtual void set_default_mtu(td::uint64 mtu) = 0;
static td::actor::ActorOwn<Rldp> create(td::actor::ActorId<adnl::Adnl> adnl);
};

10
shell.nix Normal file
View file

@ -0,0 +1,10 @@
(import
(
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
)
{ src = ./.; }
).shellNix

View file

@ -36,7 +36,7 @@ set(STORAGE_CLI_SOURCE
storage-cli.cpp
)
add_library(storage ${STORAGE_SOURCE})
add_library(storage STATIC ${STORAGE_SOURCE})
target_link_libraries(storage tdutils tdactor tddb ton_crypto tl_api ${JEMALLOC_LIBRARIES})
target_include_directories(storage PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
@ -54,4 +54,4 @@ set(STORAGE_TEST_SOURCE
add_subdirectory(storage-daemon)
# Do not install it yet
#install(TARGETS storage-cli RUNTIME DESTINATION bin)
install(TARGETS storage-cli storage-daemon storage-daemon-cli RUNTIME DESTINATION bin)

View file

@ -258,9 +258,13 @@ void StorageProvider::process_transaction(tl_object_ptr<tonlib_api::raw_transact
}
td::Ref<vm::Cell> body = r_body.move_as_ok();
vm::CellSlice cs = vm::load_cell_slice(body);
// const op::offer_storage_contract = 0x107c49ef;
if (cs.size() >= 32 && cs.prefetch_long(32) == 0x107c49ef) {
new_contract_address = message->destination_->account_address_;
if (cs.size() >= 32) {
long long op_code = cs.prefetch_long(32);
// const op::offer_storage_contract = 0x107c49ef; -- old versions
// const op::deploy_storage_contract = 0xe4748df1; -- new versions
if((op_code == 0x107c49ef) || (op_code == 0xe4748df1)) {
new_contract_address = message->destination_->account_address_;
}
}
}
if (!new_contract_address.empty()) {

View file

@ -1,4 +1,5 @@
const op::offer_storage_contract = 0x107c49ef;
const op::deploy_storage_contract = 0xe4748df1;
const op::close_contract = 0x79f937ea;
const op::contract_deployed = 0xbf7bd0c1;
const op::storage_contract_confirmed = 0xd4caedcd;

View file

@ -76,7 +76,7 @@ int check_proof(int merkle_hash, int byte_to_proof, int file_size, cell file_dic
int query_id = in_msg_body~load_uint(64);
if(op == op::offer_storage_contract) {
if(op == op::deploy_storage_contract) {
add_to_balance(msg_value - 2 * fee::receipt_value);
var (client, torrent_hash) = get_client_data(get_data().begin_parse());
var msg = begin_cell()
@ -263,4 +263,4 @@ _ get_next_proof_info() method_id {
next_proof, rate_per_mb_day, max_span, last_proof_time,
client, torrent_hash) = get_storage_contract_data();
return (next_proof, last_proof_time, max_span);
}
}

View file

@ -111,7 +111,7 @@ PROGRAM{
}> // msg_value sender_address op in_msg_body
64 LDU // msg_value sender_address op query_id in_msg_body
s2 PUSH
276580847 PUSHINT // msg_value sender_address op query_id in_msg_body op _27=276580847
3832843761 PUSHINT // msg_value sender_address op query_id in_msg_body op _27=3832843761
EQUAL // msg_value sender_address op query_id in_msg_body _28
IF:<{ // msg_value sender_address op query_id in_msg_body
s0 s4 XCHG

View file

@ -4,7 +4,10 @@
const min_deploy_amount = 50000000;
cell storage_contract_code() asm """ "storage-contract-code.boc" file>B B>boc PUSHREF """;
;; cell storage_contract_code() asm """ "storage-contract-code.boc" file>B B>boc PUSHREF """;
;; the same constant but more "compiler" friendly
cell storage_contract_code() asm " B{B5EE9C72010213010002FD000114FF00F4A413F4BCF2C80B0102016202030202CE04050201200D0E020120060700115D74CD0FA40D3FF30804E1007434C0C05C6C2497C0F83E900C0871C023A0D6F6CF380074C7C8700023A117C0F6CF3834CFC8A084391D237C6EA3AD4120829896802876CF3B51343C00E0842FDEF4305C20063232C1540133C5A0824C4B403E8084F2DA84B2C7D48832CFF2FFF25C3EC0244D388860841E8D85A22EA008080809006F35CE6CE4D7C11C3834C1C070C0E4D7C11C3834FFC12F64D7C0DC3800B50C1C25A010086B092E64693A0CC06AC140BD039BE84C645FF81C20002CED44D0D200FA0003A001C8CA0001FA0201CF16C9ED5403E68E4FED44D0D200FA00FA4003B3F2E3EF5350C705F2E1917FC8CA0058FA0201CF1621CF16C9ED54F003F8258210D4CAEDCD708018C8CB055005CF168209312D00FA0214CB6A13CB1F12CB3FCBFFC970FB00DE21821079F937EABAE30221821046ED2E94BA9130E30D8210419D5D4DBA915BE30D0A0B0C00EA10235F03ED44D0D200FA00FA40F0035352C7055162C70516B1F2E191F8258210B6236D63708018C8CB055004CF165005FA0212CB6A13CB1F12CB3F5230CBFFC902B39730318100A0FB00E0018040FB00F8258210B6236D63708018C8CB055004CF1623FA0213CB6A12CB1FCB3FCBFFC98100A0FB000092ED44D0D200FA00FA403002F2E3EB5341C705F2E19120C200998208989680A072FB029130E28210A91BAF56708018C8CB055003CF168209312D00FA0212CB6ACB1FCB3FC98100A0FB0000FA01D430ED44D0D200FA00FA40D3FFD33FD33FFA00D31FD31FD43009F2E3EB53A6C705F2E191544540525BF001F2E3EA22F811F8235003A128B6085331A8018102A3AA1AA984067007A116B609F8237FC8CA0058FA025005CF1613CBFFCB3FCB3F58FA0213CB1F12CB1FCCC9ED54708018C8CB0558CF16CB6EC98042FB000201200F100011BEE6576A2686B8500402012011120033B9241ED44D0D200FA00FA40D3FFD33FD33FFA00D31FD31FF00380017B6E4F0402A483DA87B0D9430001BB7CA50402A483DA87B0B664D8A70} B>boc PUSHREF ";
slice calculate_address_by_stateinit(cell state_init) {
return begin_cell().store_uint(4, 3)
@ -67,7 +70,7 @@ cell build_storage_contract_stateinit(int merkle_hash, int file_size, int rate_p
.store_coins(0)
.store_uint(4 + 2, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
.store_ref(state_init)
.store_uint(op::offer_storage_contract, 32)
.store_uint(op::deploy_storage_contract, 32)
.store_uint(query_id, 64)
.end_cell();
send_raw_message(msg, 64);

View file

@ -52,7 +52,7 @@ PROGRAM{
STREF // _33
ENDC // data
0 PUSHINT // data _36=0
"storage-contract-code.boc" file>B B>boc PUSHREF // data _36=0 _37
B{B5EE9C72010213010002FD000114FF00F4A413F4BCF2C80B0102016202030202CE04050201200D0E020120060700115D74CD0FA40D3FF30804E1007434C0C05C6C2497C0F83E900C0871C023A0D6F6CF380074C7C8700023A117C0F6CF3834CFC8A084391D237C6EA3AD4120829896802876CF3B51343C00E0842FDEF4305C20063232C1540133C5A0824C4B403E8084F2DA84B2C7D48832CFF2FFF25C3EC0244D388860841E8D85A22EA008080809006F35CE6CE4D7C11C3834C1C070C0E4D7C11C3834FFC12F64D7C0DC3800B50C1C25A010086B092E64693A0CC06AC140BD039BE84C645FF81C20002CED44D0D200FA0003A001C8CA0001FA0201CF16C9ED5403E68E4FED44D0D200FA00FA4003B3F2E3EF5350C705F2E1917FC8CA0058FA0201CF1621CF16C9ED54F003F8258210D4CAEDCD708018C8CB055005CF168209312D00FA0214CB6A13CB1F12CB3FCBFFC970FB00DE21821079F937EABAE30221821046ED2E94BA9130E30D8210419D5D4DBA915BE30D0A0B0C00EA10235F03ED44D0D200FA00FA40F0035352C7055162C70516B1F2E191F8258210B6236D63708018C8CB055004CF165005FA0212CB6A13CB1F12CB3F5230CBFFC902B39730318100A0FB00E0018040FB00F8258210B6236D63708018C8CB055004CF1623FA0213CB6A12CB1FCB3FCBFFC98100A0FB000092ED44D0D200FA00FA403002F2E3EB5341C705F2E19120C200998208989680A072FB029130E28210A91BAF56708018C8CB055003CF168209312D00FA0212CB6ACB1FCB3FC98100A0FB0000FA01D430ED44D0D200FA00FA40D3FFD33FD33FFA00D31FD31FD43009F2E3EB53A6C705F2E191544540525BF001F2E3EA22F811F8235003A128B6085331A8018102A3AA1AA984067007A116B609F8237FC8CA0058FA025005CF1613CBFFCB3FCB3F58FA0213CB1F12CB1FCCC9ED54708018C8CB0558CF16CB6EC98042FB000201200F100011BEE6576A2686B8500402012011120033B9241ED44D0D200FA00FA40D3FFD33FD33FFA00D31FD31FF00380017B6E4F0402A483DA87B0D9430001BB7CA50402A483DA87B0B664D8A70} B>boc PUSHREF // data _36=0 _37
OVER // data _36=0 _37 _38=0
NEWC // data _36=0 _37 _38=0 _39
2 STU // data _36=0 _37 _41
@ -93,19 +93,19 @@ PROGRAM{
s1 s5 XCHG
s1 s6 XCHG // query_id merkle_hash file_size rate_per_mb_day max_span client torrent_hash
build_storage_contract_stateinit CALLDICT // query_id state_init
276580847 PUSHINT // query_id state_init _54=276580847
6 PUSHINT // query_id state_init _54=276580847 _57
24 PUSHINT // query_id state_init _54=276580847 _57 _58=24
NEWC // query_id state_init _54=276580847 _57 _58=24 _59
6 STU // query_id state_init _54=276580847 _57 _61
s3 PUSH // query_id state_init _54=276580847 _57 _61 state_init
calculate_address_by_stateinit CALLDICT // query_id state_init _54=276580847 _57 _61 _62
STSLICER // query_id state_init _54=276580847 _57 _63
0 PUSHINT // query_id state_init _54=276580847 _57 _63 _64=0
STGRAMS // query_id state_init _54=276580847 _57 _65
108 STU // query_id state_init _54=276580847 _81
s1 s2 XCHG // query_id _54=276580847 state_init _81
STREF // query_id _54=276580847 _82
3832843761 PUSHINT // query_id state_init _54=3832843761
6 PUSHINT // query_id state_init _54=3832843761 _57
24 PUSHINT // query_id state_init _54=3832843761 _57 _58=24
NEWC // query_id state_init _54=3832843761 _57 _58=24 _59
6 STU // query_id state_init _54=3832843761 _57 _61
s3 PUSH // query_id state_init _54=3832843761 _57 _61 state_init
calculate_address_by_stateinit CALLDICT // query_id state_init _54=3832843761 _57 _61 _62
STSLICER // query_id state_init _54=3832843761 _57 _63
0 PUSHINT // query_id state_init _54=3832843761 _57 _63 _64=0
STGRAMS // query_id state_init _54=3832843761 _57 _65
108 STU // query_id state_init _54=3832843761 _81
s1 s2 XCHG // query_id _54=3832843761 state_init _81
STREF // query_id _54=3832843761 _82
32 STU // query_id _84
64 STU // _86
ENDC // msg
@ -113,6 +113,7 @@ PROGRAM{
SENDRAWMSG
}>
recv_internal PROC:<{
c2 SAVE
SAMEALTSAVE // msg_value in_msg_full in_msg_body
SWAP // msg_value in_msg_body in_msg_full
CTOS // msg_value in_msg_body cs

View file

@ -14,8 +14,9 @@ if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "lib")
endif()
find_package(PkgConfig REQUIRED)
if (NOT ZLIB_FOUND)
find_package(ZLIB)
pkg_check_modules(ZLIB zlib)
endif()
if (ZLIB_FOUND)
set(TD_HAVE_ZLIB 1)

View file

@ -60,7 +60,7 @@ Result<T> read_file_impl(CSlice path, int64 size, int64 offset) {
if (size == -1) {
size = file_size - offset;
} else if (size >= 0) {
if (size + offset > file_size) {
if (size > file_size - offset) {
size = file_size - offset;
}
}

View file

@ -170,8 +170,8 @@ TEST(Misc, TsList) {
TEST(Misc, TsListConcurrent) {
td::TsList<ListData> root;
td::vector<td::thread> threads;
std::atomic<td::uint64> id{0};
td::vector<td::thread> threads;
for (std::size_t i = 0; i < 4; i++) {
threads.emplace_back(
[&] { do_run_list_test<td::TsListNode<ListData>, td::TsList<ListData>, td::TsListNode<ListData>>(root, id); });

View file

@ -720,11 +720,13 @@ storage.getPiece piece_id:int = storage.Piece;
http.header name:string value:string = http.Header;
http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart;
http.response http_version:string status_code:int reason:string headers:(vector http.header) no_payload:Bool = http.Response;
http.proxy.capabilities capabilities:long = http.proxy.Capabilities;
---functions---
http.request id:int256 method:string url:string http_version:string headers:(vector http.header) = http.Response;
http.getNextPayloadPart id:int256 seqno:int max_chunk_size:int = http.PayloadPart;
http.proxy.getCapabilities capabilities:long = http.proxy.Capabilities;
---types---

Binary file not shown.

View file

@ -257,6 +257,7 @@ getBip39Hints prefix:string = Bip39Hints;
//raw.init initial_account_state:raw.initialAccountState = Ok;
raw.getAccountState account_address:accountAddress = raw.FullAccountState;
raw.getAccountStateByTransaction account_address:accountAddress transaction_id:internal.transactionId = raw.FullAccountState;
raw.getTransactions private_key:InputKey account_address:accountAddress from_transaction_id:internal.transactionId = raw.Transactions;
raw.getTransactionsV2 private_key:InputKey account_address:accountAddress from_transaction_id:internal.transactionId count:# try_decode_messages:Bool = raw.Transactions;
raw.sendMessage body:bytes = Ok;
@ -278,9 +279,13 @@ guessAccountRevision initial_account_state:InitialAccountState workchain_id:int3
guessAccount public_key:string rwallet_init_public_key:string = AccountRevisionList;
getAccountState account_address:accountAddress = FullAccountState;
getAccountStateByTransaction account_address:accountAddress transaction_id:internal.transactionId = FullAccountState;
getShardAccountCell account_address:accountAddress = tvm.Cell;
getShardAccountCellByTransaction account_address:accountAddress transaction_id:internal.transactionId = tvm.Cell;
createQuery private_key:InputKey address:accountAddress timeout:int32 action:Action initial_account_state:InitialAccountState = query.Info;
getConfigParam mode:# id:ton.blockIdExt param:# = ConfigInfo;
getConfigParam mode:# param:# = ConfigInfo;
getConfigAll mode:# = ConfigInfo;
msg.decrypt input_key:InputKey data:msg.dataEncryptedArray = msg.DataDecryptedArray;
msg.decryptWithProof proof:bytes data:msg.dataEncrypted = msg.Data;
@ -292,6 +297,7 @@ query.estimateFees id:int53 ignore_chksig:Bool = query.Fees;
query.getInfo id:int53 = query.Info;
smc.load account_address:accountAddress = smc.Info;
smc.loadByTransaction account_address:accountAddress transaction_id:internal.transactionId = smc.Info;
smc.forget id:int53 = Ok;
smc.getCode id:int53 = tvm.Cell;
smc.getData id:int53 = tvm.Cell;

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more