mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Compare commits
74 commits
v2024.12-1
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
0439613bff | ||
|
cf50b4b5da | ||
|
6eeae5d78b | ||
|
faf58118a4 | ||
|
f67e9f4b6f | ||
|
ef0328837f | ||
|
7bcb8b895f | ||
|
f3e620f48c | ||
|
44e7e091b2 | ||
|
b3b2bd1c3c | ||
|
1389ff6789 | ||
|
1b70e48327 | ||
|
3ff951c225 | ||
|
901467f424 | ||
|
1e8fdc0561 | ||
|
61b9155d15 | ||
|
8a08bf67a2 | ||
|
04f2bc1360 | ||
|
aca51a8dae | ||
|
9d94e04d20 | ||
|
ce6c29941e | ||
|
2a68c8610b | ||
|
aef538114a | ||
|
050a984163 | ||
|
3c245c6146 | ||
|
c7271d97ae | ||
|
e5feb76b90 | ||
|
b1c9466df4 | ||
|
e9d8f1611b | ||
|
5b44e01455 | ||
|
7a1602f591 | ||
|
565bc59735 | ||
|
989629a832 | ||
|
c720204199 | ||
|
294db69227 | ||
|
6f1feb43d5 | ||
|
8ffa3dd9dc | ||
|
2a02b54786 | ||
|
ed88f55a3d | ||
|
818a254126 | ||
|
99b78f78d7 | ||
|
7d9ef6e0bf | ||
|
59a8cf0ae5 | ||
|
e7e57f8e6d | ||
|
da5644e758 | ||
|
0f6cf13d45 | ||
|
fe46f0e238 | ||
|
e0605156de | ||
|
e42b0cba26 | ||
|
1b7c46f496 | ||
|
a224491179 | ||
|
2d603f1f47 | ||
|
77e5a2f4a2 | ||
|
d3485e42b9 | ||
|
710514b8f1 | ||
|
2997c027a2 | ||
|
974d76c5f6 | ||
|
799e2d1265 | ||
|
987c7ca04b | ||
|
2ebc6d6a3c | ||
|
62838571eb | ||
|
f6fa986b33 | ||
|
652f4f0141 | ||
|
8b68210db7 | ||
|
87c4b4a5d4 | ||
|
cae9ccfacf | ||
|
4ddb14c136 | ||
|
dc2f0dad81 | ||
|
3540424aa1 | ||
|
46d4e12b4c | ||
|
0fff1bd8c7 | ||
|
a01c7e2e75 | ||
|
f03f6ce7ca | ||
|
ce58805104 |
325 changed files with 17526 additions and 6127 deletions
20
.github/script/amd64-20.04.Dockerfile
vendored
20
.github/script/amd64-20.04.Dockerfile
vendored
|
@ -1,20 +0,0 @@
|
|||
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 libsecp256k1-dev libsodium-dev pkg-config
|
||||
|
||||
WORKDIR /
|
||||
|
||||
ARG BRANCH
|
||||
ARG REPO
|
||||
RUN git clone --recurse-submodules https://github.com/$REPO ton && cd ton && git checkout $BRANCH && git submodule update
|
||||
|
||||
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 tolk validator-engine validator-engine-console create-state generate-random-id create-hardfork dht-server lite-client
|
20
.github/script/amd64-22.04.Dockerfile
vendored
20
.github/script/amd64-22.04.Dockerfile
vendored
|
@ -1,20 +0,0 @@
|
|||
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 libsecp256k1-dev libsodium-dev pkg-config
|
||||
|
||||
WORKDIR /
|
||||
|
||||
ARG BRANCH
|
||||
ARG REPO
|
||||
RUN git clone --recurse-submodules https://github.com/$REPO ton && cd ton && git checkout $BRANCH && git submodule update
|
||||
|
||||
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 tolk validator-engine validator-engine-console create-state generate-random-id create-hardfork dht-server lite-client
|
20
.github/script/arm64-20.04.Dockerfile
vendored
20
.github/script/arm64-20.04.Dockerfile
vendored
|
@ -1,20 +0,0 @@
|
|||
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 libsecp256k1-dev libsodium-dev pkg-config
|
||||
|
||||
WORKDIR /
|
||||
|
||||
ARG BRANCH
|
||||
ARG REPO
|
||||
RUN git clone --recurse-submodules https://github.com/$REPO ton && cd ton && git checkout $BRANCH && git submodule update
|
||||
|
||||
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 tolk validator-engine validator-engine-console create-state generate-random-id dht-server lite-client
|
20
.github/script/arm64-22.04.Dockerfile
vendored
20
.github/script/arm64-22.04.Dockerfile
vendored
|
@ -1,20 +0,0 @@
|
|||
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 libsecp256k1-dev libsodium-dev pkg-config
|
||||
|
||||
WORKDIR /
|
||||
|
||||
ARG BRANCH
|
||||
ARG REPO
|
||||
RUN git clone --recurse-submodules https://github.com/$REPO ton && cd ton && git checkout $BRANCH && git submodule update
|
||||
|
||||
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 tolk validator-engine validator-engine-console create-state generate-random-id dht-server lite-client
|
57
.github/workflows/build-ton-linux-arm64-appimage.yml
vendored
Normal file
57
.github/workflows/build-ton-linux-arm64-appimage.yml
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
name: Ubuntu TON build (AppImages, arm64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04-arm
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install system libraries
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential git cmake ninja-build zlib1g-dev libsecp256k1-dev libmicrohttpd-dev libsodium-dev liblz4-dev
|
||||
sudo apt remove libgsl-dev
|
||||
|
||||
- name: Install clang-16
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 16 all
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/native/build-ubuntu-appimages.sh .
|
||||
chmod +x build-ubuntu-appimages.sh
|
||||
./build-ubuntu-appimages.sh -a
|
||||
|
||||
- name: Make AppImages
|
||||
run: |
|
||||
cp assembly/appimage/create-appimages.sh .
|
||||
cp assembly/appimage/AppRun .
|
||||
cp assembly/appimage/ton.png .
|
||||
chmod +x create-appimages.sh
|
||||
./create-appimages.sh aarch64
|
||||
rm -rf artifacts
|
||||
|
||||
|
||||
- name: Build TON libs
|
||||
run: |
|
||||
cp assembly/native/build-ubuntu-portable-libs.sh .
|
||||
chmod +x build-ubuntu-portable-libs.sh
|
||||
./build-ubuntu-portable-libs.sh -a
|
||||
cp ./artifacts/libtonlibjson.so appimages/artifacts/
|
||||
cp ./artifacts/libemulator.so appimages/artifacts/
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-arm64-linux
|
||||
path: appimages/artifacts
|
43
.github/workflows/build-ton-linux-arm64-shared.yml
vendored
Normal file
43
.github/workflows/build-ton-linux-arm64-shared.yml
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
name: Ubuntu TON build (shared, arm64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04-arm, ubuntu-24.04-arm]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install system libraries
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential git cmake ninja-build zlib1g-dev libsecp256k1-dev libmicrohttpd-dev libsodium-dev liblz4-dev libjemalloc-dev
|
||||
|
||||
- if: matrix.os != 'ubuntu-24.04-arm'
|
||||
name: Install llvm-16
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 16 all
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/native/build-ubuntu-shared.sh .
|
||||
chmod +x build-ubuntu-shared.sh
|
||||
./build-ubuntu-shared.sh -t -a
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-binaries-${{ matrix.os }}
|
||||
path: artifacts
|
63
.github/workflows/build-ton-linux-x86-64-appimage.yml
vendored
Normal file
63
.github/workflows/build-ton-linux-x86-64-appimage.yml
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
name: Ubuntu TON build (AppImages, x86-64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install system libraries
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential git cmake ninja-build zlib1g-dev libsecp256k1-dev libmicrohttpd-dev libsodium-dev liblz4-dev
|
||||
sudo apt remove libgsl-dev
|
||||
|
||||
- name: Install gcc-11 g++-11
|
||||
run: |
|
||||
sudo apt install -y manpages-dev software-properties-common
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt update && sudo apt install gcc-11 g++-11
|
||||
|
||||
- name: Install clang-16
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 16 all
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/native/build-ubuntu-appimages.sh .
|
||||
chmod +x build-ubuntu-appimages.sh
|
||||
./build-ubuntu-appimages.sh -a
|
||||
|
||||
- name: Make AppImages
|
||||
run: |
|
||||
cp assembly/appimage/create-appimages.sh .
|
||||
cp assembly/appimage/AppRun .
|
||||
cp assembly/appimage/ton.png .
|
||||
chmod +x create-appimages.sh
|
||||
./create-appimages.sh x86_64
|
||||
rm -rf artifacts
|
||||
|
||||
|
||||
- name: Build TON libs
|
||||
run: |
|
||||
cp assembly/native/build-ubuntu-portable-libs.sh .
|
||||
chmod +x build-ubuntu-portable-libs.sh
|
||||
./build-ubuntu-portable-libs.sh -a
|
||||
cp ./artifacts/libtonlibjson.so appimages/artifacts/
|
||||
cp ./artifacts/libemulator.so appimages/artifacts/
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-x86_64-linux
|
||||
path: appimages/artifacts
|
27
.github/workflows/build-ton-macos-13-x86-64-portable.yml
vendored
Normal file
27
.github/workflows/build-ton-macos-13-x86-64-portable.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: MacOS-13 TON build (portable, x86-64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/native/build-macos-portable.sh .
|
||||
chmod +x build-macos-portable.sh
|
||||
./build-macos-portable.sh -t -a
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-x86_64-macos
|
||||
path: artifacts
|
27
.github/workflows/build-ton-macos-14-arm64-portable.yml
vendored
Normal file
27
.github/workflows/build-ton-macos-14-arm64-portable.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: MacOS-14 TON build (portable, arm64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/native/build-macos-portable.sh .
|
||||
chmod +x build-macos-portable.sh
|
||||
./build-macos-portable.sh -t -a
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-arm64-macos
|
||||
path: artifacts
|
21
.github/workflows/build-ton-wasm-emscripten.yml
vendored
21
.github/workflows/build-ton-wasm-emscripten.yml
vendored
|
@ -25,8 +25,27 @@ jobs:
|
|||
chmod +x fift-func-wasm-build-ubuntu.sh
|
||||
./fift-func-wasm-build-ubuntu.sh -a
|
||||
|
||||
- name: Prepare test
|
||||
run: |
|
||||
cp assembly/wasm/*.fc .
|
||||
git clone https://github.com/ton-community/func-js.git
|
||||
cd func-js
|
||||
npm install
|
||||
npm run build
|
||||
npm link
|
||||
|
||||
- name: Test TON WASM artifacts
|
||||
run: |
|
||||
base64 -w 0 artifacts/funcfiftlib.wasm > artifacts/funcfiftlib.wasm.js
|
||||
printf "module.exports = { FuncFiftLibWasm: '" | cat - artifacts/funcfiftlib.wasm.js > temp.txt && mv temp.txt artifacts/funcfiftlib.wasm.js
|
||||
echo "'}" >> artifacts/funcfiftlib.wasm.js
|
||||
cp artifacts/funcfiftlib.wasm.js func-js/node_modules/@ton-community/func-js-bin/dist/funcfiftlib.wasm.js
|
||||
cp artifacts/funcfiftlib.js func-js/node_modules/@ton-community/func-js-bin/dist/funcfiftlib.js
|
||||
npx func-js stdlib.fc intrinsics.fc --fift ./output.f
|
||||
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-wasm-binaries
|
||||
name: ton-wasm
|
||||
path: artifacts
|
||||
|
|
267
.github/workflows/create-release.yml
vendored
267
.github/workflows/create-release.yml
vendored
|
@ -4,6 +4,9 @@ on: [workflow_dispatch]
|
|||
|
||||
permissions: write-all
|
||||
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
runs-on: ubuntu-22.04
|
||||
|
@ -11,52 +14,76 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Download Linux arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-linux-arm64-appimage.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download and unzip Linux arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-linux-arm64-appimage.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download Linux x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-x86-64-linux.yml
|
||||
workflow: build-ton-linux-x86-64-appimage.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download and unzip Linux x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-x86-64-linux.yml
|
||||
workflow: build-ton-linux-x86-64-appimage.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download Mac x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-x86-64-macos.yml
|
||||
workflow: build-ton-macos-13-x86-64-portable.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download Mac arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-arm64-macos.yml
|
||||
workflow: build-ton-macos-14-arm64-portable.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download and unzip Mac x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-x86-64-macos.yml
|
||||
workflow: build-ton-macos-13-x86-64-portable.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download and unzip arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-arm64-macos.yml
|
||||
workflow: build-ton-macos-14-arm64-portable.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download Windows artifacts
|
||||
|
@ -65,6 +92,7 @@ jobs:
|
|||
workflow: ton-x86-64-windows.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download and unzip Windows artifacts
|
||||
|
@ -73,6 +101,7 @@ jobs:
|
|||
workflow: ton-x86-64-windows.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download WASM artifacts
|
||||
|
@ -81,6 +110,7 @@ jobs:
|
|||
workflow: build-ton-wasm-emscripten.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download Android Tonlib artifacts
|
||||
|
@ -89,6 +119,7 @@ jobs:
|
|||
workflow: build-ton-linux-android-tonlib.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Show all artifacts
|
||||
|
@ -147,7 +178,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries.zip
|
||||
file: artifacts/ton-x86-64-windows.zip
|
||||
asset_name: ton-win-x86-64.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -155,7 +186,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/fift.exe
|
||||
file: artifacts/ton-x86-64-windows/fift.exe
|
||||
asset_name: fift.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -163,7 +194,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/func.exe
|
||||
file: artifacts/ton-x86-64-windows/func.exe
|
||||
asset_name: func.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -171,7 +202,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/tolk.exe
|
||||
file: artifacts/ton-x86-64-windows/tolk.exe
|
||||
asset_name: tolk.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -179,7 +210,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/lite-client.exe
|
||||
file: artifacts/ton-x86-64-windows/lite-client.exe
|
||||
asset_name: lite-client.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -187,7 +218,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/proxy-liteserver.exe
|
||||
file: artifacts/ton-x86-64-windows/proxy-liteserver.exe
|
||||
asset_name: proxy-liteserver.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -195,7 +226,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/rldp-http-proxy.exe
|
||||
file: artifacts/ton-x86-64-windows/rldp-http-proxy.exe
|
||||
asset_name: rldp-http-proxy.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -203,7 +234,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/http-proxy.exe
|
||||
file: artifacts/ton-x86-64-windows/http-proxy.exe
|
||||
asset_name: http-proxy.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -211,7 +242,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/storage-daemon-cli.exe
|
||||
file: artifacts/ton-x86-64-windows/storage-daemon-cli.exe
|
||||
asset_name: storage-daemon-cli.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -219,7 +250,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/storage-daemon.exe
|
||||
file: artifacts/ton-x86-64-windows/storage-daemon.exe
|
||||
asset_name: storage-daemon.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -227,7 +258,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/tonlibjson.dll
|
||||
file: artifacts/ton-x86-64-windows/tonlibjson.dll
|
||||
asset_name: tonlibjson.dll
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -235,7 +266,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/emulator.dll
|
||||
file: artifacts/ton-x86-64-windows/emulator.dll
|
||||
asset_name: libemulator.dll
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -243,7 +274,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-win-binaries/tonlib-cli.exe
|
||||
file: artifacts/ton-x86-64-windows/tonlib-cli.exe
|
||||
asset_name: tonlib-cli.exe
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -253,7 +284,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries.zip
|
||||
file: artifacts/ton-x86_64-macos.zip
|
||||
asset_name: ton-mac-x86-64.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -261,7 +292,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/fift
|
||||
file: artifacts/ton-x86_64-macos/fift
|
||||
asset_name: fift-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -269,7 +300,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/func
|
||||
file: artifacts/ton-x86_64-macos/func
|
||||
asset_name: func-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -277,7 +308,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/tolk
|
||||
file: artifacts/ton-x86_64-macos/tolk
|
||||
asset_name: tolk-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -285,7 +316,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/lite-client
|
||||
file: artifacts/ton-x86_64-macos/lite-client
|
||||
asset_name: lite-client-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -293,7 +324,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/proxy-liteserver
|
||||
file: artifacts/ton-x86_64-macos/proxy-liteserver
|
||||
asset_name: proxy-liteserver-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -301,7 +332,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/rldp-http-proxy
|
||||
file: artifacts/ton-x86_64-macos/rldp-http-proxy
|
||||
asset_name: rldp-http-proxy-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -309,7 +340,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/http-proxy
|
||||
file: artifacts/ton-x86_64-macos/http-proxy
|
||||
asset_name: http-proxy-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -317,7 +348,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/storage-daemon-cli
|
||||
file: artifacts/ton-x86_64-macos/storage-daemon-cli
|
||||
asset_name: storage-daemon-cli-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -325,7 +356,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/storage-daemon
|
||||
file: artifacts/ton-x86_64-macos/storage-daemon
|
||||
asset_name: storage-daemon-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -333,7 +364,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/libtonlibjson.dylib
|
||||
file: artifacts/ton-x86_64-macos/libtonlibjson.dylib
|
||||
asset_name: tonlibjson-mac-x86-64.dylib
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -341,7 +372,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/libemulator.dylib
|
||||
file: artifacts/ton-x86_64-macos/libemulator.dylib
|
||||
asset_name: libemulator-mac-x86-64.dylib
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -349,7 +380,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos-binaries/tonlib-cli
|
||||
file: artifacts/ton-x86_64-macos/tonlib-cli
|
||||
asset_name: tonlib-cli-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -360,7 +391,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries.zip
|
||||
file: artifacts/ton-arm64-macos.zip
|
||||
asset_name: ton-mac-arm64.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -368,7 +399,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/fift
|
||||
file: artifacts/ton-arm64-macos/fift
|
||||
asset_name: fift-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -376,7 +407,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/func
|
||||
file: artifacts/ton-arm64-macos/func
|
||||
asset_name: func-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -384,7 +415,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/tolk
|
||||
file: artifacts/ton-arm64-macos/tolk
|
||||
asset_name: tolk-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -392,7 +423,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/lite-client
|
||||
file: artifacts/ton-arm64-macos/lite-client
|
||||
asset_name: lite-client-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -400,7 +431,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/proxy-liteserver
|
||||
file: artifacts/ton-arm64-macos/proxy-liteserver
|
||||
asset_name: proxy-liteserver-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -408,7 +439,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/rldp-http-proxy
|
||||
file: artifacts/ton-arm64-macos/rldp-http-proxy
|
||||
asset_name: rldp-http-proxy-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -416,7 +447,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/http-proxy
|
||||
file: artifacts/ton-arm64-macos/http-proxy
|
||||
asset_name: http-proxy-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -424,7 +455,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/storage-daemon-cli
|
||||
file: artifacts/ton-arm64-macos/storage-daemon-cli
|
||||
asset_name: storage-daemon-cli-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -432,7 +463,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/storage-daemon
|
||||
file: artifacts/ton-arm64-macos/storage-daemon
|
||||
asset_name: storage-daemon-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -440,7 +471,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/libtonlibjson.dylib
|
||||
file: artifacts/ton-arm64-macos/libtonlibjson.dylib
|
||||
asset_name: tonlibjson-mac-arm64.dylib
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -448,7 +479,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/libemulator.dylib
|
||||
file: artifacts/ton-arm64-macos/libemulator.dylib
|
||||
asset_name: libemulator-mac-arm64.dylib
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -456,7 +487,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/tonlib-cli
|
||||
file: artifacts/ton-arm64-macos/tonlib-cli
|
||||
asset_name: tonlib-cli-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -466,15 +497,23 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries.zip
|
||||
file: artifacts/ton-x86_64-linux.zip
|
||||
asset_name: ton-linux-x86_64.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload generic smartcont+lib artifact
|
||||
run: |
|
||||
mkdir smartcont_lib
|
||||
cd smartcont_lib
|
||||
cp -r ../artifacts/ton-x86_64-linux/{smartcont,lib} .
|
||||
zip -r smartcont_lib.zip .
|
||||
gh release upload ${{ steps.tag.outputs.TAG }} smartcont_lib.zip
|
||||
|
||||
- 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
|
||||
file: artifacts/ton-x86_64-linux/fift
|
||||
asset_name: fift-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -482,7 +521,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/func
|
||||
file: artifacts/ton-x86_64-linux/func
|
||||
asset_name: func-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -490,7 +529,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/tolk
|
||||
file: artifacts/ton-x86_64-linux/tolk
|
||||
asset_name: tolk-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -498,7 +537,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/lite-client
|
||||
file: artifacts/ton-x86_64-linux/lite-client
|
||||
asset_name: lite-client-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -506,7 +545,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/proxy-liteserver
|
||||
file: artifacts/ton-x86_64-linux/proxy-liteserver
|
||||
asset_name: proxy-liteserver-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -514,7 +553,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/rldp-http-proxy
|
||||
file: artifacts/ton-x86_64-linux/rldp-http-proxy
|
||||
asset_name: rldp-http-proxy-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -522,7 +561,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/http-proxy
|
||||
file: artifacts/ton-x86_64-linux/http-proxy
|
||||
asset_name: http-proxy-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -530,7 +569,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/storage-daemon-cli
|
||||
file: artifacts/ton-x86_64-linux/storage-daemon-cli
|
||||
asset_name: storage-daemon-cli-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -538,7 +577,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/storage-daemon
|
||||
file: artifacts/ton-x86_64-linux/storage-daemon
|
||||
asset_name: storage-daemon-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -546,7 +585,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/libtonlibjson.so
|
||||
file: artifacts/ton-x86_64-linux/libtonlibjson.so
|
||||
asset_name: tonlibjson-linux-x86_64.so
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -554,7 +593,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/libemulator.so
|
||||
file: artifacts/ton-x86_64-linux/libemulator.so
|
||||
asset_name: libemulator-linux-x86_64.so
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
@ -562,16 +601,124 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux-binaries/tonlib-cli
|
||||
file: artifacts/ton-x86_64-linux/tonlib-cli
|
||||
asset_name: tonlib-cli-linux-x86_64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
||||
# linux arm64
|
||||
|
||||
- name: Upload Linux arm64 artifacts
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux.zip
|
||||
asset_name: ton-linux-arm64.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - fift
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/fift
|
||||
asset_name: fift-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - func
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/func
|
||||
asset_name: func-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - tolk
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/tolk
|
||||
asset_name: tolk-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - lite-client
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/lite-client
|
||||
asset_name: lite-client-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - proxy-liteserver
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/proxy-liteserver
|
||||
asset_name: proxy-liteserver-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - rldp-http-proxy
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/rldp-http-proxy
|
||||
asset_name: rldp-http-proxy-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - http-proxy
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/http-proxy
|
||||
asset_name: http-proxy-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - storage-daemon-cli
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/storage-daemon-cli
|
||||
asset_name: storage-daemon-cli-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - storage-daemon
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/storage-daemon
|
||||
asset_name: storage-daemon-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - tonlibjson
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/libtonlibjson.so
|
||||
asset_name: tonlibjson-linux-arm64.so
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - libemulator
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/libemulator.so
|
||||
asset_name: libemulator-linux-arm64.so
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Linux arm64 single artifact - tonlib-cli
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/tonlib-cli
|
||||
asset_name: tonlib-cli-linux-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
||||
- 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
|
||||
file: artifacts/ton-wasm.zip
|
||||
asset_name: ton-wasm.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Android Tonlib artifacts
|
||||
|
|
154
.github/workflows/create-tolk-release.yml
vendored
Normal file
154
.github/workflows/create-tolk-release.yml
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
name: Create tolk release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'tolk release and tag name'
|
||||
required: true
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Download and unzip Linux arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-linux-arm64-appimage.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download and unzip Linux x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-linux-x86-64-appimage.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download and unzip Mac x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-macos-13-x86-64-portable.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download and unzip arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-macos-14-arm64-portable.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download and unzip Windows artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: ton-x86-64-windows.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download WASM artifacts
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: build-ton-wasm-emscripten.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
branch: master
|
||||
skip_unpack: true
|
||||
|
||||
- name: Show all artifacts
|
||||
run: |
|
||||
tree artifacts
|
||||
|
||||
|
||||
# create release
|
||||
- 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/ton-blockchain/ton/actions/runners/registration-token
|
||||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ inputs.tag }}
|
||||
release_name: ${{ inputs.tag }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
# upload
|
||||
|
||||
# win
|
||||
|
||||
- name: Upload Windows 2019 single artifact - tolk
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86-64-windows/tolk.exe
|
||||
asset_name: tolk.exe
|
||||
tag: ${{ inputs.tag }}
|
||||
|
||||
# mac x86-64
|
||||
|
||||
- name: Upload Mac x86-64 single artifact - tolk
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-macos/tolk
|
||||
asset_name: tolk-mac-x86-64
|
||||
tag: ${{ inputs.tag }}
|
||||
|
||||
# mac arm64
|
||||
|
||||
- name: Upload Mac arm64 single artifact - tolk
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos/tolk
|
||||
asset_name: tolk-mac-arm64
|
||||
tag: ${{ inputs.tag }}
|
||||
|
||||
# linux x86-64
|
||||
|
||||
- name: Upload Linux x86-64 single artifact - tolk
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-x86_64-linux/tolk
|
||||
asset_name: tolk-linux-x86_64
|
||||
tag: ${{ inputs.tag }}
|
||||
|
||||
# linux arm64
|
||||
|
||||
- name: Upload Linux arm64 single artifact - tolk
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-linux/tolk
|
||||
asset_name: tolk-linux-arm64
|
||||
tag: ${{ inputs.tag }}
|
||||
|
||||
- name: Upload WASM artifacts
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-wasm.zip
|
||||
asset_name: ton-wasm.zip
|
||||
tag: ${{ inputs.tag }}
|
||||
|
17
.github/workflows/docker-ubuntu-branch-image.yml
vendored
17
.github/workflows/docker-ubuntu-branch-image.yml
vendored
|
@ -20,10 +20,12 @@ jobs:
|
|||
submodules: 'recursive'
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v3.5.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v3.10.0
|
||||
with:
|
||||
driver-opts: image=moby/buildkit:v0.11.0
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
|
@ -32,6 +34,17 @@ jobs:
|
|||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and export to Docker
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
load: true
|
||||
context: ./
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
docker run --rm -e "TEST=1" ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test
|
||||
|
||||
- name: Get tag as branch name
|
||||
id: tag
|
||||
run: |
|
||||
|
|
6
.github/workflows/docker-ubuntu-image.yml
vendored
6
.github/workflows/docker-ubuntu-image.yml
vendored
|
@ -20,10 +20,10 @@ jobs:
|
|||
submodules: 'recursive'
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
uses: docker/setup-qemu-action@v3.5.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v3.10.0
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
|
|
40
.github/workflows/ton-arm64-macos.yml
vendored
40
.github/workflows/ton-arm64-macos.yml
vendored
|
@ -1,40 +0,0 @@
|
|||
name: MacOS TON build (portable, arm64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: cachix/install-nix-action@v23
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh -t
|
||||
|
||||
- name: Simple binaries test
|
||||
run: |
|
||||
sudo mv /nix/store /nix/store2
|
||||
artifacts/validator-engine -V
|
||||
artifacts/lite-client -V
|
||||
artifacts/fift -V
|
||||
artifacts/func -V
|
||||
artifacts/tolk -v
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-arm64-macos-binaries
|
||||
path: artifacts
|
44
.github/workflows/ton-x86-64-linux.yml
vendored
44
.github/workflows/ton-x86-64-linux.yml
vendored
|
@ -1,44 +0,0 @@
|
|||
name: Ubuntu TON build (portable, x86-64)
|
||||
|
||||
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@v23
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/nix/build-linux-x86-64-nix.sh .
|
||||
chmod +x build-linux-x86-64-nix.sh
|
||||
./build-linux-x86-64-nix.sh -t
|
||||
|
||||
- name: Simple binaries test
|
||||
run: |
|
||||
sudo mv /nix/store /nix/store2
|
||||
artifacts/validator-engine -V
|
||||
artifacts/lite-client -V
|
||||
artifacts/fift -V
|
||||
artifacts/func -V
|
||||
artifacts/tolk -v
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-x86_64-linux-binaries
|
||||
path: artifacts
|
40
.github/workflows/ton-x86-64-macos.yml
vendored
40
.github/workflows/ton-x86-64-macos.yml
vendored
|
@ -1,40 +0,0 @@
|
|||
name: MacOS TON build (portable, x86-64)
|
||||
|
||||
on: [push,workflow_dispatch,workflow_call]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: cachix/install-nix-action@v23
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build TON
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh -t
|
||||
|
||||
- name: Simple binaries test
|
||||
run: |
|
||||
sudo mv /nix/store /nix/store2
|
||||
artifacts/validator-engine -V
|
||||
artifacts/lite-client -V
|
||||
artifacts/fift -V
|
||||
artifacts/func -V
|
||||
artifacts/tolk -v
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-x86_64-macos-binaries
|
||||
path: artifacts
|
2
.github/workflows/ton-x86-64-windows.yml
vendored
2
.github/workflows/ton-x86-64-windows.yml
vendored
|
@ -32,5 +32,5 @@ jobs:
|
|||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-win-binaries
|
||||
name: ton-x86-64-windows
|
||||
path: artifacts
|
||||
|
|
|
@ -84,6 +84,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
|||
set(CMAKE_CXX_EXTENSIONS FALSE)
|
||||
|
||||
#BEGIN internal
|
||||
option(BUILD_SHARED_LIBS "Use \"ON\" to build shared libraries instead of static where it's not specified (not recommended)" OFF)
|
||||
option(USE_EMSCRIPTEN "Use \"ON\" for config building wasm." OFF)
|
||||
option(TON_ONLY_TONLIB "Use \"ON\" to build only tonlib." OFF)
|
||||
if (USE_EMSCRIPTEN)
|
||||
|
|
35
Changelog.md
35
Changelog.md
|
@ -1,3 +1,30 @@
|
|||
## 2025.03 Update
|
||||
1. New extracurrency behavior introduced, check [GlobalVersions.md](./doc/GlobalVersions.md#version-10)
|
||||
2. Optmization of validation process, in particular CellStorageStat.
|
||||
3. Flag for speeding up broadcasts in various overlays.
|
||||
4. Fixes for static builds for emulator and tonlibjson
|
||||
5. Improving getstats output: adds
|
||||
* Liteserver queries count
|
||||
* Collated/validated blocks count, number of active sessions
|
||||
* Persistent state sizes
|
||||
* Initial sync progress
|
||||
6. Fixes in logging, TON Storage, external message checking, persistent state downloading, UB in tonlib
|
||||
|
||||
Besides the work of the core team, this update is based on the efforts of @Sild from StonFi(UB in tonlib).
|
||||
|
||||
## 2025.02 Update
|
||||
1. Series of improvement/fixes for `Config8.version >= 9`, check [GlobalVersions.md](./doc/GlobalVersions.md)
|
||||
2. Fix for better discovery of updated nodes' (validators') IPs: retry dht queries
|
||||
3. Series of improvements for extra currency adoption: fixed c7 in rungetmethod, reserve modes
|
||||
4. TVM: Fix processing continuation control data on deep jump
|
||||
5. A few fixes of tl-b schemes: crc computation, incorrect tag for merkle proofs, advance_ext, NatWidth print
|
||||
6. Emulator improvements: fix setting libraries, extracurrency support
|
||||
7. Increase of gas limit for unlocking highload-v2 wallets locked in the beginning of 2024
|
||||
8. Validator console improvement: dashed names, better shard formats
|
||||
|
||||
|
||||
Besides the work of the core team, this update is based on the efforts of @dbaranovstonfi from StonFi(libraries in emulator), @Rexagon (ret on deep jumps), @tvorogme from DTon (`advance_ext`), Nan from Zellic (`stk_und` and JNI)
|
||||
|
||||
## 2024.12 Update
|
||||
|
||||
1. FunC 0.4.6: Fix in try/catch handling, fixing pure flag for functions stored in variables
|
||||
|
@ -31,7 +58,7 @@ Besides the work of the core team, this update is based on the efforts of @krigg
|
|||
## 2024.08 Update
|
||||
|
||||
1. Introduction of dispatch queues, message envelopes with transaction chain metadata, and explicitly stored msg_queue size, which will be activated by `Config8.version >= 8` and new `Config8.capabilities` bits: `capStoreOutMsgQueueSize`, `capMsgMetadata`, `capDeferMessages`.
|
||||
2. A number of changes to transcation executor which will activated for `Config8.version >= 8`:
|
||||
2. A number of changes to transaction executor which will activated for `Config8.version >= 8`:
|
||||
- Check mode on invalid `action_send_msg`. Ignore action if `IGNORE_ERROR` (+2) bit is set, bounce if `BOUNCE_ON_FAIL` (+16) bit is set.
|
||||
- Slightly change random seed generation to fix mix of `addr_rewrite` and `addr`.
|
||||
- Fill in `skipped_actions` for both invalid and valid messages with `IGNORE_ERROR` mode that can't be sent.
|
||||
|
@ -103,7 +130,7 @@ Besides the work of the core team, this update is based on the efforts of @akifo
|
|||
* Fix error in proof generation for blocks after merge
|
||||
* Fix most of `block is not applied` issues related to sending too recent block in Proofs
|
||||
* LS now check external messages till `accept_message` (`set_gas`).
|
||||
3. Improvements in DHT work and storage, CellDb, config.json ammendment, peer misbehavior detection, validator session stats collection, emulator.
|
||||
3. Improvements in DHT work and storage, CellDb, config.json amendment, peer misbehavior detection, validator session stats collection, emulator.
|
||||
4. Change in CTOS and XLOAD behavior activated through setting `version >= 5` in `ConfigParam 8;`:
|
||||
* Loading "nested libraries" (i.e. a library cell that points to another library cell) throws an exception.
|
||||
* Loading a library consumes gas for cell load only once (for the library cell), not twice (both for the library cell and the cell in the library).
|
||||
|
@ -114,7 +141,7 @@ Besides the work of the Core team, this update is based on the efforts of @XaBbl
|
|||
## 2023.12 Update
|
||||
|
||||
1. Optimized message queue handling, now queue cleaning speed doesn't depend on total queue size
|
||||
* Cleaning delivered messages using lt augmentation instead of random search / consequtive walk
|
||||
* Cleaning delivered messages using lt augmentation instead of random search / consecutive walk
|
||||
* Keeping root cell of queue message in memory until outdated (caching)
|
||||
2. Changes to block collation/validation limits
|
||||
3. Stop accepting new external message if message queue is overloaded
|
||||
|
@ -206,7 +233,7 @@ Besides the work of the core team, this update is based on the efforts of @vtama
|
|||
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.
|
||||
|
||||
## 2022.08 Update
|
||||
* Blockchain state serialization now works via separate db-handler which simplfies memory clearing after serialization
|
||||
* Blockchain state serialization now works via separate db-handler which simplifies 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
|
||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -1,6 +1,13 @@
|
|||
FROM ubuntu:22.04 AS builder
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git ninja-build libsodium-dev libmicrohttpd-dev liblz4-dev pkg-config autoconf automake libtool libjemalloc-dev lsb-release software-properties-common gnupg
|
||||
rm /var/lib/dpkg/info/libc-bin.* && \
|
||||
apt-get clean && \
|
||||
apt-get update && \
|
||||
apt install libc-bin && \
|
||||
apt-get install -y build-essential cmake clang openssl libssl-dev zlib1g-dev gperf wget git \
|
||||
ninja-build libsodium-dev libmicrohttpd-dev liblz4-dev pkg-config autoconf automake libtool \
|
||||
libjemalloc-dev lsb-release software-properties-common gnupg
|
||||
|
||||
RUN wget https://apt.llvm.org/llvm.sh && \
|
||||
chmod +x llvm.sh && \
|
||||
|
@ -25,6 +32,7 @@ RUN mkdir build && \
|
|||
blockchain-explorer emulator tonlibjson http-proxy adnl-proxy
|
||||
|
||||
FROM ubuntu:22.04
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y wget curl libatomic1 openssl libsodium-dev libmicrohttpd-dev liblz4-dev libjemalloc-dev htop \
|
||||
net-tools netcat iptraf-ng jq tcpdump pv plzip && \
|
||||
|
|
22
README.md
22
README.md
|
@ -47,9 +47,9 @@ Main TON monorepo, which includes the code of the node/validator, lite-client, t
|
|||
__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](https://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 develop decentralised apps check [Tutorials](https://docs.ton.org/v3/guidelines/smart-contracts/guidelines), [FunC docs](https://ton.org/docs/develop/func/overview) and [DApp tutorials](https://docs.ton.org/v3/guidelines/dapps/overview)
|
||||
- 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/)
|
||||
- To interact with TON check [APIs](https://docs.ton.org/v3/guidelines/dapps/apis-sdks/overview)
|
||||
|
||||
## Updates flow
|
||||
|
||||
|
@ -71,7 +71,7 @@ Usually, the response to your pull request will indicate which section it falls
|
|||
|
||||
## Build TON blockchain
|
||||
|
||||
### Ubuntu 20.4, 22.04 (x86-64, aarch64)
|
||||
### Ubuntu 20.4, 22.04, 24.04 (x86-64, aarch64)
|
||||
Install additional system libraries
|
||||
```bash
|
||||
sudo apt-get update
|
||||
|
@ -141,18 +141,10 @@ Compile TON tonlib library
|
|||
./build-android-tonlib.sh
|
||||
```
|
||||
|
||||
### Build TON portable binaries with Nix package manager
|
||||
You need to install Nix first.
|
||||
```bash
|
||||
sh <(curl -L https://nixos.org/nix/install) --daemon
|
||||
```
|
||||
Then compile TON with Nix by executing below command from the root folder:
|
||||
```bash
|
||||
cp -r assembly/nix/* .
|
||||
export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz
|
||||
nix-build linux-x86-64-static.nix
|
||||
```
|
||||
More examples for other platforms can be found under `assembly/nix`.
|
||||
### TON portable binaries
|
||||
|
||||
Linux portable binaries are wrapped into AppImages, at the same time MacOS portable binaries are statically linked executables.
|
||||
Linux and MacOS binaries are available for both x86-64 and arm64 architectures.
|
||||
|
||||
## Running tests
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ void AdnlPeerPairImpl::discover() {
|
|||
void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
|
||||
last_received_packet_ = td::Timestamp::now();
|
||||
try_reinit_at_ = td::Timestamp::never();
|
||||
drop_addr_list_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) {
|
||||
|
@ -415,6 +416,9 @@ void AdnlPeerPairImpl::send_packet_continue(AdnlPacket packet, td::actor::ActorI
|
|||
if (!try_reinit_at_ && last_received_packet_ < td::Timestamp::in(-5.0)) {
|
||||
try_reinit_at_ = td::Timestamp::in(10.0);
|
||||
}
|
||||
if (!drop_addr_list_at_ && last_received_packet_ < td::Timestamp::in(-60.0 * 9.0)) {
|
||||
drop_addr_list_at_ = td::Timestamp::in(60.0);
|
||||
}
|
||||
packet.run_basic_checks().ensure();
|
||||
auto B = serialize_tl_object(packet.tl(), true);
|
||||
if (via_channel) {
|
||||
|
@ -692,6 +696,16 @@ void AdnlPeerPairImpl::reinit(td::int32 date) {
|
|||
}
|
||||
|
||||
td::Result<std::pair<td::actor::ActorId<AdnlNetworkConnection>, bool>> AdnlPeerPairImpl::get_conn() {
|
||||
if (drop_addr_list_at_ && drop_addr_list_at_.is_in_past()) {
|
||||
drop_addr_list_at_ = td::Timestamp::never();
|
||||
priority_addr_list_ = AdnlAddressList{};
|
||||
priority_conns_.clear();
|
||||
addr_list_ = AdnlAddressList{};
|
||||
conns_.clear();
|
||||
has_reverse_addr_ = false;
|
||||
return td::Status::Error(ErrorCode::notready, "no active connections");
|
||||
}
|
||||
|
||||
if (!priority_addr_list_.empty() && priority_addr_list_.expire_at() < td::Clocks::system()) {
|
||||
priority_addr_list_ = AdnlAddressList{};
|
||||
priority_conns_.clear();
|
||||
|
|
|
@ -266,6 +266,7 @@ class AdnlPeerPairImpl : public AdnlPeerPair {
|
|||
|
||||
td::Timestamp last_received_packet_ = td::Timestamp::never();
|
||||
td::Timestamp try_reinit_at_ = td::Timestamp::never();
|
||||
td::Timestamp drop_addr_list_at_ = td::Timestamp::never();
|
||||
|
||||
bool has_reverse_addr_ = false;
|
||||
td::Timestamp request_reverse_ping_after_ = td::Timestamp::now();
|
||||
|
|
3
assembly/appimage/AppRun
Normal file
3
assembly/appimage/AppRun
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
export LD_LIBRARY_PATH="${APPDIR}/usr/lib:${LD_LIBRARY_PATH}"
|
||||
exec "$(dirname $0)"/usr/bin/app "$@"
|
50
assembly/appimage/create-appimages.sh
Normal file
50
assembly/appimage/create-appimages.sh
Normal file
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ ! -d "artifacts" ]; then
|
||||
echo "No artifacts found."
|
||||
exit 2
|
||||
fi
|
||||
# x86_64 or aarch64
|
||||
ARCH=$1
|
||||
|
||||
rm -rf appimages
|
||||
|
||||
mkdir -p appimages/artifacts
|
||||
|
||||
wget -nc https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$ARCH.AppImage
|
||||
chmod +x ./appimagetool-$ARCH.AppImage
|
||||
|
||||
cd appimages
|
||||
for file in ../artifacts/*; do
|
||||
if [[ -f "$file" && "$file" != *.so ]]; then
|
||||
appName=$(basename "$file")
|
||||
echo $appName
|
||||
# prepare AppDir
|
||||
mkdir -p $appName.AppDir/usr/{bin,lib}
|
||||
cp ../AppRun $appName.AppDir/AppRun
|
||||
sed -i "s/app/$appName/g" $appName.AppDir/AppRun
|
||||
chmod +x ./$appName.AppDir/AppRun
|
||||
printf '[Desktop Entry]\nName='$appName'\nExec='$appName'\nIcon='$appName'\nType=Application\nCategories=Utility;\n' > $appName.AppDir/$appName.desktop
|
||||
cp ../ton.png $appName.AppDir/$appName.png
|
||||
cp $file $appName.AppDir/usr/bin/
|
||||
cp ../build/openssl_3/libcrypto.so.3 \
|
||||
/lib/$ARCH-linux-gnu/libatomic.so.1 \
|
||||
/lib/$ARCH-linux-gnu/libsodium.so.23 \
|
||||
/lib/$ARCH-linux-gnu/libz.so.1 \
|
||||
/lib/$ARCH-linux-gnu/liblz4.so.1 \
|
||||
/lib/$ARCH-linux-gnu/libmicrohttpd.so.12 \
|
||||
/lib/$ARCH-linux-gnu/libreadline.so.8 \
|
||||
/lib/$ARCH-linux-gnu/libstdc++.so.6 \
|
||||
$appName.AppDir/usr/lib/
|
||||
|
||||
chmod +x ./$appName.AppDir/usr/bin/$appName
|
||||
# create AppImage
|
||||
./../appimagetool-$ARCH.AppImage -l $appName.AppDir
|
||||
mv $appName-$ARCH.AppImage artifacts/$appName
|
||||
fi
|
||||
done
|
||||
|
||||
ls -larth artifacts
|
||||
cp -r ../artifacts/{smartcont,lib} artifacts/
|
||||
pwd
|
||||
ls -larth artifacts
|
BIN
assembly/appimage/ton.png
Normal file
BIN
assembly/appimage/ton.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
|
@ -1,237 +0,0 @@
|
|||
pipeline {
|
||||
|
||||
agent none
|
||||
stages {
|
||||
stage('Run Builds') {
|
||||
parallel {
|
||||
stage('Ubuntu 20.04 x86-64 (shared)') {
|
||||
agent {
|
||||
label 'Ubuntu_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/native/build-ubuntu-shared.sh .
|
||||
chmod +x build-ubuntu-shared.sh
|
||||
./build-ubuntu-shared.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-x86_64-linux-shared ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-x86_64-linux-shared.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Ubuntu 20.04 x86-64 (portable)') {
|
||||
agent {
|
||||
label 'Ubuntu_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/nix/build-linux-x86-64-nix.sh .
|
||||
chmod +x build-linux-x86-64-nix.sh
|
||||
./build-linux-x86-64-nix.sh
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-x86-64-linux-portable ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-x86-64-linux-portable.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Ubuntu 20.04 aarch64 (shared)') {
|
||||
agent {
|
||||
label 'Ubuntu_arm64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/native/build-ubuntu-shared.sh .
|
||||
chmod +x build-ubuntu-shared.sh
|
||||
./build-ubuntu-shared.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-arm64-linux-shared ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-arm64-linux-shared.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Ubuntu 20.04 aarch64 (portable)') {
|
||||
agent {
|
||||
label 'Ubuntu_arm64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/nix/build-linux-arm64-nix.sh .
|
||||
chmod +x build-linux-arm64-nix.sh
|
||||
./build-linux-arm64-nix.sh
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-arm64-linux-portable ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-arm64-linux-portable.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('macOS 12.7 x86-64 (shared)') {
|
||||
agent {
|
||||
label 'macOS_12.7_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/native/build-macos-shared.sh .
|
||||
chmod +x build-macos-shared.sh
|
||||
./build-macos-shared.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-x86-64-macos-shared ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-x86-64-macos-shared.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('macOS 12.7 x86-64 (portable)') {
|
||||
agent {
|
||||
label 'macOS_12.7_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-x86-64-macos-portable ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-x86-64-macos-portable.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('macOS 12.6 aarch64 (shared)') {
|
||||
agent {
|
||||
label 'macOS_12.6-arm64-m1'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/native/build-macos-shared.sh .
|
||||
chmod +x build-macos-shared.sh
|
||||
./build-macos-shared.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-arm64-macos-m1-shared ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-arm64-macos-m1-shared.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('macOS 12.6 aarch64 (portable)') {
|
||||
agent {
|
||||
label 'macOS_12.6-arm64-m1'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-arm64-macos-portable ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-arm64-macos-portable.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('macOS 13.2 aarch64 (shared)') {
|
||||
agent {
|
||||
label 'macOS_13.2-arm64-m2'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/native/build-macos-shared.sh .
|
||||
chmod +x build-macos-shared.sh
|
||||
./build-macos-shared.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-arm64-macos-m2-shared ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-arm64-macos-m2-shared.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Windows Server 2022 x86-64') {
|
||||
agent {
|
||||
label 'Windows_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
bat '''
|
||||
copy assembly\\native\\build-windows.bat .
|
||||
build-windows.bat
|
||||
'''
|
||||
bat '''
|
||||
cd artifacts
|
||||
zip -9r ton-x86-64-windows ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-x86-64-windows.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Android Tonlib') {
|
||||
agent {
|
||||
label 'Ubuntu_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/android/build-android-tonlib.sh .
|
||||
chmod +x build-android-tonlib.sh
|
||||
./build-android-tonlib.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts/tonlib-android-jni
|
||||
zip -9r ton-android-tonlib ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/tonlib-android-jni/ton-android-tonlib.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('WASM fift func emulator') {
|
||||
agent {
|
||||
label 'Ubuntu_x86-64'
|
||||
}
|
||||
steps {
|
||||
timeout(time: 180, unit: 'MINUTES') {
|
||||
sh '''
|
||||
cp assembly/wasm/fift-func-wasm-build-ubuntu.sh .
|
||||
chmod +x fift-func-wasm-build-ubuntu.sh
|
||||
./fift-func-wasm-build-ubuntu.sh -a
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
zip -9r ton-wasm-binaries ./*
|
||||
'''
|
||||
archiveArtifacts artifacts: 'artifacts/ton-wasm-binaries.zip'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
109
assembly/native/build-ubuntu-appimages.sh
Normal file
109
assembly/native/build-ubuntu-appimages.sh
Normal file
|
@ -0,0 +1,109 @@
|
|||
#/bin/bash
|
||||
|
||||
with_tests=false
|
||||
with_artifacts=false
|
||||
|
||||
|
||||
while getopts 'ta' flag; do
|
||||
case "${flag}" in
|
||||
t) with_tests=true ;;
|
||||
a) with_artifacts=true ;;
|
||||
*) break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -d "build" ]; then
|
||||
mkdir build
|
||||
cd build
|
||||
else
|
||||
cd build
|
||||
rm -rf .ninja* CMakeCache.txt
|
||||
fi
|
||||
|
||||
export CC=$(which clang-16)
|
||||
export CXX=$(which clang++-16)
|
||||
export CCACHE_DISABLE=1
|
||||
|
||||
if [ ! -d "openssl_3" ]; then
|
||||
git clone https://github.com/openssl/openssl openssl_3
|
||||
cd openssl_3
|
||||
opensslPath=`pwd`
|
||||
git checkout openssl-3.1.4
|
||||
./config
|
||||
make build_libs -j12
|
||||
test $? -eq 0 || { echo "Can't compile openssl_3"; exit 1; }
|
||||
cd ..
|
||||
else
|
||||
opensslPath=$(pwd)/openssl_3
|
||||
echo "Using compiled openssl_3"
|
||||
fi
|
||||
|
||||
cmake -GNinja .. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DPORTABLE=1 \
|
||||
-DOPENSSL_ROOT_DIR=$opensslPath \
|
||||
-DOPENSSL_INCLUDE_DIR=$opensslPath/include \
|
||||
-DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.so
|
||||
|
||||
|
||||
test $? -eq 0 || { echo "Can't configure ton"; exit 1; }
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
ninja storage-daemon storage-daemon-cli fift func tolk tonlib tonlibjson tonlib-cli \
|
||||
validator-engine lite-client pow-miner validator-engine-console blockchain-explorer \
|
||||
generate-random-id json2tlo dht-server http-proxy rldp-http-proxy \
|
||||
adnl-proxy create-state emulator test-ed25519 test-ed25519-crypto test-bigint \
|
||||
test-vm test-fift test-cells test-smartcont test-net test-tdactor test-tdutils \
|
||||
test-tonlib-offline test-adnl test-dht test-rldp test-rldp2 test-catchain \
|
||||
test-fec test-tddb test-db test-validator-session-state test-emulator proxy-liteserver
|
||||
test $? -eq 0 || { echo "Can't compile ton"; exit 1; }
|
||||
else
|
||||
ninja storage-daemon storage-daemon-cli fift func tolk tonlib tonlibjson tonlib-cli \
|
||||
validator-engine lite-client pow-miner validator-engine-console blockchain-explorer \
|
||||
generate-random-id json2tlo dht-server http-proxy rldp-http-proxy \
|
||||
adnl-proxy create-state emulator proxy-liteserver
|
||||
test $? -eq 0 || { echo "Can't compile ton"; exit 1; }
|
||||
fi
|
||||
|
||||
# simple binaries' test
|
||||
./storage/storage-daemon/storage-daemon -V || exit 1
|
||||
./validator-engine/validator-engine -V || exit 1
|
||||
./lite-client/lite-client -V || exit 1
|
||||
./crypto/fift -V || exit 1
|
||||
|
||||
echo validator-engine
|
||||
ldd ./validator-engine/validator-engine || exit 1
|
||||
ldd ./validator-engine-console/validator-engine-console || exit 1
|
||||
ldd ./crypto/fift || exit 1
|
||||
echo blockchain-explorer
|
||||
ldd ./blockchain-explorer/blockchain-explorer || exit 1
|
||||
echo libtonlibjson.so
|
||||
ldd ./tonlib/libtonlibjson.so.0.5 || exit 1
|
||||
echo libemulator.so
|
||||
ldd ./emulator/libemulator.so || exit 1
|
||||
|
||||
cd ..
|
||||
|
||||
if [ "$with_artifacts" = true ]; then
|
||||
rm -rf artifacts
|
||||
mkdir artifacts
|
||||
mv build/tonlib/libtonlibjson.so.0.5 build/tonlib/libtonlibjson.so
|
||||
cp build/storage/storage-daemon/storage-daemon build/storage/storage-daemon/storage-daemon-cli \
|
||||
build/crypto/fift build/crypto/tlbc build/crypto/func build/tolk/tolk build/crypto/create-state build/blockchain-explorer/blockchain-explorer \
|
||||
build/validator-engine-console/validator-engine-console build/tonlib/tonlib-cli build/utils/proxy-liteserver \
|
||||
build/tonlib/libtonlibjson.so 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 build/emulator/libemulator.so \
|
||||
artifacts
|
||||
test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; }
|
||||
cp -R crypto/smartcont artifacts
|
||||
cp -R crypto/fift/lib artifacts
|
||||
chmod -R +x artifacts/*
|
||||
fi
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
cd build
|
||||
# ctest --output-on-failure -E "test-catchain|test-actors|test-smartcont|test-adnl|test-validator-session-state|test-dht|test-rldp"
|
||||
ctest --output-on-failure --timeout 1800
|
||||
fi
|
132
assembly/native/build-ubuntu-portable-libs.sh
Normal file
132
assembly/native/build-ubuntu-portable-libs.sh
Normal file
|
@ -0,0 +1,132 @@
|
|||
#/bin/bash
|
||||
|
||||
#sudo apt-get update
|
||||
#sudo apt-get install -y build-essential git cmake ninja-build automake libtool texinfo autoconf libc++-dev libc++abi-dev
|
||||
|
||||
with_artifacts=false
|
||||
|
||||
while getopts 'ta' flag; do
|
||||
case "${flag}" in
|
||||
a) with_artifacts=true ;;
|
||||
*) break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -d "build" ]; then
|
||||
mkdir build
|
||||
cd build
|
||||
else
|
||||
cd build
|
||||
rm -rf .ninja* CMakeCache.txt
|
||||
fi
|
||||
|
||||
export CC=$(which clang)
|
||||
export CXX=$(which clang++)
|
||||
export CCACHE_DISABLE=1
|
||||
|
||||
if [ ! -d "lz4" ]; then
|
||||
git clone https://github.com/lz4/lz4.git
|
||||
cd lz4
|
||||
lz4Path=`pwd`
|
||||
git checkout v1.9.4
|
||||
CFLAGS="-fPIC" make -j12
|
||||
test $? -eq 0 || { echo "Can't compile lz4"; exit 1; }
|
||||
cd ..
|
||||
# ./lib/liblz4.a
|
||||
# ./lib
|
||||
else
|
||||
lz4Path=$(pwd)/lz4
|
||||
echo "Using compiled lz4"
|
||||
fi
|
||||
|
||||
if [ ! -d "libsodium" ]; then
|
||||
export LIBSODIUM_FULL_BUILD=1
|
||||
git clone https://github.com/jedisct1/libsodium.git
|
||||
cd libsodium
|
||||
sodiumPath=`pwd`
|
||||
git checkout 1.0.18
|
||||
./autogen.sh
|
||||
./configure --with-pic --enable-static
|
||||
make -j12
|
||||
test $? -eq 0 || { echo "Can't compile libsodium"; exit 1; }
|
||||
cd ..
|
||||
else
|
||||
sodiumPath=$(pwd)/libsodium
|
||||
echo "Using compiled libsodium"
|
||||
fi
|
||||
|
||||
if [ ! -d "openssl_3" ]; then
|
||||
git clone https://github.com/openssl/openssl openssl_3
|
||||
cd openssl_3
|
||||
opensslPath=`pwd`
|
||||
git checkout openssl-3.1.4
|
||||
./config
|
||||
make build_libs -j12
|
||||
test $? -eq 0 || { echo "Can't compile openssl_3"; exit 1; }
|
||||
cd ..
|
||||
else
|
||||
opensslPath=$(pwd)/openssl_3
|
||||
echo "Using compiled openssl_3"
|
||||
fi
|
||||
|
||||
if [ ! -d "zlib" ]; then
|
||||
git clone https://github.com/madler/zlib.git
|
||||
cd zlib
|
||||
zlibPath=`pwd`
|
||||
./configure --static
|
||||
make -j12
|
||||
test $? -eq 0 || { echo "Can't compile zlib"; exit 1; }
|
||||
cd ..
|
||||
else
|
||||
zlibPath=$(pwd)/zlib
|
||||
echo "Using compiled zlib"
|
||||
fi
|
||||
|
||||
if [ ! -d "libmicrohttpd" ]; then
|
||||
git clone https://git.gnunet.org/libmicrohttpd.git
|
||||
cd libmicrohttpd
|
||||
libmicrohttpdPath=`pwd`
|
||||
./autogen.sh
|
||||
./configure --enable-static --disable-tests --disable-benchmark --disable-shared --disable-https --with-pic
|
||||
make -j12
|
||||
test $? -eq 0 || { echo "Can't compile libmicrohttpd"; exit 1; }
|
||||
cd ..
|
||||
else
|
||||
libmicrohttpdPath=$(pwd)/libmicrohttpd
|
||||
echo "Using compiled libmicrohttpd"
|
||||
fi
|
||||
|
||||
cmake -GNinja .. \
|
||||
-DPORTABLE=1 \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DOPENSSL_FOUND=1 \
|
||||
-DOPENSSL_INCLUDE_DIR=$opensslPath/include \
|
||||
-DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a \
|
||||
-DZLIB_FOUND=1 \
|
||||
-DZLIB_INCLUDE_DIR=$zlibPath \
|
||||
-DZLIB_LIBRARIES=$zlibPath/libz.a \
|
||||
-DSODIUM_FOUND=1 \
|
||||
-DSODIUM_INCLUDE_DIR=$sodiumPath/src/libsodium/include \
|
||||
-DSODIUM_LIBRARY_RELEASE=$sodiumPath/src/libsodium/.libs/libsodium.a \
|
||||
-DMHD_FOUND=1 \
|
||||
-DMHD_INCLUDE_DIR=$libmicrohttpdPath/src/include \
|
||||
-DMHD_LIBRARY=$libmicrohttpdPath/src/microhttpd/.libs/libmicrohttpd.a \
|
||||
-DLZ4_FOUND=1 \
|
||||
-DLZ4_INCLUDE_DIRS=$lz4Path/lib \
|
||||
-DLZ4_LIBRARIES=$lz4Path/lib/liblz4.a
|
||||
|
||||
|
||||
|
||||
test $? -eq 0 || { echo "Can't configure ton"; exit 1; }
|
||||
|
||||
ninja tonlibjson emulator
|
||||
test $? -eq 0 || { echo "Can't compile ton"; exit 1; }
|
||||
|
||||
cd ..
|
||||
|
||||
mkdir artifacts
|
||||
mv build/tonlib/libtonlibjson.so.0.5 build/tonlib/libtonlibjson.so
|
||||
cp build/tonlib/libtonlibjson.so \
|
||||
build/emulator/libemulator.so \
|
||||
artifacts
|
|
@ -1,7 +1,7 @@
|
|||
#/bin/bash
|
||||
|
||||
#sudo apt-get update
|
||||
#sudo apt-get install -y build-essential git cmake ninja-build automake libtool texinfo autoconf
|
||||
#sudo apt-get install -y build-essential git cmake ninja-build automake libtool texinfo autoconf libc++-dev libc++abi-dev
|
||||
|
||||
with_tests=false
|
||||
with_artifacts=false
|
||||
|
@ -24,8 +24,8 @@ else
|
|||
rm -rf .ninja* CMakeCache.txt
|
||||
fi
|
||||
|
||||
export CC=$(which clang-16)
|
||||
export CXX=$(which clang++-16)
|
||||
export CC=$(which clang)
|
||||
export CXX=$(which clang++)
|
||||
export CCACHE_DISABLE=1
|
||||
|
||||
if [ ! -d "lz4" ]; then
|
||||
|
@ -33,7 +33,7 @@ git clone https://github.com/lz4/lz4.git
|
|||
cd lz4
|
||||
lz4Path=`pwd`
|
||||
git checkout v1.9.4
|
||||
make -j12
|
||||
CFLAGS="-fPIC" make -j12
|
||||
test $? -eq 0 || { echo "Can't compile lz4"; exit 1; }
|
||||
cd ..
|
||||
# ./lib/liblz4.a
|
||||
|
|
|
@ -71,8 +71,8 @@ echo
|
|||
fi
|
||||
|
||||
cd emsdk
|
||||
./emsdk install 3.1.40
|
||||
./emsdk activate 3.1.40
|
||||
./emsdk install 3.1.19
|
||||
./emsdk activate 3.1.19
|
||||
EMSDK_DIR=`pwd`
|
||||
|
||||
. $EMSDK_DIR/emsdk_env.sh
|
||||
|
|
61
assembly/wasm/intrinsics.fc
Normal file
61
assembly/wasm/intrinsics.fc
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma allow-post-modification;
|
||||
#pragma compute-asm-ltr;
|
||||
|
||||
(slice, slice) __tact_load_address(slice cs) inline {
|
||||
slice raw = cs~load_msg_addr();
|
||||
return (cs, raw);
|
||||
}
|
||||
|
||||
slice __gen_slice1 () asm """
|
||||
B{b5ee9c72410101010005000006abcdefe1e98884} B>boc <s PUSHSLICE
|
||||
""";
|
||||
|
||||
slice __gen_slice_slice_eb58904b617945cdf4f33042169c462cd36cf1772a2229f06171fd899e920b7f() asm """
|
||||
B{b5ee9c724101010100030000011025086565} B>boc <s PUSHSLICE
|
||||
""";
|
||||
|
||||
slice __gen_slice3 () asm """
|
||||
B{b5ee9c724101010100030000017888c37a8e} B>boc <s PUSHSLICE
|
||||
""";
|
||||
|
||||
slice __gen_slice_slice_6694a4a61b0dc7c7d5f63bbd394449f6921de7b2ad9cb() asm """
|
||||
B{b5ee9c724101010100820000ffabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdab} B>boc <s PUSHSLICE
|
||||
""";
|
||||
|
||||
slice __gen_slice_slice_80b26bab85f37e2bde3795993cdf7402cd42e68eff6187e8388083ce6cfe7c92() asm """
|
||||
B{b5ee9c724101010100030000018a0adc2f9c} B>boc <s PUSHSLICE
|
||||
""";
|
||||
|
||||
|
||||
(slice,((slice, cell, int, int, slice, slice, int, int, int, int, slice, slice, slice, slice, slice, slice, slice, slice, slice, slice, slice))) IntrinsicsTester_load(slice sc_0) inline {
|
||||
var v'c = sc_0~__tact_load_address();
|
||||
var v'd = sc_0~load_ref();
|
||||
var v'e = sc_0~load_int(257);
|
||||
var v'f = sc_0~load_int(257);
|
||||
slice sc_1 = sc_0~load_ref().begin_parse();
|
||||
var v'g = sc_1~load_ref().begin_parse();
|
||||
var v'h = sc_1~load_ref().begin_parse();
|
||||
var v'i = sc_1~load_int(257);
|
||||
var v'j = sc_1~load_int(257);
|
||||
var v'k = sc_1~load_int(257);
|
||||
slice sc_2 = sc_1~load_ref().begin_parse();
|
||||
var v'l = sc_2~load_int(257);
|
||||
var v'm = sc_2~load_ref().begin_parse();
|
||||
var v'n = sc_2~load_ref().begin_parse();
|
||||
var v'o = sc_2~load_ref().begin_parse();
|
||||
slice sc_3 = sc_2~load_ref().begin_parse();
|
||||
var v'p = sc_3~load_ref().begin_parse();
|
||||
var v'q = sc_3~load_ref().begin_parse();
|
||||
var v'r = sc_3~load_ref().begin_parse();
|
||||
slice sc_4 = sc_3~load_ref().begin_parse();
|
||||
var v's = sc_4~load_ref().begin_parse();
|
||||
var v't = sc_4~load_ref().begin_parse();
|
||||
var v'u = sc_4~load_ref().begin_parse();
|
||||
slice sc_5 = sc_4~load_ref().begin_parse();
|
||||
var v'w = sc_5~load_ref().begin_parse();
|
||||
var v'v = sc_5~load_ref().begin_parse();
|
||||
return (sc_0, (v'c, v'd, v'e, v'f, v'g, v'h, v'i, v'j, v'k, v'l, v'm, v'n, v'o, v'p, v'q, v'r, v's, v't, v'u, v'w, v'v));
|
||||
}
|
||||
|
||||
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { }
|
||||
|
681
assembly/wasm/stdlib.fc
Normal file
681
assembly/wasm/stdlib.fc
Normal file
|
@ -0,0 +1,681 @@
|
|||
;; Standard library for funC
|
||||
;;
|
||||
|
||||
{-
|
||||
This file is part of TON FunC Standard Library.
|
||||
|
||||
FunC Standard Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FunC Standard Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
-}
|
||||
|
||||
{-
|
||||
# Tuple manipulation primitives
|
||||
The names and the types are mostly self-explaining.
|
||||
See [polymorhism with forall](https://ton.org/docs/#/func/functions?id=polymorphism-with-forall)
|
||||
for more info on the polymorphic functions.
|
||||
|
||||
Note that currently values of atomic type `tuple` can't be cast to composite tuple type (e.g. `[int, cell]`)
|
||||
and vise versa.
|
||||
-}
|
||||
|
||||
{-
|
||||
# Lisp-style lists
|
||||
|
||||
Lists can be represented as nested 2-elements tuples.
|
||||
Empty list is conventionally represented as TVM `null` value (it can be obtained by calling [null()]).
|
||||
For example, tuple `(1, (2, (3, null)))` represents list `[1, 2, 3]`. Elements of a list can be of different types.
|
||||
-}
|
||||
|
||||
;;; Adds an element to the beginning of lisp-style list.
|
||||
forall X -> tuple cons(X head, tuple tail) asm "CONS";
|
||||
|
||||
;;; Extracts the head and the tail of lisp-style list.
|
||||
forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";
|
||||
|
||||
;;; Extracts the tail and the head of lisp-style list.
|
||||
forall X -> (tuple, X) list_next(tuple list) asm(-> 1 0) "UNCONS";
|
||||
|
||||
;;; Returns the head of lisp-style list.
|
||||
forall X -> X car(tuple list) asm "CAR";
|
||||
|
||||
;;; Returns the tail of lisp-style list.
|
||||
tuple cdr(tuple list) asm "CDR";
|
||||
|
||||
;;; Creates tuple with zero elements.
|
||||
tuple empty_tuple() asm "NIL";
|
||||
|
||||
;;; Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)`
|
||||
;;; is of length at most 255. Otherwise throws a type check exception.
|
||||
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
|
||||
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
|
||||
|
||||
;;; Creates a tuple of length one with given argument as element.
|
||||
forall X -> [X] single(X x) asm "SINGLE";
|
||||
|
||||
;;; Unpacks a tuple of length one
|
||||
forall X -> X unsingle([X] t) asm "UNSINGLE";
|
||||
|
||||
;;; Creates a tuple of length two with given arguments as elements.
|
||||
forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR";
|
||||
|
||||
;;; Unpacks a tuple of length two
|
||||
forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR";
|
||||
|
||||
;;; Creates a tuple of length three with given arguments as elements.
|
||||
forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE";
|
||||
|
||||
;;; Unpacks a tuple of length three
|
||||
forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE";
|
||||
|
||||
;;; Creates a tuple of length four with given arguments as elements.
|
||||
forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE";
|
||||
|
||||
;;; Unpacks a tuple of length four
|
||||
forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE";
|
||||
|
||||
;;; Returns the first element of a tuple (with unknown element types).
|
||||
forall X -> X first(tuple t) asm "FIRST";
|
||||
|
||||
;;; Returns the second element of a tuple (with unknown element types).
|
||||
forall X -> X second(tuple t) asm "SECOND";
|
||||
|
||||
;;; Returns the third element of a tuple (with unknown element types).
|
||||
forall X -> X third(tuple t) asm "THIRD";
|
||||
|
||||
;;; Returns the fourth element of a tuple (with unknown element types).
|
||||
forall X -> X fourth(tuple t) asm "3 INDEX";
|
||||
|
||||
;;; Returns the first element of a pair tuple.
|
||||
forall X, Y -> X pair_first([X, Y] p) asm "FIRST";
|
||||
|
||||
;;; Returns the second element of a pair tuple.
|
||||
forall X, Y -> Y pair_second([X, Y] p) asm "SECOND";
|
||||
|
||||
;;; Returns the first element of a triple tuple.
|
||||
forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST";
|
||||
|
||||
;;; Returns the second element of a triple tuple.
|
||||
forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";
|
||||
|
||||
;;; Returns the third element of a triple tuple.
|
||||
forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD";
|
||||
|
||||
|
||||
;;; Push null element (casted to given type)
|
||||
;;; By the TVM type `Null` FunC represents absence of a value of some atomic type.
|
||||
;;; So `null` can actually have any atomic type.
|
||||
forall X -> X null() asm "PUSHNULL";
|
||||
|
||||
;;; Moves a variable [x] to the top of the stack
|
||||
forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP";
|
||||
|
||||
|
||||
|
||||
;;; Returns the current Unix time as an Integer
|
||||
int now() asm "NOW";
|
||||
|
||||
;;; Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`.
|
||||
;;; If necessary, it can be parsed further using primitives such as [parse_std_addr].
|
||||
slice my_address() asm "MYADDR";
|
||||
|
||||
;;; Returns the balance of the smart contract as a tuple consisting of an int
|
||||
;;; (balance in nanotoncoins) and a `cell`
|
||||
;;; (a dictionary with 32-bit keys representing the balance of "extra currencies")
|
||||
;;; at the start of Computation Phase.
|
||||
;;; Note that RAW primitives such as [send_raw_message] do not update this field.
|
||||
[int, cell] get_balance() asm "BALANCE";
|
||||
|
||||
;;; Returns the logical time of the current transaction.
|
||||
int cur_lt() asm "LTIME";
|
||||
|
||||
;;; Returns the starting logical time of the current block.
|
||||
int block_lt() asm "BLOCKLT";
|
||||
|
||||
;;; Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`.
|
||||
;;; Useful for signing and checking signatures of arbitrary entities represented by a tree of cells.
|
||||
int cell_hash(cell c) asm "HASHCU";
|
||||
|
||||
;;; Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`.
|
||||
;;; The result is the same as if an ordinary cell containing only data and references from `s` had been created
|
||||
;;; and its hash computed by [cell_hash].
|
||||
int slice_hash(slice s) asm "HASHSU";
|
||||
|
||||
;;; Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight,
|
||||
;;; throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`.
|
||||
int string_hash(slice s) asm "SHA256U";
|
||||
|
||||
{-
|
||||
# Signature checks
|
||||
-}
|
||||
|
||||
;;; Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data)
|
||||
;;; using [public_key] (also represented by a 256-bit unsigned integer).
|
||||
;;; The signature must contain at least 512 data bits; only the first 512 bits are used.
|
||||
;;; The result is `−1` if the signature is valid, `0` otherwise.
|
||||
;;; Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`.
|
||||
;;; That is, if [hash] is computed as the hash of some data, these data are hashed twice,
|
||||
;;; the second hashing occurring inside `CHKSIGNS`.
|
||||
int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU";
|
||||
|
||||
;;; Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`,
|
||||
;;; similarly to [check_signature].
|
||||
;;; If the bit length of [data] is not divisible by eight, throws a cell underflow exception.
|
||||
;;; The verification of Ed25519 signatures is the standard one,
|
||||
;;; with sha256 used to reduce [data] to the 256-bit number that is actually signed.
|
||||
int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS";
|
||||
|
||||
{---
|
||||
# Computation of boc size
|
||||
The primitives below may be useful for computing storage fees of user-provided data.
|
||||
-}
|
||||
|
||||
;;; Returns `(x, y, z, -1)` or `(null, null, null, 0)`.
|
||||
;;; Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z`
|
||||
;;; in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account
|
||||
;;; the identification of equal cells.
|
||||
;;; The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG,
|
||||
;;; with a hash table of visited cell hashes used to prevent visits of already-visited cells.
|
||||
;;; The total count of visited cells `x` cannot exceed non-negative [max_cells];
|
||||
;;; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and
|
||||
;;; a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`.
|
||||
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
|
||||
|
||||
;;; Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`.
|
||||
;;; The returned value of `x` does not take into account the cell that contains the `slice` [s] itself;
|
||||
;;; however, the data bits and the cell references of [s] are accounted for in `y` and `z`.
|
||||
(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE";
|
||||
|
||||
;;; A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure.
|
||||
(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
|
||||
;;; A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure.
|
||||
(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
|
||||
;;; Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator)
|
||||
;; () throw_if(int excno, int cond) impure asm "THROWARGIF";
|
||||
|
||||
{--
|
||||
# Debug primitives
|
||||
Only works for local TVM execution with debug level verbosity
|
||||
-}
|
||||
;;; Dumps the stack (at most the top 255 values) and shows the total stack depth.
|
||||
() dump_stack() impure asm "DUMPSTK";
|
||||
|
||||
{-
|
||||
# Persistent storage save and load
|
||||
-}
|
||||
|
||||
;;; Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later.
|
||||
cell get_data() asm "c4 PUSH";
|
||||
|
||||
;;; Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive.
|
||||
() set_data(cell c) impure asm "c4 POP";
|
||||
|
||||
{-
|
||||
# Continuation primitives
|
||||
-}
|
||||
;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.
|
||||
;;; The primitive returns the current value of `c3`.
|
||||
cont get_c3() impure asm "c3 PUSH";
|
||||
|
||||
;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time.
|
||||
;;; Note that after execution of this primitive the current code
|
||||
;;; (and the stack of recursive function calls) won't change,
|
||||
;;; but any other function call will use a function from the new code.
|
||||
() set_c3(cont c) impure asm "c3 POP";
|
||||
|
||||
;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist.
|
||||
cont bless(slice s) impure asm "BLESS";
|
||||
|
||||
{---
|
||||
# Gas related primitives
|
||||
-}
|
||||
|
||||
;;; Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero,
|
||||
;;; decreasing the value of `gr` by `gc` in the process.
|
||||
;;; In other words, the current smart contract agrees to buy some gas to finish the current transaction.
|
||||
;;; This action is required to process external messages, which bring no value (hence no gas) with themselves.
|
||||
;;;
|
||||
;;; For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept).
|
||||
() accept_message() impure asm "ACCEPT";
|
||||
|
||||
;;; Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero.
|
||||
;;; If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`,
|
||||
;;; an (unhandled) out of gas exception is thrown before setting new gas limits.
|
||||
;;; Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message].
|
||||
() set_gas_limit(int limit) impure asm "SETGASLIMIT";
|
||||
|
||||
;;; Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”)
|
||||
;;; so that the current execution is considered “successful” with the saved values even if an exception
|
||||
;;; in Computation Phase is thrown later.
|
||||
() commit() impure asm "COMMIT";
|
||||
|
||||
;;; Not implemented
|
||||
;;; Computes the amount of gas that can be bought for `amount` nanoTONs,
|
||||
;;; and sets `gl` accordingly in the same way as [set_gas_limit].
|
||||
;;() buy_gas(int amount) impure asm "BUYGAS";
|
||||
|
||||
;;; Computes the minimum of two integers [x] and [y].
|
||||
int min(int x, int y) asm "MIN";
|
||||
|
||||
;;; Computes the maximum of two integers [x] and [y].
|
||||
int max(int x, int y) asm "MAX";
|
||||
|
||||
;;; Sorts two integers.
|
||||
(int, int) minmax(int x, int y) asm "MINMAX";
|
||||
|
||||
;;; Computes the absolute value of an integer [x].
|
||||
int abs(int x) asm "ABS";
|
||||
|
||||
{-
|
||||
# Slice primitives
|
||||
|
||||
It is said that a primitive _loads_ some data,
|
||||
if it returns the data and the remainder of the slice
|
||||
(so it can also be used as [modifying method](https://ton.org/docs/#/func/statements?id=modifying-methods)).
|
||||
|
||||
It is said that a primitive _preloads_ some data, if it returns only the data
|
||||
(it can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods)).
|
||||
|
||||
Unless otherwise stated, loading and preloading primitives read the data from a prefix of the slice.
|
||||
-}
|
||||
|
||||
|
||||
;;; Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell,
|
||||
;;; or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2)
|
||||
;;; which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards.
|
||||
slice begin_parse(cell c) asm "CTOS";
|
||||
|
||||
;;; Checks if [s] is empty. If not, throws an exception.
|
||||
() end_parse(slice s) impure asm "ENDS";
|
||||
|
||||
;;; Loads the first reference from the slice.
|
||||
(slice, cell) load_ref(slice s) asm(-> 1 0) "LDREF";
|
||||
|
||||
;;; Preloads the first reference from the slice.
|
||||
cell preload_ref(slice s) asm "PLDREF";
|
||||
|
||||
{- Functions below are commented because are implemented on compilator level for optimisation -}
|
||||
|
||||
;;; Loads a signed [len]-bit integer from a slice [s].
|
||||
;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX";
|
||||
|
||||
;;; Loads an unsigned [len]-bit integer from a slice [s].
|
||||
;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX";
|
||||
|
||||
;;; Preloads a signed [len]-bit integer from a slice [s].
|
||||
;; int preload_int(slice s, int len) asm "PLDIX";
|
||||
|
||||
;;; Preloads an unsigned [len]-bit integer from a slice [s].
|
||||
;; int preload_uint(slice s, int len) asm "PLDUX";
|
||||
|
||||
;;; Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`.
|
||||
;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX";
|
||||
|
||||
;;; 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^120 - 1`).
|
||||
(slice, int) load_grams(slice s) asm(-> 1 0) "LDGRAMS";
|
||||
(slice, int) load_coins(slice s) asm(-> 1 0) "LDVARUINT16";
|
||||
|
||||
(slice, int) load_varint16(slice s) asm(-> 1 0) "LDVARINT16";
|
||||
(slice, int) load_varint32(slice s) asm(-> 1 0) "LDVARINT32";
|
||||
(slice, int) load_varuint16(slice s) asm(-> 1 0) "LDVARUINT16";
|
||||
(slice, int) load_varuint32(slice s) asm(-> 1 0) "LDVARUINT32";
|
||||
|
||||
;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||
slice skip_bits(slice s, int len) asm "SDSKIPFIRST";
|
||||
(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST";
|
||||
|
||||
;;; Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||
slice first_bits(slice s, int len) asm "SDCUTFIRST";
|
||||
|
||||
;;; Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||
slice skip_last_bits(slice s, int len) asm "SDSKIPLAST";
|
||||
(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST";
|
||||
|
||||
;;; Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||
slice slice_last(slice s, int len) asm "SDCUTLAST";
|
||||
|
||||
;;; Loads a dictionary `D` (HashMapE) from `slice` [s].
|
||||
;;; (returns `null` if `nothing` constructor is used).
|
||||
(slice, cell) load_dict(slice s) asm(-> 1 0) "LDDICT";
|
||||
|
||||
;;; Preloads a dictionary `D` from `slice` [s].
|
||||
cell preload_dict(slice s) asm "PLDDICT";
|
||||
|
||||
;;; Loads a dictionary as [load_dict], but returns only the remainder of the slice.
|
||||
slice skip_dict(slice s) asm "SKIPDICT";
|
||||
(slice, ()) ~skip_dict(slice s) asm "SKIPDICT";
|
||||
|
||||
;;; Loads (Maybe ^Cell) from `slice` [s].
|
||||
;;; In other words loads 1 bit and if it is true
|
||||
;;; loads first ref and return it with slice remainder
|
||||
;;; otherwise returns `null` and slice remainder
|
||||
(slice, cell) load_maybe_ref(slice s) asm(-> 1 0) "LDOPTREF";
|
||||
|
||||
;;; Preloads (Maybe ^Cell) from `slice` [s].
|
||||
cell preload_maybe_ref(slice s) asm "PLDOPTREF";
|
||||
|
||||
|
||||
;;; Returns the depth of `cell` [c].
|
||||
;;; If [c] has no references, then return `0`;
|
||||
;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [c].
|
||||
;;; If [c] is a `null` instead of a cell, returns zero.
|
||||
int cell_depth(cell c) asm "CDEPTH";
|
||||
|
||||
|
||||
{-
|
||||
# Slice size primitives
|
||||
-}
|
||||
|
||||
;;; Returns the number of references in `slice` [s].
|
||||
int slice_refs(slice s) asm "SREFS";
|
||||
|
||||
;;; Returns the number of data bits in `slice` [s].
|
||||
int slice_bits(slice s) asm "SBITS";
|
||||
|
||||
;;; Returns both the number of data bits and the number of references in `slice` [s].
|
||||
(int, int) slice_bits_refs(slice s) asm "SBITREFS";
|
||||
|
||||
;;; Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references).
|
||||
int slice_empty?(slice s) asm "SEMPTY";
|
||||
|
||||
;;; Checks whether `slice` [s] has no bits of data.
|
||||
int slice_data_empty?(slice s) asm "SDEMPTY";
|
||||
|
||||
;;; Checks whether `slice` [s] has no references.
|
||||
int slice_refs_empty?(slice s) asm "SREMPTY";
|
||||
|
||||
;;; Returns the depth of `slice` [s].
|
||||
;;; If [s] has no references, then returns `0`;
|
||||
;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [s].
|
||||
int slice_depth(slice s) asm "SDEPTH";
|
||||
|
||||
{-
|
||||
# Builder size primitives
|
||||
-}
|
||||
|
||||
;;; Returns the number of cell references already stored in `builder` [b]
|
||||
int builder_refs(builder b) asm "BREFS";
|
||||
|
||||
;;; Returns the number of data bits already stored in `builder` [b].
|
||||
int builder_bits(builder b) asm "BBITS";
|
||||
|
||||
;;; Returns the depth of `builder` [b].
|
||||
;;; If no cell references are stored in [b], then returns 0;
|
||||
;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [b].
|
||||
int builder_depth(builder b) asm "BDEPTH";
|
||||
|
||||
{-
|
||||
# Builder primitives
|
||||
It is said that a primitive _stores_ a value `x` into a builder `b`
|
||||
if it returns a modified version of the builder `b'` with the value `x` stored at the end of it.
|
||||
It can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods).
|
||||
|
||||
All the primitives below first check whether there is enough space in the `builder`,
|
||||
and only then check the range of the value being serialized.
|
||||
-}
|
||||
|
||||
;;; Creates a new empty `builder`.
|
||||
builder begin_cell() asm "NEWC";
|
||||
|
||||
;;; Converts a `builder` into an ordinary `cell`.
|
||||
cell end_cell(builder b) asm "ENDC";
|
||||
|
||||
;;; Stores a reference to `cell` [c] into `builder` [b].
|
||||
builder store_ref(builder b, cell c) asm(c b) "STREF";
|
||||
|
||||
;;; Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`.
|
||||
;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX";
|
||||
|
||||
;;; Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`.
|
||||
;; builder store_int(builder b, int x, int len) asm(x b len) "STIX";
|
||||
|
||||
|
||||
;;; 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^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].
|
||||
;;; If [x] does not belong to the supported range, a range check exception is thrown.
|
||||
;;;
|
||||
;;; Store amounts of TonCoins to the builder as VarUInteger 16
|
||||
builder store_grams(builder b, int x) asm "STGRAMS";
|
||||
builder store_coins(builder b, int x) asm "STVARUINT16";
|
||||
|
||||
builder store_varint16(builder b, int x) asm "STVARINT16";
|
||||
builder store_varint32(builder b, int x) asm "STVARINT32";
|
||||
builder store_varuint16(builder b, int x) asm "STVARUINT16";
|
||||
builder store_varuint32(builder b, int x) asm "STVARUINT32";
|
||||
|
||||
;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b].
|
||||
;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise.
|
||||
builder store_dict(builder b, cell c) asm(c b) "STDICT";
|
||||
|
||||
;;; Stores (Maybe ^Cell) to builder:
|
||||
;;; if cell is null store 1 zero bit
|
||||
;;; otherwise store 1 true bit and ref to cell
|
||||
builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
|
||||
|
||||
|
||||
{-
|
||||
# Address manipulation primitives
|
||||
The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme:
|
||||
```TL-B
|
||||
addr_none$00 = MsgAddressExt;
|
||||
addr_extern$01 len:(## 8) external_address:(bits len)
|
||||
= MsgAddressExt;
|
||||
anycast_info$_ depth:(#<= 30) { depth >= 1 }
|
||||
rewrite_pfx:(bits depth) = Anycast;
|
||||
addr_std$10 anycast:(Maybe Anycast)
|
||||
workchain_id:int8 address:bits256 = MsgAddressInt;
|
||||
addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
|
||||
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
|
||||
_ _:MsgAddressInt = MsgAddress;
|
||||
_ _:MsgAddressExt = MsgAddress;
|
||||
|
||||
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
src:MsgAddress dest:MsgAddressInt
|
||||
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
|
||||
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;
|
||||
ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt
|
||||
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;
|
||||
```
|
||||
A deserialized `MsgAddress` is represented by a tuple `t` as follows:
|
||||
|
||||
- `addr_none` is represented by `t = (0)`,
|
||||
i.e., a tuple containing exactly one integer equal to zero.
|
||||
- `addr_extern` is represented by `t = (1, s)`,
|
||||
where slice `s` contains the field `external_address`. In other words, `
|
||||
t` is a pair (a tuple consisting of two entries), containing an integer equal to one and slice `s`.
|
||||
- `addr_std` is represented by `t = (2, u, x, s)`,
|
||||
where `u` is either a `null` (if `anycast` is absent) or a slice `s'` containing `rewrite_pfx` (if anycast is present).
|
||||
Next, integer `x` is the `workchain_id`, and slice `s` contains the address.
|
||||
- `addr_var` is represented by `t = (3, u, x, s)`,
|
||||
where `u`, `x`, and `s` have the same meaning as for `addr_std`.
|
||||
-}
|
||||
|
||||
;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`,
|
||||
;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices.
|
||||
(slice, slice) load_msg_addr(slice s) asm(-> 1 0) "LDMSGADDR";
|
||||
|
||||
;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`.
|
||||
;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown.
|
||||
tuple parse_addr(slice s) asm "PARSEMSGADDR";
|
||||
|
||||
;;; Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`),
|
||||
;;; applies rewriting from the anycast (if present) to the same-length prefix of the address,
|
||||
;;; and returns both the workchain and the 256-bit address as integers.
|
||||
;;; If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`,
|
||||
;;; throws a cell deserialization exception.
|
||||
(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR";
|
||||
|
||||
;;; A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s],
|
||||
;;; even if it is not exactly 256 bit long (represented by a `msg_addr_var`).
|
||||
(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR";
|
||||
|
||||
{-
|
||||
# Dictionary primitives
|
||||
-}
|
||||
|
||||
|
||||
;;; Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell),
|
||||
;;; and returns the resulting dictionary.
|
||||
cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
|
||||
(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
|
||||
|
||||
;;; Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell),
|
||||
;;; and returns the resulting dictionary.
|
||||
cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||
(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||
|
||||
cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF";
|
||||
(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT";
|
||||
(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT";
|
||||
(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF";
|
||||
(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF";
|
||||
(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL";
|
||||
(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL";
|
||||
(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
|
||||
(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT";
|
||||
(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||
(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||
(cell, cell, int) idict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGETREF" "NULLSWAPIFNOT";
|
||||
(cell, cell, int) udict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGETREF" "NULLSWAPIFNOT";
|
||||
(cell, (cell, int)) ~idict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGETREF" "NULLSWAPIFNOT";
|
||||
(cell, (cell, int)) ~udict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGETREF" "NULLSWAPIFNOT";
|
||||
cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
|
||||
(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
|
||||
cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
|
||||
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
|
||||
cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
|
||||
(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
|
||||
(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD";
|
||||
(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE";
|
||||
(cell, int) udict_replace_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUREPLACEREF";
|
||||
(cell, slice, int) udict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACEGET" "NULLSWAPIFNOT";
|
||||
(cell, cell, int) udict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUREPLACEGETREF" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~udict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACEGET" "NULLSWAPIFNOT";
|
||||
(cell, (cell, int)) ~udict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUREPLACEGETREF" "NULLSWAPIFNOT";
|
||||
(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD";
|
||||
(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE";
|
||||
(cell, int) idict_replace_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTIREPLACEREF";
|
||||
(cell, slice, int) idict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACEGET" "NULLSWAPIFNOT";
|
||||
(cell, cell, int) idict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTIREPLACEGETREF" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~idict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACEGET" "NULLSWAPIFNOT";
|
||||
(cell, (cell, int)) ~idict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTIREPLACEGETREF" "NULLSWAPIFNOT";
|
||||
cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
|
||||
(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
|
||||
cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
|
||||
(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
|
||||
cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
|
||||
(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
|
||||
(cell, int) dict_replace_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTREPLACEB";
|
||||
(cell, builder, int) dict_replaceget_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTREPLACEGETB" "NULLSWAPIFNOT";
|
||||
(cell, slice, int) dict_replaceget?(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTREPLACEGET" "NULLSWAPIFNOT";
|
||||
(cell, (builder, int)) ~dict_replaceget_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTREPLACEGETB" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~dict_replaceget?(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTREPLACEGET" "NULLSWAPIFNOT";
|
||||
(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB";
|
||||
(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB";
|
||||
(cell, builder, int) udict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEGETB" "NULLSWAPIFNOT";
|
||||
(cell, (builder, int)) ~udict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEGETB" "NULLSWAPIFNOT";
|
||||
(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB";
|
||||
(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB";
|
||||
(cell, builder, int) idict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEGETB" "NULLSWAPIFNOT";
|
||||
(cell, (builder, int)) ~idict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEGETB" "NULLSWAPIFNOT";
|
||||
(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";
|
||||
|
||||
;;; Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL
|
||||
cell new_dict() asm "NEWDICT";
|
||||
;;; Checks whether a dictionary is empty. Equivalent to cell_null?.
|
||||
int dict_empty?(cell c) asm "DICTEMPTY";
|
||||
|
||||
|
||||
{- Prefix dictionary primitives -}
|
||||
(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
||||
(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET";
|
||||
(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL";
|
||||
|
||||
;;; Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value.
|
||||
cell config_param(int x) asm "CONFIGOPTPARAM";
|
||||
;;; Checks whether c is a null. Note, that FunC also has polymorphic null? built-in.
|
||||
int cell_null?(cell c) asm "ISNULL";
|
||||
|
||||
;;; Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15.
|
||||
() raw_reserve(int amount, int mode) impure asm "RAWRESERVE";
|
||||
;;; Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved.
|
||||
() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX";
|
||||
;;; Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128.
|
||||
() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG";
|
||||
;;; Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract
|
||||
() set_code(cell new_code) impure asm "SETCODE";
|
||||
|
||||
;;; Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x.
|
||||
int random() impure asm "RANDU256";
|
||||
;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed.
|
||||
int rand(int range) impure asm "RAND";
|
||||
;;; Returns the current random seed as an unsigned 256-bit Integer.
|
||||
int get_seed() impure asm "RANDSEED";
|
||||
;;; Sets the random seed to unsigned 256-bit seed.
|
||||
() set_seed(int x) impure asm "SETRAND";
|
||||
;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x.
|
||||
() randomize(int x) impure asm "ADDRAND";
|
||||
;;; Equivalent to randomize(cur_lt());.
|
||||
() randomize_lt() impure asm "LTIME" "ADDRAND";
|
||||
|
||||
;;; Checks whether the data parts of two slices coinside
|
||||
int equal_slices_bits(slice a, slice b) asm "SDEQ";
|
||||
;;; Checks whether b is a null. Note, that FunC also has polymorphic null? built-in.
|
||||
int builder_null?(builder b) asm "ISNULL";
|
||||
;;; Concatenates two builders
|
||||
builder store_builder(builder to, builder from) asm "STBR";
|
||||
|
||||
;; CUSTOM:
|
||||
|
||||
;; TVM UPGRADE 2023-07 https://docs.ton.org/learn/tvm-instructions/tvm-upgrade-2023-07
|
||||
;; In mainnet since 20 Dec 2023 https://t.me/tonblockchain/226
|
||||
|
||||
;;; Retrieves code of smart-contract from c7
|
||||
|
||||
cell my_code() asm "MYCODE";
|
|
@ -526,10 +526,12 @@ void CatChainReceiverImpl::start_up() {
|
|||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
root_keys.emplace(get_source(i)->get_hash(), OVERLAY_MAX_ALLOWED_PACKET_SIZE);
|
||||
}
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::create_private_overlay,
|
||||
overlay::OverlayOptions overlay_options;
|
||||
overlay_options.broadcast_speed_multiplier_ = opts_.broadcast_speed_multiplier;
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::create_private_overlay_ex,
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_full_id_.clone(), std::move(ids),
|
||||
make_callback(), overlay::OverlayPrivacyRules{0, 0, std::move(root_keys)},
|
||||
R"({ "type": "catchain" })");
|
||||
R"({ "type": "catchain" })", std::move(overlay_options));
|
||||
|
||||
CHECK(root_block_);
|
||||
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
namespace ton {
|
||||
|
||||
// See doc/GlobalVersions.md
|
||||
const int SUPPORTED_VERSION = 9;
|
||||
constexpr int SUPPORTED_VERSION = 10;
|
||||
|
||||
}
|
||||
|
|
|
@ -360,7 +360,6 @@ MsgProcessedUptoCollection::MsgProcessedUptoCollection(ton::ShardIdFull _owner,
|
|||
z.shard = key.get_uint(64);
|
||||
z.mc_seqno = (unsigned)((key + 64).get_uint(32));
|
||||
z.last_inmsg_lt = value.write().fetch_ulong(64);
|
||||
// std::cerr << "ProcessedUpto shard " << std::hex << z.shard << std::dec << std::endl;
|
||||
return value.write().fetch_bits_to(z.last_inmsg_hash) && z.shard && ton::shard_contains(owner.shard, z.shard);
|
||||
});
|
||||
}
|
||||
|
@ -862,8 +861,10 @@ td::Status ShardState::unpack_out_msg_queue_info(Ref<vm::Cell> out_msg_queue_inf
|
|||
out_msg_queue_ =
|
||||
std::make_unique<vm::AugmentedDictionary>(std::move(qinfo.out_queue), 352, block::tlb::aug_OutMsgQueue);
|
||||
if (verbosity >= 3 * 1) {
|
||||
LOG(DEBUG) << "unpacking ProcessedUpto of our previous block " << id_.to_str();
|
||||
block::gen::t_ProcessedInfo.print(std::cerr, qinfo.proc_info);
|
||||
FLOG(DEBUG) {
|
||||
sb << "unpacking ProcessedUpto of our previous block " << id_.to_str();
|
||||
block::gen::t_ProcessedInfo.print(sb, qinfo.proc_info);
|
||||
};
|
||||
}
|
||||
if (!block::gen::t_ProcessedInfo.validate_csr(1024, qinfo.proc_info)) {
|
||||
return td::Status::Error(
|
||||
|
@ -1319,6 +1320,65 @@ CurrencyCollection CurrencyCollection::operator-(td::RefInt256 other_grams) cons
|
|||
}
|
||||
}
|
||||
|
||||
bool CurrencyCollection::clamp(const CurrencyCollection& other) {
|
||||
if (!is_valid() || !other.is_valid()) {
|
||||
return invalidate();
|
||||
}
|
||||
grams = std::min(grams, other.grams);
|
||||
vm::Dictionary dict1{extra, 32}, dict2(other.extra, 32);
|
||||
bool ok = dict1.check_for_each([&](td::Ref<vm::CellSlice> cs1, td::ConstBitPtr key, int n) {
|
||||
CHECK(n == 32);
|
||||
td::Ref<vm::CellSlice> cs2 = dict2.lookup(key, 32);
|
||||
td::RefInt256 val1 = tlb::t_VarUIntegerPos_32.as_integer(cs1);
|
||||
if (val1.is_null()) {
|
||||
return false;
|
||||
}
|
||||
td::RefInt256 val2 = cs2.is_null() ? td::zero_refint() : tlb::t_VarUIntegerPos_32.as_integer(cs2);
|
||||
if (val2.is_null()) {
|
||||
return false;
|
||||
}
|
||||
if (val1 > val2) {
|
||||
if (val2->sgn() == 0) {
|
||||
dict1.lookup_delete(key, 32);
|
||||
} else {
|
||||
dict1.set(key, 32, cs2);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
extra = dict1.get_root_cell();
|
||||
return ok || invalidate();
|
||||
}
|
||||
|
||||
bool CurrencyCollection::check_extra_currency_limit(td::uint32 max_currencies) const {
|
||||
td::uint32 count = 0;
|
||||
return vm::Dictionary{extra, 32}.check_for_each([&](td::Ref<vm::CellSlice>, td::ConstBitPtr, int) {
|
||||
++count;
|
||||
return count <= max_currencies;
|
||||
});
|
||||
}
|
||||
|
||||
bool CurrencyCollection::remove_zero_extra_currencies(Ref<vm::Cell>& root, td::uint32 max_currencies) {
|
||||
td::uint32 count = 0;
|
||||
vm::Dictionary dict{root, 32};
|
||||
int res = dict.filter([&](const vm::CellSlice& cs, td::ConstBitPtr, int) -> int {
|
||||
++count;
|
||||
if (count > max_currencies) {
|
||||
return -1;
|
||||
}
|
||||
td::RefInt256 val = tlb::t_VarUInteger_32.as_integer(cs);
|
||||
if (val.is_null()) {
|
||||
return -1;
|
||||
}
|
||||
return val->sgn() > 0;
|
||||
});
|
||||
if (res < 0) {
|
||||
return false;
|
||||
}
|
||||
root = dict.get_root_cell();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CurrencyCollection::operator==(const CurrencyCollection& other) const {
|
||||
return is_valid() && other.is_valid() && !td::cmp(grams, other.grams) &&
|
||||
(extra.not_null() == other.extra.not_null()) &&
|
||||
|
|
|
@ -390,6 +390,9 @@ struct CurrencyCollection {
|
|||
CurrencyCollection operator-(const CurrencyCollection& other) const;
|
||||
CurrencyCollection operator-(CurrencyCollection&& other) const;
|
||||
CurrencyCollection operator-(td::RefInt256 other_grams) const;
|
||||
bool clamp(const CurrencyCollection& other);
|
||||
bool check_extra_currency_limit(td::uint32 max_currencies) const;
|
||||
static bool remove_zero_extra_currencies(Ref<vm::Cell>& root, td::uint32 max_currencies);
|
||||
bool store(vm::CellBuilder& cb) const;
|
||||
bool store_or_zero(vm::CellBuilder& cb) const;
|
||||
bool fetch(vm::CellSlice& cs);
|
||||
|
|
|
@ -296,7 +296,7 @@ transaction$0111 account_addr:bits256 lt:uint64
|
|||
total_fees:CurrencyCollection state_update:^(HASH_UPDATE Account)
|
||||
description:^TransactionDescr = Transaction;
|
||||
|
||||
!merkle_update#02 {X:Type} old_hash:bits256 new_hash:bits256
|
||||
!merkle_update#04 {X:Type} old_hash:bits256 new_hash:bits256 old_depth:uint16 new_depth:uint16
|
||||
old:^X new:^X = MERKLE_UPDATE X;
|
||||
update_hashes#72 {X:Type} old_hash:bits256 new_hash:bits256
|
||||
= HASH_UPDATE X;
|
||||
|
@ -801,7 +801,7 @@ size_limits_config#01 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells
|
|||
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 = SizeLimitsConfig;
|
||||
size_limits_config_v2#02 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16
|
||||
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 max_acc_state_cells:uint32 max_acc_state_bits:uint32
|
||||
max_acc_public_libraries:uint32 defer_out_queue_size_limit:uint32 = SizeLimitsConfig;
|
||||
max_acc_public_libraries:uint32 defer_out_queue_size_limit:uint32 max_msg_extra_currencies:uint32 = SizeLimitsConfig;
|
||||
_ SizeLimitsConfig = ConfigParam 43;
|
||||
|
||||
// key is [ wc:int32 addr:uint256 ]
|
||||
|
|
|
@ -163,8 +163,11 @@ td::Status ConfigInfo::unpack() {
|
|||
}
|
||||
gen::McStateExtra::Record extra_info;
|
||||
if (!tlb::unpack_cell(state_extra_root_, extra_info)) {
|
||||
vm::load_cell_slice(state_extra_root_).print_rec(std::cerr);
|
||||
block::gen::t_McStateExtra.print_ref(std::cerr, state_extra_root_);
|
||||
FLOG(WARNING) {
|
||||
sb << "state extra information is invalid: ";
|
||||
vm::load_cell_slice(state_extra_root_).print_rec(sb);
|
||||
block::gen::t_McStateExtra.print_ref(sb, state_extra_root_);
|
||||
};
|
||||
return td::Status::Error("state extra information is invalid");
|
||||
}
|
||||
gen::ValidatorInfo::Record validator_info;
|
||||
|
@ -1067,7 +1070,6 @@ Ref<McShardHash> ShardConfig::get_shard_hash(ton::ShardIdFull id, bool exact) co
|
|||
ton::ShardIdFull true_id;
|
||||
vm::CellSlice cs;
|
||||
if (get_shard_hash_raw(cs, id, true_id, exact)) {
|
||||
// block::gen::t_ShardDescr.print(std::cerr, vm::CellSlice{cs});
|
||||
return McShardHash::unpack(cs, true_id);
|
||||
} else {
|
||||
return {};
|
||||
|
@ -1637,8 +1639,10 @@ bool ShardConfig::set_shard_info(ton::ShardIdFull shard, Ref<vm::Cell> value) {
|
|||
if (!gen::t_BinTree_ShardDescr.validate_ref(1024, value)) {
|
||||
LOG(ERROR) << "attempting to store an invalid (BinTree ShardDescr) at shard configuration position "
|
||||
<< shard.to_str();
|
||||
gen::t_BinTree_ShardDescr.print_ref(std::cerr, value);
|
||||
vm::load_cell_slice(value).print_rec(std::cerr);
|
||||
FLOG(WARNING) {
|
||||
gen::t_BinTree_ShardDescr.print_ref(sb, value);
|
||||
vm::load_cell_slice(value).print_rec(sb);
|
||||
};
|
||||
return false;
|
||||
}
|
||||
auto root = shard_hashes_dict_->lookup_ref(td::BitArray<32>{shard.workchain});
|
||||
|
@ -1956,6 +1960,7 @@ td::Result<SizeLimitsConfig> Config::do_get_size_limits_config(td::Ref<vm::CellS
|
|||
limits.max_acc_state_cells = rec.max_acc_state_cells;
|
||||
limits.max_acc_public_libraries = rec.max_acc_public_libraries;
|
||||
limits.defer_out_queue_size_limit = rec.defer_out_queue_size_limit;
|
||||
limits.max_msg_extra_currencies = rec.max_msg_extra_currencies;
|
||||
};
|
||||
gen::SizeLimitsConfig::Record_size_limits_config rec_v1;
|
||||
gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2;
|
||||
|
@ -2292,7 +2297,8 @@ Ref<vm::Cell> ConfigInfo::lookup_library(td::ConstBitPtr root_hash) const {
|
|||
td::Result<Ref<vm::Tuple>> ConfigInfo::get_prev_blocks_info() const {
|
||||
// [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
|
||||
// [ last_mc_blocks:[BlockId...]
|
||||
// prev_key_block:BlockId ] : PrevBlocksInfo
|
||||
// prev_key_block:BlockId
|
||||
// last_mc_blocks_100[BlockId...] ] : PrevBlocksInfo
|
||||
auto block_id_to_tuple = [](const ton::BlockIdExt& block_id) -> vm::Ref<vm::Tuple> {
|
||||
td::RefInt256 shard = td::make_refint(block_id.id.shard);
|
||||
if (shard->sgn() < 0) {
|
||||
|
@ -2302,25 +2308,44 @@ td::Result<Ref<vm::Tuple>> ConfigInfo::get_prev_blocks_info() const {
|
|||
td::make_refint(block_id.id.seqno), td::bits_to_refint(block_id.root_hash.bits(), 256),
|
||||
td::bits_to_refint(block_id.file_hash.bits(), 256));
|
||||
};
|
||||
std::vector<vm::StackEntry> last_mc_blocks;
|
||||
std::vector<vm::StackEntry> tuple;
|
||||
|
||||
std::vector<vm::StackEntry> last_mc_blocks;
|
||||
last_mc_blocks.push_back(block_id_to_tuple(block_id));
|
||||
for (ton::BlockSeqno seqno = block_id.id.seqno; seqno > 0 && last_mc_blocks.size() < 16;) {
|
||||
--seqno;
|
||||
ton::BlockIdExt block_id;
|
||||
if (!get_old_mc_block_id(seqno, block_id)) {
|
||||
ton::BlockIdExt id;
|
||||
if (!get_old_mc_block_id(seqno, id)) {
|
||||
return td::Status::Error("cannot fetch old mc block");
|
||||
}
|
||||
last_mc_blocks.push_back(block_id_to_tuple(block_id));
|
||||
last_mc_blocks.push_back(block_id_to_tuple(id));
|
||||
}
|
||||
tuple.push_back(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks)));
|
||||
|
||||
ton::BlockIdExt last_key_block;
|
||||
ton::LogicalTime last_key_block_lt;
|
||||
if (!get_last_key_block(last_key_block, last_key_block_lt)) {
|
||||
return td::Status::Error("cannot fetch last key block");
|
||||
}
|
||||
return vm::make_tuple_ref(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks)),
|
||||
block_id_to_tuple(last_key_block));
|
||||
tuple.push_back(block_id_to_tuple(last_key_block));
|
||||
|
||||
if (get_global_version() >= 9) {
|
||||
std::vector<vm::StackEntry> last_mc_blocks_100;
|
||||
for (ton::BlockSeqno seqno = block_id.id.seqno / 100 * 100; last_mc_blocks_100.size() < 16;) {
|
||||
ton::BlockIdExt id;
|
||||
if (!get_old_mc_block_id(seqno, id)) {
|
||||
return td::Status::Error("cannot fetch old mc block");
|
||||
}
|
||||
last_mc_blocks_100.push_back(block_id_to_tuple(id));
|
||||
if (seqno < 100) {
|
||||
break;
|
||||
}
|
||||
seqno -= 100;
|
||||
}
|
||||
tuple.push_back(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks_100)));
|
||||
}
|
||||
|
||||
return td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
|
||||
}
|
||||
|
||||
td::optional<PrecompiledContractsConfig::Contract> PrecompiledContractsConfig::get_contract(
|
||||
|
|
|
@ -397,6 +397,7 @@ struct SizeLimitsConfig {
|
|||
td::uint32 max_acc_state_bits = (1 << 16) * 1023;
|
||||
td::uint32 max_acc_public_libraries = 256;
|
||||
td::uint32 defer_out_queue_size_limit = 256;
|
||||
td::uint32 max_msg_extra_currencies = 2;
|
||||
};
|
||||
|
||||
struct CatchainValidatorsConfig {
|
||||
|
|
|
@ -138,7 +138,6 @@ bool OutputQueueMerger::add_root(int src, Ref<vm::Cell> outmsg_root) {
|
|||
if (outmsg_root.is_null()) {
|
||||
return true;
|
||||
}
|
||||
//block::gen::HashmapAug{352, block::gen::t_EnqueuedMsg, block::gen::t_uint64}.print_ref(std::cerr, outmsg_root);
|
||||
auto kv = std::make_unique<MsgKeyValue>(src, std::move(outmsg_root));
|
||||
if (kv->replace_by_prefix(common_pfx.cbits(), common_pfx_len)) {
|
||||
heap.push_back(std::move(kv));
|
||||
|
|
|
@ -446,8 +446,10 @@ bool Account::unpack(Ref<vm::CellSlice> shard_account, ton::UnixTime now, bool s
|
|||
return false;
|
||||
}
|
||||
if (verbosity > 2) {
|
||||
shard_account->print_rec(std::cerr, 2);
|
||||
block::gen::t_ShardAccount.print(std::cerr, *shard_account);
|
||||
FLOG(INFO) {
|
||||
shard_account->print_rec(sb, 2);
|
||||
block::gen::t_ShardAccount.print(sb, shard_account);
|
||||
};
|
||||
}
|
||||
block::gen::ShardAccount::Record acc_info;
|
||||
if (!(block::tlb::t_ShardAccount.validate_csr(shard_account) && tlb::unpack_exact(shard_account.write(), acc_info))) {
|
||||
|
@ -737,9 +739,11 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig*
|
|||
return false;
|
||||
}
|
||||
if (verbosity > 2) {
|
||||
fprintf(stderr, "unpacking inbound message for a new transaction: ");
|
||||
block::gen::t_Message_Any.print_ref(std::cerr, in_msg);
|
||||
load_cell_slice(in_msg).print_rec(std::cerr);
|
||||
FLOG(INFO) {
|
||||
sb << "unpacking inbound message for a new transaction: ";
|
||||
block::gen::t_Message_Any.print_ref(sb, in_msg);
|
||||
load_cell_slice(in_msg).print_rec(sb);
|
||||
};
|
||||
}
|
||||
auto cs = vm::load_cell_slice(in_msg);
|
||||
int tag = block::gen::t_CommonMsgInfo.get_tag(cs);
|
||||
|
@ -1145,31 +1149,66 @@ td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
|
|||
namespace transaction {
|
||||
|
||||
/**
|
||||
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) to special_gas_limit * 2
|
||||
* from masterchain GasLimitsPrices config for the transaction.
|
||||
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) for the transaction
|
||||
*
|
||||
* In January 2024 a highload wallet of @wallet Telegram bot in mainnet was stuck because current gas limit (1M) is
|
||||
* not enough to clean up old queires, thus locking funds inside.
|
||||
* See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened.
|
||||
* Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu
|
||||
* It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-29).
|
||||
* It was proposed to validators to increase gas limit for this account to 70M for a limited amount
|
||||
* of time (until 2024-02-29).
|
||||
* It is activated by setting global version to 5 in ConfigParam 8.
|
||||
* This config change also activates new behavior for special accounts in masterchain.
|
||||
*
|
||||
* In August 2024 it was decided to unlock other old highload wallets that got into the same situation.
|
||||
* See https://t.me/tondev_news/129
|
||||
* It is activated by setting global version to 9.
|
||||
*
|
||||
* @param cfg The compute phase configuration.
|
||||
* @param now The Unix time of the transaction.
|
||||
* @param account The account of the transaction.
|
||||
*
|
||||
* @returns True if gas_limit override is required, false otherwise
|
||||
* @returns Overridden gas limit or empty td::optional
|
||||
*/
|
||||
static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) {
|
||||
if (!cfg.special_gas_full) {
|
||||
return false;
|
||||
static td::optional<td::uint64> override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now,
|
||||
const Account& account) {
|
||||
struct OverridenGasLimit {
|
||||
td::uint64 new_limit;
|
||||
int from_version;
|
||||
ton::UnixTime until;
|
||||
};
|
||||
static std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, OverridenGasLimit> accounts = []() {
|
||||
auto parse_addr = [](const char* s) -> std::pair<ton::WorkchainId, ton::StdSmcAddress> {
|
||||
auto r_addr = StdAddress::parse(td::Slice(s));
|
||||
r_addr.ensure();
|
||||
return {r_addr.ok().workchain, r_addr.ok().addr};
|
||||
};
|
||||
std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, OverridenGasLimit> accounts;
|
||||
|
||||
// Increase limit for EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu until 2024-02-29 00:00:00 UTC
|
||||
accounts[parse_addr("0:FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD")] = {
|
||||
.new_limit = 70'000'000, .from_version = 5, .until = 1709164800};
|
||||
|
||||
// Increase limit for multiple accounts (https://t.me/tondev_news/129) until 2025-03-01 00:00:00 UTC
|
||||
accounts[parse_addr("UQBeSl-dumOHieZ3DJkNKVkjeso7wZ0VpzR4LCbLGTQ8xr57")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQC3VcQ-43klww9UfimR58TBjBzk7GPupXQ3CNuthoNp-uTR")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQBhwBb8jvokGvfreHRRoeVxI237PrOJgyrsAhLA-4rBC_H5")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQCkoRp4OE-SFUoMEnYfL3vF43T3AzNfW8jyTC4yzk8cJqMS")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("UQBN5ICras79U8FYEm71ws34n-ZNIQ0LRNpckOUsIV3OebnC")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQBDanbCeUqI4_v-xrnAN0_I2wRvEIaLg1Qg2ZN5c6Zl1KOh")] = {
|
||||
.new_limit = 225'000'000, .from_version = 9, .until = 1740787200};
|
||||
return accounts;
|
||||
}();
|
||||
auto it = accounts.find({account.workchain, account.addr});
|
||||
if (it == accounts.end() || cfg.global_version < it->second.from_version || now >= it->second.until) {
|
||||
return {};
|
||||
}
|
||||
ton::UnixTime until = 1709164800; // 2024-02-29 00:00:00 UTC
|
||||
ton::WorkchainId wc = 0;
|
||||
const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD";
|
||||
return now < until && account.workchain == wc && account.addr.to_hex() == addr_hex;
|
||||
return it->second.new_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1183,10 +1222,12 @@ static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now,
|
|||
* @returns The amount of gas.
|
||||
*/
|
||||
td::uint64 Transaction::gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms) {
|
||||
if (override_gas_limit(cfg, now, account)) {
|
||||
if (auto new_limit = override_gas_limit(cfg, now, account)) {
|
||||
gas_limit_overridden = true;
|
||||
// Same as ComputePhaseConfig::gas_bought for, but with other gas_limit and max_gas_threshold
|
||||
auto gas_limit = cfg.mc_gas_prices.special_gas_limit * 2;
|
||||
auto gas_limit = new_limit.value();
|
||||
LOG(INFO) << "overridding gas limit for account " << account.workchain << ":" << account.addr.to_hex() << " to "
|
||||
<< gas_limit;
|
||||
auto max_gas_threshold =
|
||||
compute_max_gas_threshold(cfg.gas_price256, gas_limit, cfg.flat_gas_limit, cfg.flat_gas_price);
|
||||
if (nanograms.is_null() || sgn(nanograms) < 0) {
|
||||
|
@ -1336,7 +1377,8 @@ Ref<vm::Tuple> Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const {
|
|||
// See crypto/block/mc-config.cpp#2223 (get_prev_blocks_info)
|
||||
// [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
|
||||
// [ last_mc_blocks:[BlockId...]
|
||||
// prev_key_block:BlockId ] : PrevBlocksInfo
|
||||
// prev_key_block:BlockId
|
||||
// last_mc_blocks_100:[BlockId...] ] : PrevBlocksInfo
|
||||
// The only context where PrevBlocksInfo (13 parameter of c7) is null is inside emulator
|
||||
// where it need to be set via transaction_emulator_set_prev_blocks_info (see emulator/emulator-extern.cpp)
|
||||
// Inside validator, collator and liteserver checking external message contexts
|
||||
|
@ -1512,11 +1554,13 @@ bool Transaction::run_precompiled_contract(const ComputePhaseConfig& cfg, precom
|
|||
cp.actions = impl.get_c5();
|
||||
int out_act_num = output_actions_count(cp.actions);
|
||||
if (verbosity > 2) {
|
||||
std::cerr << "new smart contract data: ";
|
||||
bool can_be_special = true;
|
||||
load_cell_slice_special(cp.new_data, can_be_special).print_rec(std::cerr);
|
||||
std::cerr << "output actions: ";
|
||||
block::gen::OutList{out_act_num}.print_ref(std::cerr, cp.actions);
|
||||
FLOG(INFO) {
|
||||
sb << "new smart contract data: ";
|
||||
bool can_be_special = true;
|
||||
load_cell_slice_special(cp.new_data, can_be_special).print_rec(sb);
|
||||
sb << "output actions: ";
|
||||
block::gen::OutList{out_act_num}.print_ref(sb, cp.actions);
|
||||
};
|
||||
}
|
||||
}
|
||||
cp.mode = 0;
|
||||
|
@ -1581,7 +1625,6 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
if (in_msg_state.not_null()) {
|
||||
LOG(DEBUG) << "HASH(in_msg_state) = " << in_msg_state->get_hash().bits().to_hex(256)
|
||||
<< ", account_state_hash = " << account.state_hash.to_hex();
|
||||
// vm::load_cell_slice(in_msg_state).print_rec(std::cerr);
|
||||
} else {
|
||||
LOG(DEBUG) << "in_msg_state is null";
|
||||
}
|
||||
|
@ -1691,9 +1734,8 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
}
|
||||
}
|
||||
}
|
||||
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
|
||||
vm::VmState vm{new_code, cfg.global_version, 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_global_version(cfg.global_version);
|
||||
vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
|
||||
vm.set_chksig_always_succeed(cfg.ignore_chksig);
|
||||
vm.set_stop_on_accept_message(cfg.stop_on_accept_message);
|
||||
|
@ -1738,11 +1780,13 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
cp.actions = vm.get_committed_state().c5; // c5 -> action list
|
||||
int out_act_num = output_actions_count(cp.actions);
|
||||
if (verbosity > 2) {
|
||||
std::cerr << "new smart contract data: ";
|
||||
bool can_be_special = true;
|
||||
load_cell_slice_special(cp.new_data, can_be_special).print_rec(std::cerr);
|
||||
std::cerr << "output actions: ";
|
||||
block::gen::OutList{out_act_num}.print_ref(std::cerr, cp.actions);
|
||||
FLOG(INFO) {
|
||||
sb << "new smart contract data: ";
|
||||
bool can_be_special = true;
|
||||
load_cell_slice_special(cp.new_data, can_be_special).print_rec(sb);
|
||||
sb << "output actions: ";
|
||||
block::gen::OutList{out_act_num}.print_ref(sb, cp.actions);
|
||||
};
|
||||
}
|
||||
}
|
||||
cp.mode = 0;
|
||||
|
@ -1956,9 +2000,9 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
|
|||
ap.remaining_balance += ap.reserved_balance;
|
||||
CHECK(ap.remaining_balance.is_valid());
|
||||
if (ap.acc_delete_req) {
|
||||
CHECK(ap.remaining_balance.is_zero());
|
||||
CHECK(cfg.extra_currency_v2 ? ap.remaining_balance.grams->sgn() == 0 : ap.remaining_balance.is_zero());
|
||||
ap.acc_status_change = ActionPhase::acst_deleted;
|
||||
acc_status = Account::acc_deleted;
|
||||
acc_status = (ap.remaining_balance.is_zero() ? Account::acc_deleted : Account::acc_uninit);
|
||||
was_deleted = true;
|
||||
}
|
||||
ap.success = true;
|
||||
|
@ -2428,6 +2472,20 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
LOG(DEBUG) << "invalid destination address in a proposed outbound message";
|
||||
return check_skip_invalid(36); // invalid destination address
|
||||
}
|
||||
if (cfg.extra_currency_v2) {
|
||||
CurrencyCollection value;
|
||||
if (!value.unpack(info.value)) {
|
||||
LOG(DEBUG) << "invalid value:ExtraCurrencies in a proposed outbound message";
|
||||
return check_skip_invalid(37); // invalid value:CurrencyCollection
|
||||
}
|
||||
if (!CurrencyCollection::remove_zero_extra_currencies(value.extra, cfg.size_limits.max_msg_extra_currencies)) {
|
||||
LOG(DEBUG) << "invalid value:ExtraCurrencies in a proposed outbound message: too many currencies (max "
|
||||
<< cfg.size_limits.max_msg_extra_currencies << ")";
|
||||
// Dict should be valid, since it was checked in t_OutListNode.validate_ref, so error here means limit exceeded
|
||||
return check_skip_invalid(41); // invalid value:CurrencyCollection : too many extra currencies
|
||||
}
|
||||
info.value = value.pack();
|
||||
}
|
||||
|
||||
// fetch message pricing info
|
||||
const MsgPrices& msg_prices = cfg.fetch_msg_prices(to_mc || account.is_masterchain());
|
||||
|
@ -2480,7 +2538,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
};
|
||||
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) {
|
||||
if (!ext_msg && !cfg.extra_currency_v2) {
|
||||
add_used_storage(info.value->prefetch_ref(), 0);
|
||||
}
|
||||
auto collect_fine = [&] {
|
||||
|
@ -2551,11 +2609,19 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
|
||||
if (act_rec.mode & 0x80) {
|
||||
// attach all remaining balance to this message
|
||||
req = ap.remaining_balance;
|
||||
if (cfg.extra_currency_v2) {
|
||||
req.grams = ap.remaining_balance.grams;
|
||||
} else {
|
||||
req = ap.remaining_balance;
|
||||
}
|
||||
act_rec.mode &= ~1; // pay fees from attached value
|
||||
} else if (act_rec.mode & 0x40) {
|
||||
// attach all remaining balance of the inbound message (in addition to the original value)
|
||||
req += msg_balance_remaining;
|
||||
if (cfg.extra_currency_v2) {
|
||||
req.grams += msg_balance_remaining.grams;
|
||||
} else {
|
||||
req += msg_balance_remaining;
|
||||
}
|
||||
if (!(act_rec.mode & 1)) {
|
||||
req -= ap.action_fine;
|
||||
if (compute_phase) {
|
||||
|
@ -2595,6 +2661,11 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
return check_skip_invalid(37); // not enough grams
|
||||
}
|
||||
|
||||
if (cfg.extra_currency_v2 && !req.check_extra_currency_limit(cfg.size_limits.max_msg_extra_currencies)) {
|
||||
LOG(DEBUG) << "too many extra currencies in the message : max " << cfg.size_limits.max_msg_extra_currencies;
|
||||
return check_skip_invalid(41); // to many extra currencies
|
||||
}
|
||||
|
||||
Ref<vm::Cell> new_extra;
|
||||
|
||||
if (!block::sub_extra_currency(ap.remaining_balance.extra, req.extra, new_extra)) {
|
||||
|
@ -2636,7 +2707,11 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
|
||||
// clear msg_balance_remaining if it has been used
|
||||
if (act_rec.mode & 0xc0) {
|
||||
msg_balance_remaining.set_zero();
|
||||
if (cfg.extra_currency_v2) {
|
||||
msg_balance_remaining.grams = td::zero_refint();
|
||||
} else {
|
||||
msg_balance_remaining.set_zero();
|
||||
}
|
||||
}
|
||||
|
||||
// update balance
|
||||
|
@ -2688,14 +2763,18 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
}
|
||||
if (!block::gen::t_Message_Any.validate_ref(new_msg)) {
|
||||
LOG(ERROR) << "generated outbound message is not a valid (Message Any) according to automated check";
|
||||
block::gen::t_Message_Any.print_ref(std::cerr, new_msg);
|
||||
vm::load_cell_slice(new_msg).print_rec(std::cerr);
|
||||
FLOG(INFO) {
|
||||
block::gen::t_Message_Any.print_ref(sb, new_msg);
|
||||
vm::load_cell_slice(new_msg).print_rec(sb);
|
||||
};
|
||||
collect_fine();
|
||||
return -1;
|
||||
}
|
||||
if (verbosity > 2) {
|
||||
std::cerr << "converted outbound message: ";
|
||||
block::gen::t_Message_Any.print_ref(std::cerr, new_msg);
|
||||
FLOG(INFO) {
|
||||
sb << "converted outbound message: ";
|
||||
block::gen::t_Message_Any.print_ref(sb, new_msg);
|
||||
};
|
||||
}
|
||||
|
||||
ap.msgs_created++;
|
||||
|
@ -2706,8 +2785,13 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
ap.total_fwd_fees += fees_total;
|
||||
|
||||
if ((act_rec.mode & 0xa0) == 0xa0) {
|
||||
CHECK(ap.remaining_balance.is_zero());
|
||||
ap.acc_delete_req = ap.reserved_balance.is_zero();
|
||||
if (cfg.extra_currency_v2) {
|
||||
CHECK(ap.remaining_balance.grams->sgn() == 0);
|
||||
ap.acc_delete_req = ap.reserved_balance.grams->sgn() == 0;
|
||||
} else {
|
||||
CHECK(ap.remaining_balance.is_zero());
|
||||
ap.acc_delete_req = ap.reserved_balance.is_zero();
|
||||
}
|
||||
}
|
||||
|
||||
ap.tot_msg_bits += sstat.bits + new_msg_bits;
|
||||
|
@ -2760,22 +2844,25 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap,
|
|||
LOG(DEBUG) << "cannot reserve a negative amount: " << reserve.to_str();
|
||||
return -1;
|
||||
}
|
||||
if (reserve.grams > ap.remaining_balance.grams) {
|
||||
if (mode & 2) {
|
||||
reserve.grams = ap.remaining_balance.grams;
|
||||
if (mode & 2) {
|
||||
if (cfg.reserve_extra_enabled) {
|
||||
if (!reserve.clamp(ap.remaining_balance)) {
|
||||
LOG(DEBUG) << "failed to clamp reserve amount" << mode;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
LOG(DEBUG) << "cannot reserve " << reserve.grams << " nanograms : only " << ap.remaining_balance.grams
|
||||
<< " available";
|
||||
return 37; // not enough grams
|
||||
reserve.grams = std::min(reserve.grams, ap.remaining_balance.grams);
|
||||
}
|
||||
}
|
||||
if (reserve.grams > ap.remaining_balance.grams) {
|
||||
LOG(DEBUG) << "cannot reserve " << reserve.grams << " nanograms : only " << ap.remaining_balance.grams
|
||||
<< " available";
|
||||
return 37; // not enough grams
|
||||
}
|
||||
if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) {
|
||||
LOG(DEBUG) << "not enough extra currency to reserve: " << block::CurrencyCollection{0, reserve.extra}.to_str()
|
||||
<< " required, only " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str()
|
||||
<< " available";
|
||||
if (mode & 2) {
|
||||
// TODO: process (mode & 2) correctly by setting res_extra := inf (reserve.extra, ap.remaining_balance.extra)
|
||||
}
|
||||
return 38; // not enough (extra) funds
|
||||
}
|
||||
newc.grams = ap.remaining_balance.grams - reserve.grams;
|
||||
|
@ -2975,7 +3062,8 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
|
|||
bp.fwd_fees -= bp.fwd_fees_collected;
|
||||
total_fees += td::make_refint(bp.fwd_fees_collected);
|
||||
// serialize outbound message
|
||||
info.created_lt = end_lt++;
|
||||
info.created_lt = start_lt + 1 + out_msgs.size();
|
||||
end_lt++;
|
||||
info.created_at = now;
|
||||
vm::CellBuilder cb;
|
||||
CHECK(cb.store_long_bool(5, 4) // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
|
@ -3005,8 +3093,10 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
|
|||
}
|
||||
CHECK(cb.finalize_to(bp.out_msg));
|
||||
if (verbosity > 2) {
|
||||
LOG(INFO) << "generated bounced message: ";
|
||||
block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg);
|
||||
FLOG(INFO) {
|
||||
sb << "generated bounced message: ";
|
||||
block::gen::t_Message_Any.print_ref(sb, bp.out_msg);
|
||||
};
|
||||
}
|
||||
out_msgs.push_back(bp.out_msg);
|
||||
bp.ok = true;
|
||||
|
@ -3054,6 +3144,7 @@ bool Account::store_acc_status(vm::CellBuilder& cb, int acc_status) const {
|
|||
* Tries to update the storage statistics based on the old storage statistics and old account state without fully recomputing it.
|
||||
*
|
||||
* It succeeds if only root cell of AccountStorage is changed.
|
||||
* old_cs and new_cell are AccountStorage without extra currencies (if global_version >= 10).
|
||||
*
|
||||
* @param old_stat The old storage statistics.
|
||||
* @param old_cs The old AccountStorage.
|
||||
|
@ -3087,13 +3178,48 @@ static td::optional<vm::CellStorageStat> try_update_storage_stat(const vm::CellS
|
|||
return new_stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes extra currencies dict from AccountStorage.
|
||||
*
|
||||
* This is used for computing account storage stats.
|
||||
*
|
||||
* @param storage_cs AccountStorage as CellSlice.
|
||||
*
|
||||
* @returns AccountStorage without extra currencies as Cell.
|
||||
*/
|
||||
static td::Ref<vm::Cell> storage_without_extra_currencies(td::Ref<vm::CellSlice> storage_cs) {
|
||||
block::gen::AccountStorage::Record rec;
|
||||
if (!block::gen::csr_unpack(storage_cs, rec)) {
|
||||
LOG(ERROR) << "failed to unpack AccountStorage";
|
||||
return {};
|
||||
}
|
||||
if (rec.balance->size_refs() > 0) {
|
||||
block::gen::CurrencyCollection::Record balance;
|
||||
if (!block::gen::csr_unpack(rec.balance, balance)) {
|
||||
LOG(ERROR) << "failed to unpack AccountStorage";
|
||||
return {};
|
||||
}
|
||||
balance.other = vm::CellBuilder{}.store_zeroes(1).as_cellslice_ref();
|
||||
if (!block::gen::csr_pack(rec.balance, balance)) {
|
||||
LOG(ERROR) << "failed to pack AccountStorage";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
td::Ref<vm::Cell> cell;
|
||||
if (!block::gen::pack_cell(cell, rec)) {
|
||||
LOG(ERROR) << "failed to pack AccountStorage";
|
||||
return {};
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
namespace transaction {
|
||||
/**
|
||||
* Computes the new state of the account.
|
||||
*
|
||||
* @returns True if the state computation is successful, false otherwise.
|
||||
*/
|
||||
bool Transaction::compute_state() {
|
||||
bool Transaction::compute_state(const SerializeConfig& cfg) {
|
||||
if (new_total_state.not_null()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -3127,11 +3253,13 @@ bool Transaction::compute_state() {
|
|||
auto frozen_state = cb2.finalize();
|
||||
frozen_hash = frozen_state->get_hash().bits();
|
||||
if (verbosity >= 3 * 1) { // !!!DEBUG!!!
|
||||
std::cerr << "freezing state of smart contract: ";
|
||||
block::gen::t_StateInit.print_ref(std::cerr, frozen_state);
|
||||
CHECK(block::gen::t_StateInit.validate_ref(frozen_state));
|
||||
CHECK(block::tlb::t_StateInit.validate_ref(frozen_state));
|
||||
std::cerr << "with hash " << frozen_hash.to_hex() << std::endl;
|
||||
FLOG(INFO) {
|
||||
sb << "freezing state of smart contract: ";
|
||||
block::gen::t_StateInit.print_ref(sb, frozen_state);
|
||||
CHECK(block::gen::t_StateInit.validate_ref(frozen_state));
|
||||
CHECK(block::tlb::t_StateInit.validate_ref(frozen_state));
|
||||
sb << "with hash " << frozen_hash.to_hex();
|
||||
};
|
||||
}
|
||||
}
|
||||
new_code.clear();
|
||||
|
@ -3163,13 +3291,27 @@ bool Transaction::compute_state() {
|
|||
new_inner_state.clear();
|
||||
}
|
||||
vm::CellStorageStat& stats = new_storage_stat;
|
||||
auto new_stats = try_update_storage_stat(account.storage_stat, account.storage, storage);
|
||||
td::Ref<vm::CellSlice> old_storage_for_stat = account.storage;
|
||||
td::Ref<vm::Cell> new_storage_for_stat = storage;
|
||||
if (cfg.extra_currency_v2) {
|
||||
new_storage_for_stat = storage_without_extra_currencies(new_storage);
|
||||
if (new_storage_for_stat.is_null()) {
|
||||
return false;
|
||||
}
|
||||
if (old_storage_for_stat.not_null()) {
|
||||
old_storage_for_stat = vm::load_cell_slice_ref(storage_without_extra_currencies(old_storage_for_stat));
|
||||
if (old_storage_for_stat.is_null()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto new_stats = try_update_storage_stat(account.storage_stat, old_storage_for_stat, storage);
|
||||
if (new_stats) {
|
||||
stats = new_stats.unwrap();
|
||||
} else {
|
||||
TD_PERF_COUNTER(transaction_storage_stat_b);
|
||||
td::Timer timer;
|
||||
stats.add_used_storage(Ref<vm::Cell>(storage)).ensure();
|
||||
stats.add_used_storage(new_storage_for_stat).ensure();
|
||||
if (timer.elapsed() > 0.1) {
|
||||
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
|
||||
}
|
||||
|
@ -3189,8 +3331,10 @@ bool Transaction::compute_state() {
|
|||
CHECK(cb.append_data_cell_bool(std::move(storage)));
|
||||
new_total_state = cb.finalize();
|
||||
if (verbosity > 2) {
|
||||
std::cerr << "new account state: ";
|
||||
block::gen::t_Account.print_ref(std::cerr, new_total_state);
|
||||
FLOG(INFO) {
|
||||
sb << "new account state: ";
|
||||
block::gen::t_Account.print_ref(sb, new_total_state);
|
||||
};
|
||||
}
|
||||
CHECK(block::tlb::t_Account.validate_ref(new_total_state));
|
||||
return true;
|
||||
|
@ -3203,11 +3347,11 @@ bool Transaction::compute_state() {
|
|||
*
|
||||
* @returns True if the serialization is successful, False otherwise.
|
||||
*/
|
||||
bool Transaction::serialize() {
|
||||
bool Transaction::serialize(const SerializeConfig& cfg) {
|
||||
if (root.not_null()) {
|
||||
return true;
|
||||
}
|
||||
if (!compute_state()) {
|
||||
if (!compute_state(cfg)) {
|
||||
return false;
|
||||
}
|
||||
vm::Dictionary dict{15};
|
||||
|
@ -3282,22 +3426,28 @@ bool Transaction::serialize() {
|
|||
return false;
|
||||
}
|
||||
if (verbosity >= 3 * 1) {
|
||||
std::cerr << "new transaction: ";
|
||||
block::gen::t_Transaction.print_ref(std::cerr, root);
|
||||
vm::load_cell_slice(root).print_rec(std::cerr);
|
||||
FLOG(INFO) {
|
||||
sb << "new transaction: ";
|
||||
block::gen::t_Transaction.print_ref(sb, root);
|
||||
vm::load_cell_slice(root).print_rec(sb);
|
||||
};
|
||||
}
|
||||
|
||||
if (!block::gen::t_Transaction.validate_ref(4096, root)) {
|
||||
LOG(ERROR) << "newly-generated transaction failed to pass automated validation:";
|
||||
vm::load_cell_slice(root).print_rec(std::cerr);
|
||||
block::gen::t_Transaction.print_ref(std::cerr, root);
|
||||
FLOG(INFO) {
|
||||
vm::load_cell_slice(root).print_rec(sb);
|
||||
block::gen::t_Transaction.print_ref(sb, root);
|
||||
};
|
||||
root.clear();
|
||||
return false;
|
||||
}
|
||||
if (!block::tlb::t_Transaction.validate_ref(4096, root)) {
|
||||
LOG(ERROR) << "newly-generated transaction failed to pass hand-written validation:";
|
||||
vm::load_cell_slice(root).print_rec(std::cerr);
|
||||
block::gen::t_Transaction.print_ref(std::cerr, root);
|
||||
FLOG(INFO) {
|
||||
vm::load_cell_slice(root).print_rec(sb);
|
||||
block::gen::t_Transaction.print_ref(sb, root);
|
||||
};
|
||||
root.clear();
|
||||
return false;
|
||||
}
|
||||
|
@ -3667,6 +3817,7 @@ bool Account::libraries_changed() const {
|
|||
* @param rand_seed Pointer to the random seed. Generates a new seed if the value is `td::Bits256::zero()`.
|
||||
* @param compute_phase_cfg Pointer to store the compute phase configuration.
|
||||
* @param action_phase_cfg Pointer to store the action phase configuration.
|
||||
* @param serialize_cfg Pointer to store the serialize phase configuration.
|
||||
* @param masterchain_create_fee Pointer to store the masterchain create fee.
|
||||
* @param basechain_create_fee Pointer to store the basechain create fee.
|
||||
* @param wc The workchain ID.
|
||||
|
@ -3675,15 +3826,15 @@ bool Account::libraries_changed() const {
|
|||
td::Status FetchConfigParams::fetch_config_params(
|
||||
const block::ConfigInfo& 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) {
|
||||
ActionPhaseConfig* action_phase_cfg, SerializeConfig* serialize_cfg, td::RefInt256* masterchain_create_fee,
|
||||
td::RefInt256* basechain_create_fee, ton::WorkchainId wc, ton::UnixTime now) {
|
||||
auto prev_blocks_info = config.get_prev_blocks_info();
|
||||
if (prev_blocks_info.is_error()) {
|
||||
return prev_blocks_info.move_as_error_prefix(
|
||||
td::Status::Error(-668, "cannot fetch prev blocks info from masterchain configuration: "));
|
||||
}
|
||||
return fetch_config_params(config, prev_blocks_info.move_as_ok(), old_mparams, storage_prices, storage_phase_cfg,
|
||||
rand_seed, compute_phase_cfg, action_phase_cfg, masterchain_create_fee,
|
||||
rand_seed, compute_phase_cfg, action_phase_cfg, serialize_cfg, masterchain_create_fee,
|
||||
basechain_create_fee, wc, now);
|
||||
}
|
||||
|
||||
|
@ -3698,6 +3849,7 @@ td::Status FetchConfigParams::fetch_config_params(
|
|||
* @param rand_seed Pointer to the random seed. Generates a new seed if the value is `td::Bits256::zero()`.
|
||||
* @param compute_phase_cfg Pointer to store the compute phase configuration.
|
||||
* @param action_phase_cfg Pointer to store the action phase configuration.
|
||||
* @param serialize_cfg Pointer to store the serialize phase configuration.
|
||||
* @param masterchain_create_fee Pointer to store the masterchain create fee.
|
||||
* @param basechain_create_fee Pointer to store the basechain create fee.
|
||||
* @param wc The workchain ID.
|
||||
|
@ -3707,8 +3859,8 @@ td::Status FetchConfigParams::fetch_config_params(
|
|||
const block::Config& config, td::Ref<vm::Tuple> prev_blocks_info, 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) {
|
||||
SerializeConfig* serialize_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();
|
||||
|
@ -3778,7 +3930,12 @@ td::Status FetchConfigParams::fetch_config_params(
|
|||
action_phase_cfg->bounce_on_fail_enabled = config.get_global_version() >= 4;
|
||||
action_phase_cfg->message_skip_enabled = config.get_global_version() >= 8;
|
||||
action_phase_cfg->disable_custom_fess = config.get_global_version() >= 8;
|
||||
action_phase_cfg->reserve_extra_enabled = config.get_global_version() >= 9;
|
||||
action_phase_cfg->mc_blackhole_addr = config.get_burning_config().blackhole_addr;
|
||||
action_phase_cfg->extra_currency_v2 = config.get_global_version() >= 10;
|
||||
}
|
||||
{
|
||||
serialize_cfg->extra_currency_v2 = config.get_global_version() >= 10;
|
||||
}
|
||||
{
|
||||
// fetch block_grams_created
|
||||
|
|
|
@ -169,12 +169,18 @@ struct ActionPhaseConfig {
|
|||
bool bounce_on_fail_enabled{false};
|
||||
bool message_skip_enabled{false};
|
||||
bool disable_custom_fess{false};
|
||||
bool reserve_extra_enabled{false};
|
||||
bool extra_currency_v2{false};
|
||||
td::optional<td::Bits256> mc_blackhole_addr;
|
||||
const MsgPrices& fetch_msg_prices(bool is_masterchain) const {
|
||||
return is_masterchain ? fwd_mc : fwd_std;
|
||||
}
|
||||
};
|
||||
|
||||
struct SerializeConfig {
|
||||
bool extra_currency_v2{false};
|
||||
};
|
||||
|
||||
struct CreditPhase {
|
||||
td::RefInt256 due_fees_collected;
|
||||
block::CurrencyCollection credit;
|
||||
|
@ -388,8 +394,8 @@ struct Transaction {
|
|||
bool prepare_action_phase(const ActionPhaseConfig& cfg);
|
||||
td::Status check_state_limits(const SizeLimitsConfig& size_limits, bool update_storage_stat = true);
|
||||
bool prepare_bounce_phase(const ActionPhaseConfig& cfg);
|
||||
bool compute_state();
|
||||
bool serialize();
|
||||
bool compute_state(const SerializeConfig& cfg);
|
||||
bool serialize(const SerializeConfig& cfg);
|
||||
td::uint64 gas_used() const {
|
||||
return compute_phase ? compute_phase->gas_used : 0;
|
||||
}
|
||||
|
@ -427,14 +433,14 @@ struct FetchConfigParams {
|
|||
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);
|
||||
SerializeConfig* serialize_cfg, td::RefInt256* masterchain_create_fee,
|
||||
td::RefInt256* basechain_create_fee, ton::WorkchainId wc, ton::UnixTime now);
|
||||
static td::Status fetch_config_params(const block::Config& config, Ref<vm::Tuple> prev_blocks_info,
|
||||
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);
|
||||
SerializeConfig* serialize_cfg, td::RefInt256* masterchain_create_fee,
|
||||
td::RefInt256* basechain_create_fee, ton::WorkchainId wc, ton::UnixTime now);
|
||||
};
|
||||
|
||||
} // namespace block
|
||||
|
|
|
@ -1312,6 +1312,7 @@ x{F832} @Defop CONFIGPARAM
|
|||
x{F833} @Defop CONFIGOPTPARAM
|
||||
x{F83400} @Defop PREVMCBLOCKS
|
||||
x{F83401} @Defop PREVKEYBLOCK
|
||||
x{F83402} @Defop PREVMCBLOCKS_100
|
||||
x{F835} @Defop GLOBALID
|
||||
x{F836} @Defop GETGASFEE
|
||||
x{F837} @Defop GETSTORAGEFEE
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Standard library for Tolk (LGPL licence).
|
||||
// It contains common functions that are available out of the box, the user doesn't have to import anything.
|
||||
// More specific functions are required to be imported explicitly, like "@stdlib/tvm-dicts".
|
||||
tolk 0.6
|
||||
tolk 0.9
|
||||
|
||||
/**
|
||||
Tuple manipulation primitives.
|
||||
|
@ -17,27 +17,36 @@ fun createEmptyTuple(): tuple
|
|||
/// Appends a value to tuple, resulting in `Tuple t' = (x1, ..., xn, value)`.
|
||||
/// If its size exceeds 255, throws a type check exception.
|
||||
@pure
|
||||
fun tuplePush<X>(mutate self: tuple, value: X): void
|
||||
fun tuplePush<T>(mutate self: tuple, value: T): void
|
||||
asm "TPUSH";
|
||||
|
||||
/// Returns the first element of a non-empty tuple.
|
||||
/// `t.0` is actually the same as `t.tupleFirst()`
|
||||
@pure
|
||||
fun tupleFirst<X>(t: tuple): X
|
||||
fun tupleFirst<T>(self: tuple): T
|
||||
asm "FIRST";
|
||||
|
||||
/// Returns the [`index`]-th element of a tuple.
|
||||
/// `t.i` is actually the same as `t.tupleAt(i)`
|
||||
@pure
|
||||
fun tupleAt<X>(t: tuple, index: int): X
|
||||
fun tupleAt<T>(self: tuple, index: int): T
|
||||
builtin;
|
||||
|
||||
/// Sets the [`index`]-th element of a tuple to a specified value
|
||||
/// (element with this index must already exist, a new element isn't created).
|
||||
/// `t.i = value` is actually the same as `t.tupleSetAt(value, i)`
|
||||
@pure
|
||||
fun tupleSetAt<T>(mutate self: tuple, value: T, index: int): void
|
||||
builtin;
|
||||
|
||||
/// Returns the size of a tuple (elements count in it).
|
||||
@pure
|
||||
fun tupleSize(t: tuple): int
|
||||
fun tupleSize(self: tuple): int
|
||||
asm "TLEN";
|
||||
|
||||
/// Returns the last element of a non-empty tuple.
|
||||
@pure
|
||||
fun tupleLast(t: tuple): int
|
||||
fun tupleLast<T>(self: tuple): T
|
||||
asm "LAST";
|
||||
|
||||
|
||||
|
@ -130,7 +139,7 @@ fun getMyOriginalBalance(): int
|
|||
/// `int` — balance in nanotoncoins;
|
||||
/// `cell` — a dictionary with 32-bit keys representing the balance of "extra currencies".
|
||||
@pure
|
||||
fun getMyOriginalBalanceWithExtraCurrencies(): [int, cell]
|
||||
fun getMyOriginalBalanceWithExtraCurrencies(): [int, cell?]
|
||||
asm "BALANCE";
|
||||
|
||||
/// Returns the logical time of the current transaction.
|
||||
|
@ -145,7 +154,7 @@ fun getCurrentBlockLogicalTime(): int
|
|||
|
||||
/// Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value.
|
||||
@pure
|
||||
fun getBlockchainConfigParam(x: int): cell
|
||||
fun getBlockchainConfigParam(x: int): cell?
|
||||
asm "CONFIGOPTPARAM";
|
||||
|
||||
/// Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later.
|
||||
|
@ -205,7 +214,7 @@ fun stringHash(s: slice): int
|
|||
/// That is, if [hash] is computed as the hash of some data, these data are hashed twice,
|
||||
/// the second hashing occurring inside `CHKSIGNS`.
|
||||
@pure
|
||||
fun isSignatureValid(hash: int, signature: slice, publicKey: int): int
|
||||
fun isSignatureValid(hash: int, signature: slice, publicKey: int): bool
|
||||
asm "CHKSIGNU";
|
||||
|
||||
/// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `publicKey`,
|
||||
|
@ -214,7 +223,7 @@ fun isSignatureValid(hash: int, signature: slice, publicKey: int): int
|
|||
/// The verification of Ed25519 signatures is the standard one,
|
||||
/// with sha256 used to reduce [data] to the 256-bit number that is actually signed.
|
||||
@pure
|
||||
fun isSliceSignatureValid(data: slice, signature: slice, publicKey: int): int
|
||||
fun isSliceSignatureValid(data: slice, signature: slice, publicKey: int): bool
|
||||
asm "CHKSIGNS";
|
||||
|
||||
/// Generates a new pseudo-random unsigned 256-bit integer x.
|
||||
|
@ -259,14 +268,14 @@ fun randomizeByLogicalTime(): void
|
|||
/// otherwise the computation is aborted before visiting the `(maxCells + 1)`-st cell and
|
||||
/// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`.
|
||||
@pure
|
||||
fun calculateCellSize(c: cell, maxCells: int): (int, int, int, int)
|
||||
fun calculateCellSize(c: cell, maxCells: int): (int, int, int, bool)
|
||||
asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
|
||||
/// Similar to [calculateCellSize], but accepting a `slice` [s] instead of a `cell`.
|
||||
/// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself;
|
||||
/// however, the data bits and the cell references of [s] are accounted for in `y` and `z`.
|
||||
@pure
|
||||
fun calculateSliceSize(s: slice, maxCells: int): (int, int, int, int)
|
||||
fun calculateSliceSize(s: slice, maxCells: int): (int, int, int, bool)
|
||||
asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
|
||||
/// A non-quiet version of [calculateCellSize] that throws a cell overflow exception (`8`) on failure.
|
||||
|
@ -282,7 +291,7 @@ fun calculateSliceSizeStrict(s: slice, maxCells: int): (int, int, int)
|
|||
/// otherwise the returned value is one plus the maximum of depths of cells referred to from [c].
|
||||
/// If [c] is a `null` instead of a cell, returns zero.
|
||||
@pure
|
||||
fun getCellDepth(c: cell): int
|
||||
fun getCellDepth(c: cell?): int
|
||||
asm "CDEPTH";
|
||||
|
||||
/// Returns the depth of `slice` [s].
|
||||
|
@ -306,11 +315,11 @@ fun getBuilderDepth(b: builder): int
|
|||
*/
|
||||
|
||||
/// Dump a variable [x] to the debug log.
|
||||
fun debugPrint<X>(x: X): void
|
||||
fun debugPrint<T>(x: T): void
|
||||
builtin;
|
||||
|
||||
/// Dump a string [x] to the debug log.
|
||||
fun debugPrintString<X>(x: X): void
|
||||
fun debugPrintString<T>(x: T): void
|
||||
builtin;
|
||||
|
||||
/// Dumps the stack (at most the top 255 values) and shows the total stack depth.
|
||||
|
@ -382,7 +391,7 @@ fun loadCoins(mutate self: slice): int
|
|||
|
||||
/// Loads bool (-1 or 0) from a slice
|
||||
@pure
|
||||
fun loadBool(mutate self: slice): int
|
||||
fun loadBool(mutate self: slice): bool
|
||||
asm( -> 1 0) "1 LDI";
|
||||
|
||||
/// Shifts a slice pointer to [len] bits forward, mutating the slice.
|
||||
|
@ -408,12 +417,12 @@ fun getLastBits(self: slice, len: int): slice
|
|||
/// Loads a dictionary (TL HashMapE structure, represented as TVM cell) from a slice.
|
||||
/// Returns `null` if `nothing` constructor is used.
|
||||
@pure
|
||||
fun loadDict(mutate self: slice): cell
|
||||
fun loadDict(mutate self: slice): cell?
|
||||
asm( -> 1 0) "LDDICT";
|
||||
|
||||
/// Preloads a dictionary (cell) from a slice.
|
||||
@pure
|
||||
fun preloadDict(self: slice): cell
|
||||
fun preloadDict(self: slice): cell?
|
||||
asm "PLDDICT";
|
||||
|
||||
/// Loads a dictionary as [loadDict], but returns only the remainder of the slice.
|
||||
|
@ -424,12 +433,12 @@ fun skipDict(mutate self: slice): self
|
|||
/// Loads (Maybe ^Cell) from a slice.
|
||||
/// In other words, loads 1 bit: if it's true, loads the first ref, otherwise returns `null`.
|
||||
@pure
|
||||
fun loadMaybeRef(mutate self: slice): cell
|
||||
fun loadMaybeRef(mutate self: slice): cell?
|
||||
asm( -> 1 0) "LDOPTREF";
|
||||
|
||||
/// Preloads (Maybe ^Cell) from a slice.
|
||||
@pure
|
||||
fun preloadMaybeRef(self: slice): cell
|
||||
fun preloadMaybeRef(self: slice): cell?
|
||||
asm "PLDOPTREF";
|
||||
|
||||
/// Loads (Maybe ^Cell), but returns only the remainder of the slice.
|
||||
|
@ -482,19 +491,19 @@ fun storeCoins(mutate self: builder, x: int): self
|
|||
/// Stores bool (-1 or 0) into a builder.
|
||||
/// Attention: true value is `-1`, not 1! If you pass `1` here, TVM will throw an exception.
|
||||
@pure
|
||||
fun storeBool(mutate self: builder, x: int): self
|
||||
fun storeBool(mutate self: builder, x: bool): self
|
||||
asm(x self) "1 STI";
|
||||
|
||||
/// Stores dictionary (represented by TVM `cell` or `null`) into a builder.
|
||||
/// In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise.
|
||||
@pure
|
||||
fun storeDict(mutate self: builder, c: cell): self
|
||||
fun storeDict(mutate self: builder, c: cell?): self
|
||||
asm(c self) "STDICT";
|
||||
|
||||
/// Stores (Maybe ^Cell) into a builder.
|
||||
/// In other words, if cell is `null`, store '0' bit; otherwise, store '1' and a ref to [c].
|
||||
@pure
|
||||
fun storeMaybeRef(mutate self: builder, c: cell): self
|
||||
fun storeMaybeRef(mutate self: builder, c: cell?): self
|
||||
asm(c self) "STOPTREF";
|
||||
|
||||
/// Concatenates two builders.
|
||||
|
@ -529,22 +538,22 @@ fun getRemainingBitsAndRefsCount(self: slice): (int, int)
|
|||
|
||||
/// Checks whether a slice is empty (i.e., contains no bits of data and no cell references).
|
||||
@pure
|
||||
fun isEndOfSlice(self: slice): int
|
||||
fun isEndOfSlice(self: slice): bool
|
||||
asm "SEMPTY";
|
||||
|
||||
/// Checks whether a slice has no bits of data.
|
||||
@pure
|
||||
fun isEndOfSliceBits(self: slice): int
|
||||
fun isEndOfSliceBits(self: slice): bool
|
||||
asm "SDEMPTY";
|
||||
|
||||
/// Checks whether a slice has no references.
|
||||
@pure
|
||||
fun isEndOfSliceRefs(self: slice): int
|
||||
fun isEndOfSliceRefs(self: slice): bool
|
||||
asm "SREMPTY";
|
||||
|
||||
/// Checks whether data parts of two slices coinside.
|
||||
@pure
|
||||
fun isSliceBitsEqual(self: slice, b: slice): int
|
||||
fun isSliceBitsEqual(self: slice, b: slice): bool
|
||||
asm "SDEQ";
|
||||
|
||||
/// Returns the number of cell references already stored in a builder.
|
||||
|
@ -621,10 +630,10 @@ fun parseStandardAddress(s: slice): (int, int)
|
|||
fun createAddressNone(): slice
|
||||
asm "b{00} PUSHSLICE";
|
||||
|
||||
/// Returns if a slice pointer contains an empty address (`-1` for true, `0` for false, as always).
|
||||
/// Returns if a slice pointer contains an empty address.
|
||||
/// In other words, a slice starts with two `0` bits (TL addr_none$00).
|
||||
@pure
|
||||
fun addressIsNone(s: slice): int
|
||||
fun addressIsNone(s: slice): bool
|
||||
asm "2 PLDU" "0 EQINT";
|
||||
|
||||
|
||||
|
@ -652,7 +661,7 @@ fun reserveToncoinsOnBalance(nanoTonCoins: int, reserveMode: int): void
|
|||
|
||||
/// Similar to [reserveToncoinsOnBalance], but also accepts a dictionary extraAmount (represented by a cell or null)
|
||||
/// with extra currencies. In this way currencies other than Toncoin can be reserved.
|
||||
fun reserveExtraCurrenciesOnBalance(nanoTonCoins: int, extraAmount: cell, reserveMode: int): void
|
||||
fun reserveExtraCurrenciesOnBalance(nanoTonCoins: int, extraAmount: cell?, reserveMode: int): void
|
||||
asm "RAWRESERVEX";
|
||||
|
||||
|
||||
|
@ -677,8 +686,8 @@ fun loadMessageFlags(mutate self: slice): int
|
|||
/// Having msgFlags (4 bits), check that a message is bounced.
|
||||
/// Effectively, it's `msgFlags & 1` (the lowest bit present).
|
||||
@pure
|
||||
fun isMessageBounced(msgFlags: int): int
|
||||
asm "1 PUSHINT" "AND";
|
||||
fun isMessageBounced(msgFlags: int): bool
|
||||
asm "2 PUSHINT" "MODR";
|
||||
|
||||
/// Skip 0xFFFFFFFF prefix (when a message is bounced).
|
||||
@pure
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// A part of standard library for Tolk
|
||||
tolk 0.6
|
||||
tolk 0.9
|
||||
|
||||
/**
|
||||
Gas and payment related primitives.
|
||||
|
@ -61,3 +61,9 @@ fun calculateOriginalMessageFee(workchain: int, incomingFwdFee: int): int
|
|||
/// If it has no debt, `0` is returned.
|
||||
fun getMyStorageDuePayment(): int
|
||||
asm "DUEPAYMENT";
|
||||
|
||||
/// Returns the amount of nanotoncoins charged for storage.
|
||||
/// (during storage phase preceeding to current computation phase)
|
||||
@pure
|
||||
fun getMyStoragePaidPayment(): int
|
||||
asm "STORAGEFEES";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// A part of standard library for Tolk
|
||||
tolk 0.6
|
||||
tolk 0.9
|
||||
|
||||
/**
|
||||
Lisp-style lists are nested 2-elements tuples: `(1, (2, (3, null)))` represents list `[1, 2, 3]`.
|
||||
|
@ -14,17 +14,18 @@ fun createEmptyList(): tuple
|
|||
/// Adds an element to the beginning of lisp-style list.
|
||||
/// Note, that it does not mutate the list: instead, it returns a new one (it's a lisp pattern).
|
||||
@pure
|
||||
fun listPrepend<X>(head: X, tail: tuple): tuple
|
||||
fun listPrepend<X>(head: X, tail: tuple?): tuple
|
||||
asm "CONS";
|
||||
|
||||
/// Extracts the head and the tail of lisp-style list.
|
||||
@pure
|
||||
fun listSplit<X>(list: tuple): (X, tuple)
|
||||
fun listSplit<X>(list: tuple): (X, tuple?)
|
||||
asm "UNCONS";
|
||||
|
||||
/// Extracts the tail and the head of lisp-style list.
|
||||
/// After extracting the last element, tuple is assigned to null.
|
||||
@pure
|
||||
fun listNext<X>(mutate self: tuple): X
|
||||
fun listNext<X>(mutate self: tuple?): X
|
||||
asm( -> 1 0) "UNCONS";
|
||||
|
||||
/// Returns the head of lisp-style list.
|
||||
|
@ -34,5 +35,5 @@ fun listGetHead<X>(list: tuple): X
|
|||
|
||||
/// Returns the tail of lisp-style list.
|
||||
@pure
|
||||
fun listGetTail(list: tuple): tuple
|
||||
fun listGetTail(list: tuple): tuple?
|
||||
asm "CDR";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// A part of standard library for Tolk
|
||||
tolk 0.6
|
||||
tolk 0.9
|
||||
|
||||
/**
|
||||
Dictionaries are represented as `cell` data type (cells can store anything, dicts in particular).
|
||||
|
@ -9,288 +9,289 @@ tolk 0.6
|
|||
- uDict* - dicts with unsigned integer keys
|
||||
- sDict* - dicts with arbitrary slice keys
|
||||
When accessing a dict element, you should not only provide a key, but provide keyLen,
|
||||
since for optimization, for optimization, key length is not stored in the dictionary itself.
|
||||
since for optimization, key length is not stored in the dictionary itself.
|
||||
Every dictionary object (`self` parameter) can be null. TVM NULL is essentially "empty dictionary".
|
||||
*/
|
||||
|
||||
/// Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL
|
||||
@pure
|
||||
fun createEmptyDict(): cell
|
||||
fun createEmptyDict(): cell?
|
||||
asm "NEWDICT";
|
||||
|
||||
/// Checks whether a dictionary is empty.
|
||||
@pure
|
||||
fun dictIsEmpty(self: cell): int
|
||||
fun dictIsEmpty(self: cell?): bool
|
||||
asm "DICTEMPTY";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGet(self: cell, keyLen: int, key: int): (slice, int)
|
||||
fun iDictGet(self: cell?, keyLen: int, key: int): (slice?, bool)
|
||||
asm(key self keyLen) "DICTIGET" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun uDictGet(self: cell, keyLen: int, key: int): (slice, int)
|
||||
fun uDictGet(self: cell?, keyLen: int, key: int): (slice?, bool)
|
||||
asm(key self keyLen) "DICTUGET" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun sDictGet(self: cell, keyLen: int, key: slice): (slice, int)
|
||||
fun sDictGet(self: cell?, keyLen: int, key: slice): (slice?, bool)
|
||||
asm(key self keyLen) "DICTGET" "NULLSWAPIFNOT";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSet(mutate self: cell, keyLen: int, key: int, value: slice): void
|
||||
fun iDictSet(mutate self: cell?, keyLen: int, key: int, value: slice): void
|
||||
asm(value key self keyLen) "DICTISET";
|
||||
|
||||
@pure
|
||||
fun uDictSet(mutate self: cell, keyLen: int, key: int, value: slice): void
|
||||
fun uDictSet(mutate self: cell?, keyLen: int, key: int, value: slice): void
|
||||
asm(value key self keyLen) "DICTUSET";
|
||||
|
||||
@pure
|
||||
fun sDictSet(mutate self: cell, keyLen: int, key: slice, value: slice): void
|
||||
fun sDictSet(mutate self: cell?, keyLen: int, key: slice, value: slice): void
|
||||
asm(value key self keyLen) "DICTSET";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetRef(mutate self: cell, keyLen: int, key: int, value: cell): void
|
||||
fun iDictSetRef(mutate self: cell?, keyLen: int, key: int, value: cell): void
|
||||
asm(value key self keyLen) "DICTISETREF";
|
||||
|
||||
@pure
|
||||
fun uDictSetRef(mutate self: cell, keyLen: int, key: int, value: cell): void
|
||||
fun uDictSetRef(mutate self: cell?, keyLen: int, key: int, value: cell): void
|
||||
asm(value key self keyLen) "DICTUSETREF";
|
||||
|
||||
@pure
|
||||
fun sDictSetRef(mutate self: cell, keyLen: int, key: slice, value: cell): void
|
||||
fun sDictSetRef(mutate self: cell?, keyLen: int, key: slice, value: cell): void
|
||||
asm(value key self keyLen) "DICTSETREF";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetIfNotExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
||||
fun iDictSetIfNotExists(mutate self: cell?, keyLen: int, key: int, value: slice): bool
|
||||
asm(value key self keyLen) "DICTIADD";
|
||||
|
||||
@pure
|
||||
fun uDictSetIfNotExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
||||
fun uDictSetIfNotExists(mutate self: cell?, keyLen: int, key: int, value: slice): bool
|
||||
asm(value key self keyLen) "DICTUADD";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetIfExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
||||
fun iDictSetIfExists(mutate self: cell?, keyLen: int, key: int, value: slice): bool
|
||||
asm(value key self keyLen) "DICTIREPLACE";
|
||||
|
||||
@pure
|
||||
fun uDictSetIfExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
||||
fun uDictSetIfExists(mutate self: cell?, keyLen: int, key: int, value: slice): bool
|
||||
asm(value key self keyLen) "DICTUREPLACE";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGetRef(self: cell, keyLen: int, key: int): (cell, int)
|
||||
fun iDictGetRef(self: cell?, keyLen: int, key: int): (cell?, bool)
|
||||
asm(key self keyLen) "DICTIGETREF" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun uDictGetRef(self: cell, keyLen: int, key: int): (cell, int)
|
||||
fun uDictGetRef(self: cell?, keyLen: int, key: int): (cell?, bool)
|
||||
asm(key self keyLen) "DICTUGETREF" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun sDictGetRef(self: cell, keyLen: int, key: slice): (cell, int)
|
||||
fun sDictGetRef(self: cell?, keyLen: int, key: slice): (cell?, bool)
|
||||
asm(key self keyLen) "DICTGETREF" "NULLSWAPIFNOT";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGetRefOrNull(self: cell, keyLen: int, key: int): cell
|
||||
fun iDictGetRefOrNull(self: cell?, keyLen: int, key: int): cell?
|
||||
asm(key self keyLen) "DICTIGETOPTREF";
|
||||
|
||||
@pure
|
||||
fun uDictGetRefOrNull(self: cell, keyLen: int, key: int): cell
|
||||
fun uDictGetRefOrNull(self: cell?, keyLen: int, key: int): cell?
|
||||
asm(key self keyLen) "DICTUGETOPTREF";
|
||||
|
||||
@pure
|
||||
fun sDictGetRefOrNull(self: cell, keyLen: int, key: slice): cell
|
||||
fun sDictGetRefOrNull(self: cell?, keyLen: int, key: slice): cell?
|
||||
asm(key self keyLen) "DICTGETOPTREF";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictDelete(mutate self: cell, keyLen: int, key: int): int
|
||||
fun iDictDelete(mutate self: cell?, keyLen: int, key: int): bool
|
||||
asm(key self keyLen) "DICTIDEL";
|
||||
|
||||
@pure
|
||||
fun uDictDelete(mutate self: cell, keyLen: int, key: int): int
|
||||
fun uDictDelete(mutate self: cell?, keyLen: int, key: int): bool
|
||||
asm(key self keyLen) "DICTUDEL";
|
||||
|
||||
@pure
|
||||
fun sDictDelete(mutate self: cell, keyLen: int, key: slice): int
|
||||
fun sDictDelete(mutate self: cell?, keyLen: int, key: slice): bool
|
||||
asm(key self keyLen) "DICTDEL";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetAndGet(mutate self: cell, keyLen: int, key: int, value: slice): (slice, int)
|
||||
fun iDictSetAndGet(mutate self: cell?, keyLen: int, key: int, value: slice): (slice?, bool)
|
||||
asm(value key self keyLen) "DICTISETGET" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun uDictSetAndGet(mutate self: cell, keyLen: int, key: int, value: slice): (slice, int)
|
||||
fun uDictSetAndGet(mutate self: cell?, keyLen: int, key: int, value: slice): (slice?, bool)
|
||||
asm(value key self keyLen) "DICTUSETGET" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun sDictSetAndGet(mutate self: cell, keyLen: int, key: slice, value: slice): (slice, int)
|
||||
fun sDictSetAndGet(mutate self: cell?, keyLen: int, key: slice, value: slice): (slice?, bool)
|
||||
asm(value key self keyLen) "DICTSETGET" "NULLSWAPIFNOT";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetAndGetRefOrNull(mutate self: cell, keyLen: int, key: int, value: cell): cell
|
||||
fun iDictSetAndGetRefOrNull(mutate self: cell?, keyLen: int, key: int, value: cell): cell?
|
||||
asm(value key self keyLen) "DICTISETGETOPTREF";
|
||||
|
||||
@pure
|
||||
fun uDictSetAndGetRefOrNull(mutate self: cell, keyLen: int, key: int, value: cell): cell
|
||||
fun uDictSetAndGetRefOrNull(mutate self: cell?, keyLen: int, key: int, value: cell): cell?
|
||||
asm(value key self keyLen) "DICTUSETGETOPTREF";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictDeleteAndGet(mutate self: cell, keyLen: int, key: int): (slice, int)
|
||||
fun iDictDeleteAndGet(mutate self: cell?, keyLen: int, key: int): (slice?, bool)
|
||||
asm(key self keyLen) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun uDictDeleteAndGet(mutate self: cell, keyLen: int, key: int): (slice, int)
|
||||
fun uDictDeleteAndGet(mutate self: cell?, keyLen: int, key: int): (slice?, bool)
|
||||
asm(key self keyLen) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||
|
||||
@pure
|
||||
fun sDictDeleteAndGet(mutate self: cell, keyLen: int, key: slice): (slice, int)
|
||||
fun sDictDeleteAndGet(mutate self: cell?, keyLen: int, key: slice): (slice?, bool)
|
||||
asm(key self keyLen) "DICTDELGET" "NULLSWAPIFNOT";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetBuilder(mutate self: cell, keyLen: int, key: int, value: builder): void
|
||||
fun iDictSetBuilder(mutate self: cell?, keyLen: int, key: int, value: builder): void
|
||||
asm(value key self keyLen) "DICTISETB";
|
||||
|
||||
@pure
|
||||
fun uDictSetBuilder(mutate self: cell, keyLen: int, key: int, value: builder): void
|
||||
fun uDictSetBuilder(mutate self: cell?, keyLen: int, key: int, value: builder): void
|
||||
asm(value key self keyLen) "DICTUSETB";
|
||||
|
||||
@pure
|
||||
fun sDictSetBuilder(mutate self: cell, keyLen: int, key: slice, value: builder): void
|
||||
fun sDictSetBuilder(mutate self: cell?, keyLen: int, key: slice, value: builder): void
|
||||
asm(value key self keyLen) "DICTSETB";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictSetBuilderIfNotExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
||||
fun iDictSetBuilderIfNotExists(mutate self: cell?, keyLen: int, key: int, value: builder): bool
|
||||
asm(value key self keyLen) "DICTIADDB";
|
||||
|
||||
@pure
|
||||
fun uDictSetBuilderIfNotExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
||||
fun uDictSetBuilderIfNotExists(mutate self: cell?, keyLen: int, key: int, value: builder): bool
|
||||
asm(value key self keyLen) "DICTUADDB";
|
||||
|
||||
@pure
|
||||
fun iDictSetBuilderIfExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
||||
fun iDictSetBuilderIfExists(mutate self: cell?, keyLen: int, key: int, value: builder): bool
|
||||
asm(value key self keyLen) "DICTIREPLACEB";
|
||||
|
||||
@pure
|
||||
fun uDictSetBuilderIfExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
||||
fun uDictSetBuilderIfExists(mutate self: cell?, keyLen: int, key: int, value: builder): bool
|
||||
asm(value key self keyLen) "DICTUREPLACEB";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
||||
fun iDictDeleteFirstAndGet(mutate self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
||||
fun uDictDeleteFirstAndGet(mutate self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun sDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (slice, slice, int)
|
||||
fun sDictDeleteFirstAndGet(mutate self: cell?, keyLen: int): (slice?, slice?, bool)
|
||||
asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictDeleteLastAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
||||
fun iDictDeleteLastAndGet(mutate self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictDeleteLastAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
||||
fun uDictDeleteLastAndGet(mutate self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun sDictDeleteLastAndGet(mutate self: cell, keyLen: int): (slice, slice, int)
|
||||
fun sDictDeleteLastAndGet(mutate self: cell?, keyLen: int): (slice?, slice?, bool)
|
||||
asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGetFirst(self: cell, keyLen: int): (int, slice, int)
|
||||
fun iDictGetFirst(self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetFirst(self: cell, keyLen: int): (int, slice, int)
|
||||
fun uDictGetFirst(self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun sDictGetFirst(self: cell, keyLen: int): (slice, slice, int)
|
||||
fun sDictGetFirst(self: cell?, keyLen: int): (slice?, slice?, bool)
|
||||
asm (-> 1 0 2) "DICTMIN" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun iDictGetFirstAsRef(self: cell, keyLen: int): (int, cell, int)
|
||||
fun iDictGetFirstAsRef(self: cell?, keyLen: int): (int?, cell?, bool)
|
||||
asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetFirstAsRef(self: cell, keyLen: int): (int, cell, int)
|
||||
fun uDictGetFirstAsRef(self: cell?, keyLen: int): (int?, cell?, bool)
|
||||
asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun sDictGetFirstAsRef(self: cell, keyLen: int): (slice, cell, int)
|
||||
fun sDictGetFirstAsRef(self: cell?, keyLen: int): (slice?, cell?, bool)
|
||||
asm (-> 1 0 2) "DICTMINREF" "NULLSWAPIFNOT2";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGetLast(self: cell, keyLen: int): (int, slice, int)
|
||||
fun iDictGetLast(self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetLast(self: cell, keyLen: int): (int, slice, int)
|
||||
fun uDictGetLast(self: cell?, keyLen: int): (int?, slice?, bool)
|
||||
asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun sDictGetLast(self: cell, keyLen: int): (slice, slice, int)
|
||||
fun sDictGetLast(self: cell?, keyLen: int): (slice?, slice?, bool)
|
||||
asm (-> 1 0 2) "DICTMAX" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun iDictGetLastAsRef(self: cell, keyLen: int): (int, cell, int)
|
||||
fun iDictGetLastAsRef(self: cell?, keyLen: int): (int?, cell?, bool)
|
||||
asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetLastAsRef(self: cell, keyLen: int): (int, cell, int)
|
||||
fun uDictGetLastAsRef(self: cell?, keyLen: int): (int?, cell?, bool)
|
||||
asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun sDictGetLastAsRef(self: cell, keyLen: int): (slice, cell, int)
|
||||
fun sDictGetLastAsRef(self: cell?, keyLen: int): (slice?, cell?, bool)
|
||||
asm (-> 1 0 2) "DICTMAXREF" "NULLSWAPIFNOT2";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGetNext(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun iDictGetNext(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetNext(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun uDictGetNext(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun iDictGetNextOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun iDictGetNextOrEqual(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetNextOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun uDictGetNextOrEqual(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||
|
||||
|
||||
@pure
|
||||
fun iDictGetPrev(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun iDictGetPrev(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetPrev(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun uDictGetPrev(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun iDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun iDictGetPrevOrEqual(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun uDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||
fun uDictGetPrevOrEqual(self: cell?, keyLen: int, pivot: int): (int?, slice?, bool)
|
||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
|
||||
|
||||
|
||||
|
@ -299,13 +300,13 @@ fun uDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
|||
*/
|
||||
|
||||
@pure
|
||||
fun prefixDictGet(self: cell, keyLen: int, key: slice): (slice, slice, slice, int)
|
||||
fun prefixDictGet(self: cell?, keyLen: int, key: slice): (slice, slice?, slice?, bool)
|
||||
asm(key self keyLen) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
||||
|
||||
@pure
|
||||
fun prefixDictSet(mutate self: cell, keyLen: int, key: slice, value: slice): int
|
||||
fun prefixDictSet(mutate self: cell?, keyLen: int, key: slice, value: slice): bool
|
||||
asm(value key self keyLen) "PFXDICTSET";
|
||||
|
||||
@pure
|
||||
fun prefixDictDelete(mutate self: cell, keyLen: int, key: slice): int
|
||||
fun prefixDictDelete(mutate self: cell?, keyLen: int, key: slice): bool
|
||||
asm(key self keyLen) "PFXDICTDEL";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// A part of standard library for Tolk
|
||||
tolk 0.6
|
||||
tolk 0.9
|
||||
|
||||
/// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.
|
||||
/// The primitive returns the current value of `c3`.
|
||||
|
|
|
@ -149,16 +149,17 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args, td::Ref<vm::Cell> cod
|
|||
}
|
||||
|
||||
std::vector<vm::StackEntry> tuple = {
|
||||
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
|
||||
td::make_refint(0), // actions:Integer
|
||||
td::make_refint(0), // msgs_sent:Integer
|
||||
td::make_refint(now), // unixtime:Integer
|
||||
td::make_refint(0), //TODO: // block_lt:Integer
|
||||
td::make_refint(0), //TODO: // trans_lt:Integer
|
||||
std::move(rand_seed_int), // rand_seed:Integer
|
||||
block::CurrencyCollection(args.balance).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||
vm::load_cell_slice_ref(address), // myself:MsgAddressInt
|
||||
vm::StackEntry::maybe(config) // vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
||||
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
|
||||
td::make_refint(0), // actions:Integer
|
||||
td::make_refint(0), // msgs_sent:Integer
|
||||
td::make_refint(now), // unixtime:Integer
|
||||
td::make_refint(0), // block_lt:Integer (TODO)
|
||||
td::make_refint(0), // trans_lt:Integer (TODO)
|
||||
std::move(rand_seed_int), // rand_seed:Integer
|
||||
block::CurrencyCollection(args.balance, args.extra_currencies)
|
||||
.as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||
vm::load_cell_slice_ref(address), // myself:MsgAddressInt
|
||||
vm::StackEntry::maybe(config) // vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
||||
};
|
||||
if (args.config && args.config.value()->get_global_version() >= 4) {
|
||||
tuple.push_back(vm::StackEntry::maybe(code)); // code:Cell
|
||||
|
@ -222,14 +223,14 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
stack->dump(os, 2);
|
||||
LOG(DEBUG) << "VM stack:\n" << os.str();
|
||||
}
|
||||
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
|
||||
int global_version = config ? config->get_global_version() : 0;
|
||||
vm::VmState vm{state.code, global_version, std::move(stack), gas, 1, state.data, log};
|
||||
vm.set_c7(std::move(c7));
|
||||
vm.set_chksig_always_succeed(ignore_chksig);
|
||||
if (!libraries.is_null()) {
|
||||
vm.register_library_collection(libraries);
|
||||
}
|
||||
if (config) {
|
||||
vm.set_global_version(config->get_global_version());
|
||||
auto r_limits = config->get_size_limits_config();
|
||||
if (r_limits.is_ok()) {
|
||||
vm.set_max_data_depth(r_limits.ok().max_vm_data_depth);
|
||||
|
|
|
@ -64,6 +64,7 @@ class SmartContract : public td::CntObject {
|
|||
bool ignore_chksig{false};
|
||||
td::uint64 amount{0};
|
||||
td::uint64 balance{0};
|
||||
td::Ref<vm::Cell> extra_currencies;
|
||||
int vm_log_verbosity_level{0};
|
||||
bool debug_enabled{false};
|
||||
|
||||
|
@ -121,6 +122,10 @@ class SmartContract : public td::CntObject {
|
|||
this->balance = balance;
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_extra_currencies(td::Ref<vm::Cell> extra_currencies) {
|
||||
this->extra_currencies = std::move(extra_currencies);
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_address(block::StdAddress address) {
|
||||
this->address = address;
|
||||
return std::move(*this);
|
||||
|
|
|
@ -2074,7 +2074,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi
|
|||
output_cpp_expr(ss, expr, 100);
|
||||
ss << '.';
|
||||
}
|
||||
ss << "validate_skip_ref(ops, cs, weak)" << tail;
|
||||
ss << "validate_skip_ref(ops, cs, " << (constr.is_special ? "true" : "weak") << ")" << tail;
|
||||
actions += Action{ss.str()};
|
||||
}
|
||||
|
||||
|
|
|
@ -1800,9 +1800,6 @@ void Constructor::show(std::ostream& os, int mode) const {
|
|||
}
|
||||
for (int i = 0; i < type_arity; i++) {
|
||||
os << ' ';
|
||||
if (param_negated.at(i)) {
|
||||
os << '~';
|
||||
}
|
||||
params.at(i)->show(os, this, 100, mode | 1);
|
||||
}
|
||||
if (!(mode & 2)) {
|
||||
|
|
|
@ -45,7 +45,7 @@ bool Bool::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
|||
}
|
||||
|
||||
bool NatWidth::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
long long value = (long long)cs.fetch_ulong(32);
|
||||
long long value = (long long)cs.fetch_ulong(n);
|
||||
return value >= 0 && pp.out_int(value);
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,13 @@ bool TLB::validate_ref_internal(int* ops, Ref<vm::Cell> cell_ref, bool weak) con
|
|||
}
|
||||
bool is_special;
|
||||
auto cs = load_cell_slice_special(std::move(cell_ref), is_special);
|
||||
return always_special() ? is_special : (is_special ? weak : (validate_skip(ops, cs) && cs.empty_ext()));
|
||||
if (cs.special_type() == vm::Cell::SpecialType::PrunnedBranch && weak) {
|
||||
return true;
|
||||
}
|
||||
if (always_special() != is_special) {
|
||||
return false;
|
||||
}
|
||||
return validate_skip(ops, cs, weak) && cs.empty_ext();
|
||||
}
|
||||
|
||||
bool TLB::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
|
@ -190,6 +196,13 @@ bool TLB::print_ref(std::ostream& os, Ref<vm::Cell> cell_ref, int indent, int re
|
|||
return pp.fail_unless(print_ref(pp, std::move(cell_ref)));
|
||||
}
|
||||
|
||||
bool TLB::print_ref(td::StringBuilder& sb, Ref<vm::Cell> cell_ref, int indent, int rec_limit) const {
|
||||
std::ostringstream ss;
|
||||
auto result = print_ref(ss, std::move(cell_ref), indent, rec_limit);
|
||||
sb << ss.str();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string TLB::as_string_skip(vm::CellSlice& cs, int indent) const {
|
||||
std::ostringstream os;
|
||||
print_skip(os, cs, indent);
|
||||
|
|
|
@ -246,7 +246,14 @@ class TLB {
|
|||
bool print(std::ostream& os, Ref<vm::CellSlice> cs_ref, int indent = 0, int rec_limit = 0) const {
|
||||
return print(os, *cs_ref, indent, rec_limit);
|
||||
}
|
||||
bool print(td::StringBuilder& sb, Ref<vm::CellSlice> cs_ref, int indent = 0, int rec_limit = 0) const {
|
||||
std::ostringstream ss;
|
||||
auto result = print(ss, *cs_ref, indent, rec_limit);
|
||||
sb << ss.str();
|
||||
return result;
|
||||
}
|
||||
bool print_ref(std::ostream& os, Ref<vm::Cell> cell_ref, int indent = 0, int rec_limit = 0) const;
|
||||
bool print_ref(td::StringBuilder& sb, Ref<vm::Cell> cell_ref, int indent = 0, int rec_limit = 0) const;
|
||||
bool print_ref(int rec_limit, std::ostream& os, Ref<vm::Cell> cell_ref, int indent = 0) const {
|
||||
return print_ref(os, std::move(cell_ref), indent, rec_limit);
|
||||
}
|
||||
|
|
|
@ -1153,8 +1153,12 @@ td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::
|
|||
return ins.first->second;
|
||||
}
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVm{}, std::move(cell)};
|
||||
return add_used_storage(std::move(cs), kill_dup, skip_count_root);
|
||||
vm::CellSlice cs{vm::NoVm{}, cell};
|
||||
TRY_RESULT(res, add_used_storage(std::move(cs), kill_dup, skip_count_root));
|
||||
if (kill_dup) {
|
||||
seen[cell->get_hash()] = res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void NewCellStorageStat::add_cell(Ref<Cell> cell) {
|
||||
|
|
|
@ -101,9 +101,9 @@ class NewCellStorageStat {
|
|||
|
||||
private:
|
||||
const CellUsageTree* usage_tree_;
|
||||
std::set<vm::Cell::Hash> seen_;
|
||||
td::HashSet<vm::Cell::Hash> seen_;
|
||||
Stat stat_;
|
||||
std::set<vm::Cell::Hash> proof_seen_;
|
||||
td::HashSet<vm::Cell::Hash> proof_seen_;
|
||||
Stat proof_stat_;
|
||||
const NewCellStorageStat* parent_{nullptr};
|
||||
|
||||
|
@ -117,7 +117,7 @@ struct CellStorageStat {
|
|||
struct CellInfo {
|
||||
td::uint32 max_merkle_depth = 0;
|
||||
};
|
||||
std::map<vm::Cell::Hash, CellInfo> seen;
|
||||
td::HashMap<vm::Cell::Hash, CellInfo> seen;
|
||||
CellStorageStat() : cells(0), bits(0), public_cells(0) {
|
||||
}
|
||||
explicit CellStorageStat(unsigned long long limit_cells)
|
||||
|
@ -173,7 +173,7 @@ class ProofStorageStat {
|
|||
enum CellStatus {
|
||||
c_none = 0, c_prunned = 1, c_loaded = 2
|
||||
};
|
||||
std::map<vm::Cell::Hash, CellStatus> cells_;
|
||||
td::HashMap<vm::Cell::Hash, CellStatus> cells_;
|
||||
td::uint64 proof_size_ = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@ bool CellSlice::advance_ext(unsigned bits, unsigned refs) {
|
|||
}
|
||||
|
||||
bool CellSlice::advance_ext(unsigned bits_refs) {
|
||||
return advance_ext(bits_refs >> 16, bits_refs & 0xffff);
|
||||
return advance_ext(bits_refs & 0xffff, bits_refs >> 16);
|
||||
}
|
||||
|
||||
// (PRIVATE)
|
||||
|
@ -1026,6 +1026,13 @@ bool CellSlice::print_rec(std::ostream& os, int indent) const {
|
|||
return print_rec(os, &limit, indent);
|
||||
}
|
||||
|
||||
bool CellSlice::print_rec(td::StringBuilder& sb, int indent) const {
|
||||
std::ostringstream ss;
|
||||
auto result = print_rec(ss, indent);
|
||||
sb << ss.str();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CellSlice::print_rec(int limit, std::ostream& os, int indent) const {
|
||||
return print_rec(os, &limit, indent);
|
||||
}
|
||||
|
|
|
@ -257,6 +257,7 @@ class CellSlice : public td::CntObject {
|
|||
void dump(std::ostream& os, int level = 0, bool endl = true) const;
|
||||
void dump_hex(std::ostream& os, int mode = 0, bool endl = false) const;
|
||||
bool print_rec(std::ostream& os, int indent = 0) const;
|
||||
bool print_rec(td::StringBuilder& sb, int indent = 0) const;
|
||||
bool print_rec(std::ostream& os, int* limit, int indent = 0) const;
|
||||
bool print_rec(int limit, std::ostream& os, int indent = 0) const;
|
||||
void error() const {
|
||||
|
|
|
@ -261,10 +261,10 @@ int exec_runvm_common(VmState* st, unsigned mode) {
|
|||
vm::GasLimits gas{gas_limit, gas_max};
|
||||
|
||||
VmStateInterface::Guard guard{nullptr}; // Don't consume gas for creating/loading cells during VM init
|
||||
VmState new_state{std::move(code), std::move(new_stack), gas, (int)mode & 3, std::move(data),
|
||||
VmLog{}, std::vector<Ref<Cell>>{}, std::move(c7)};
|
||||
VmState new_state{
|
||||
std::move(code), st->get_global_version(), std::move(new_stack), gas, (int)mode & 3, std::move(data),
|
||||
VmLog{}, std::vector<Ref<Cell>>{}, std::move(c7)};
|
||||
new_state.set_chksig_always_succeed(st->get_chksig_always_succeed());
|
||||
new_state.set_global_version(st->get_global_version());
|
||||
st->run_child_vm(std::move(new_state), with_data, mode & 32, mode & 8, mode & 128, ret_vals);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -100,8 +100,18 @@ class DynamicBagOfCellsDbImpl : public DynamicBagOfCellsDb, private ExtCellCreat
|
|||
return get_cell_info_lazy(level_mask, hash, depth).cell;
|
||||
}
|
||||
td::Result<Ref<DataCell>> load_cell(td::Slice hash) override {
|
||||
TRY_RESULT(loaded_cell, get_cell_info_force(hash).cell->load_cell());
|
||||
return std::move(loaded_cell.data_cell);
|
||||
auto info = hash_table_.get_if_exists(hash);
|
||||
if (info && info->sync_with_db) {
|
||||
TRY_RESULT(loaded_cell, info->cell->load_cell());
|
||||
return std::move(loaded_cell.data_cell);
|
||||
}
|
||||
TRY_RESULT(res, loader_->load(hash, true, *this));
|
||||
if (res.status != CellLoader::LoadResult::Ok) {
|
||||
return td::Status::Error("cell not found");
|
||||
}
|
||||
Ref<DataCell> cell = res.cell();
|
||||
hash_table_.apply(hash, [&](CellInfo &info) { update_cell_info_loaded(info, hash, std::move(res)); });
|
||||
return cell;
|
||||
}
|
||||
td::Result<Ref<DataCell>> load_root(td::Slice hash) override {
|
||||
return load_cell(hash);
|
||||
|
@ -145,9 +155,6 @@ class DynamicBagOfCellsDbImpl : public DynamicBagOfCellsDb, private ExtCellCreat
|
|||
promise->set_result(std::move(cell));
|
||||
});
|
||||
}
|
||||
CellInfo &get_cell_info_force(td::Slice hash) {
|
||||
return hash_table_.apply(hash, [&](CellInfo &info) { update_cell_info_force(info, hash); });
|
||||
}
|
||||
CellInfo &get_cell_info_lazy(Cell::LevelMask level_mask, td::Slice hash, td::Slice depth) {
|
||||
return hash_table_.apply(hash.substr(hash.size() - Cell::hash_bytes),
|
||||
[&](CellInfo &info) { update_cell_info_lazy(info, level_mask, hash, depth); });
|
||||
|
|
|
@ -309,7 +309,9 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
return 0;
|
||||
}
|
||||
td::Slice offset_view;
|
||||
CHECK(info_.offset_byte_size <= 8);
|
||||
if (info_.offset_byte_size > 8) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid offset_byte_size " << info_.offset_byte_size);
|
||||
}
|
||||
char arr[8];
|
||||
td::RwMutex::ReadLock guard;
|
||||
if (info_.has_index) {
|
||||
|
@ -321,19 +323,25 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
offset_view = td::Slice(index_data_).substr((td::int64)idx * info_.offset_byte_size, info_.offset_byte_size);
|
||||
}
|
||||
|
||||
CHECK(offset_view.size() == (size_t)info_.offset_byte_size);
|
||||
if (offset_view.size() != (size_t)info_.offset_byte_size) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid offset view size" << offset_view.size());
|
||||
}
|
||||
return td::narrow_cast<std::size_t>(info_.read_offset(offset_view.ubegin()));
|
||||
}
|
||||
|
||||
td::Result<td::int64> load_root_idx(int root_i) {
|
||||
CHECK(root_i >= 0 && root_i < info_.root_count);
|
||||
if (root_i < 0 || root_i >= info_.root_count) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid root index " << root_i);
|
||||
}
|
||||
if (!info_.has_roots) {
|
||||
return 0;
|
||||
}
|
||||
char arr[8];
|
||||
TRY_RESULT(idx_view, data_.view(td::MutableSlice(arr, info_.ref_byte_size),
|
||||
info_.roots_offset + (td::int64)root_i * info_.ref_byte_size));
|
||||
CHECK(idx_view.size() == (size_t)info_.ref_byte_size);
|
||||
if (idx_view.size() != (size_t)info_.ref_byte_size) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid idx_view size" << idx_view.size());
|
||||
}
|
||||
return info_.read_ref(idx_view.ubegin());
|
||||
}
|
||||
|
||||
|
@ -343,8 +351,9 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
bool should_cache;
|
||||
};
|
||||
td::Result<CellLocation> get_cell_location(int idx) {
|
||||
CHECK(idx >= 0);
|
||||
CHECK(idx < info_.cell_count);
|
||||
if (idx < 0 || idx >= info_.cell_count) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid cell index " << idx);
|
||||
}
|
||||
TRY_STATUS(preload_index(idx));
|
||||
TRY_RESULT(from, load_idx_offset(idx - 1));
|
||||
TRY_RESULT(till, load_idx_offset(idx));
|
||||
|
@ -357,10 +366,15 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
res.should_cache = res.end % 2 == 1;
|
||||
res.end /= 2;
|
||||
}
|
||||
CHECK(std::numeric_limits<std::size_t>::max() - res.begin >= info_.data_offset);
|
||||
CHECK(std::numeric_limits<std::size_t>::max() - res.end >= info_.data_offset);
|
||||
if (std::numeric_limits<std::size_t>::max() - res.begin < info_.data_offset ||
|
||||
std::numeric_limits<std::size_t>::max() - res.end < info_.data_offset) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid cell location (1) " << res.begin << ":" << res.end);
|
||||
}
|
||||
res.begin += static_cast<std::size_t>(info_.data_offset);
|
||||
res.end += static_cast<std::size_t>(info_.data_offset);
|
||||
if (res.begin > res.end) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid cell location (2) " << res.begin << ":" << res.end);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -396,8 +410,6 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
if (info_.has_index) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
CHECK(idx < info_.cell_count);
|
||||
if (index_i_.load(std::memory_order_relaxed) > idx) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -407,12 +419,17 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
auto buf_slice = td::MutableSlice(buf.data(), buf.size());
|
||||
for (; index_i_ <= idx; index_i_++) {
|
||||
auto offset = td::narrow_cast<size_t>(info_.data_offset + index_offset_);
|
||||
CHECK(data_.size() >= offset);
|
||||
if (data_.size() < offset) {
|
||||
return td::Status::Error(PSLICE() << "bag-of-cells error: invalid offset " << offset
|
||||
<< " (size=" << data_.size() << ")");
|
||||
}
|
||||
TRY_RESULT(cell, data_.view(buf_slice.copy().truncate(data_.size() - offset), offset));
|
||||
CellSerializationInfo cell_info;
|
||||
TRY_STATUS(cell_info.init(cell, info_.ref_byte_size));
|
||||
index_offset_ += cell_info.end_offset;
|
||||
LOG_CHECK((unsigned)info_.offset_byte_size <= 8) << info_.offset_byte_size;
|
||||
if ((unsigned)info_.offset_byte_size > 8) {
|
||||
return td::Status::Error(PSTRING() << "bag-of-cell error: invalid offset_byte_size " << info_.offset_byte_size);
|
||||
}
|
||||
td::uint8 tmp[8];
|
||||
info_.write_offset(tmp, index_offset_);
|
||||
auto guard = index_data_rw_mutex_.lock_write();
|
||||
|
@ -488,7 +505,10 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
bool should_cache) {
|
||||
deserialize_cell_cnt_.add(1);
|
||||
Ref<Cell> refs[4];
|
||||
CHECK(cell_info.refs_cnt <= 4);
|
||||
if (cell_info.refs_cnt > 4) {
|
||||
return td::Status::Error(PSLICE() << "invalid bag-of-cells cell #" << idx << " has " << cell_info.refs_cnt
|
||||
<< " refs");
|
||||
}
|
||||
auto* ref_ptr = cell_slice.ubegin() + cell_info.refs_offset;
|
||||
for (int k = 0; k < cell_info.refs_cnt; k++, ref_ptr += info_.ref_byte_size) {
|
||||
int ref_idx = td::narrow_cast<int>(info_.read_ref(ref_ptr));
|
||||
|
|
|
@ -566,7 +566,7 @@ int exec_dict_getnear(VmState* st, unsigned args) {
|
|||
int exec_pfx_dict_set(VmState* st, Dictionary::SetMode mode, const char* name) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute PFXDICT" << name;
|
||||
stack.check_underflow(3);
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 4 : 3);
|
||||
int n = stack.pop_smallint_range(PrefixDictionary::max_key_bits);
|
||||
PrefixDictionary dict{stack.pop_maybe_cell(), n};
|
||||
auto key_slice = stack.pop_cellslice();
|
||||
|
@ -580,7 +580,7 @@ int exec_pfx_dict_set(VmState* st, Dictionary::SetMode mode, const char* name) {
|
|||
int exec_pfx_dict_delete(VmState* st) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute PFXDICTDEL\n";
|
||||
stack.check_underflow(2);
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 2);
|
||||
int n = stack.pop_smallint_range(PrefixDictionary::max_key_bits);
|
||||
PrefixDictionary dict{stack.pop_maybe_cell(), n};
|
||||
auto key_slice = stack.pop_cellslice();
|
||||
|
|
|
@ -279,6 +279,7 @@ int exec_get_global_id(VmState* st) {
|
|||
int exec_get_gas_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETGASFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 gas = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
block::GasLimitsPrices prices = util::get_gas_prices(get_unpacked_config_tuple(st), is_masterchain);
|
||||
|
@ -289,6 +290,7 @@ int exec_get_gas_fee(VmState* st) {
|
|||
int exec_get_storage_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETSTORAGEFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 4 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::int64 delta = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
|
@ -302,6 +304,7 @@ int exec_get_storage_fee(VmState* st) {
|
|||
int exec_get_forward_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETFORWARDFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
td::uint64 cells = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
|
@ -320,6 +323,7 @@ int exec_get_precompiled_gas(VmState* st) {
|
|||
int exec_get_original_fwd_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETORIGINALFWDFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::RefInt256 fwd_fee = stack.pop_int_finite();
|
||||
if (fwd_fee->sgn() < 0) {
|
||||
|
@ -333,6 +337,7 @@ int exec_get_original_fwd_fee(VmState* st) {
|
|||
int exec_get_gas_fee_simple(VmState* st) {
|
||||
VM_LOG(st) << "execute GETGASFEESIMPLE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 gas = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
block::GasLimitsPrices prices = util::get_gas_prices(get_unpacked_config_tuple(st), is_masterchain);
|
||||
|
@ -343,6 +348,7 @@ int exec_get_gas_fee_simple(VmState* st) {
|
|||
int exec_get_forward_fee_simple(VmState* st) {
|
||||
VM_LOG(st) << "execute GETFORWARDFEESIMPLE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
td::uint64 cells = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
|
@ -373,6 +379,7 @@ void register_ton_config_ops(OpcodeTable& cp0) {
|
|||
.insert(OpcodeInstr::mksimple(0xf833, 16, "CONFIGOPTPARAM", std::bind(exec_get_config_param, _1, true)))
|
||||
.insert(OpcodeInstr::mksimple(0xf83400, 24, "PREVMCBLOCKS", std::bind(exec_get_prev_blocks_info, _1, 0, "PREVMCBLOCKS"))->require_version(4))
|
||||
.insert(OpcodeInstr::mksimple(0xf83401, 24, "PREVKEYBLOCK", std::bind(exec_get_prev_blocks_info, _1, 1, "PREVKEYBLOCK"))->require_version(4))
|
||||
.insert(OpcodeInstr::mksimple(0xf83402, 24, "PREVMCBLOCKS_100", std::bind(exec_get_prev_blocks_info, _1, 2, "PREVMCBLOCKS_100"))->require_version(9))
|
||||
.insert(OpcodeInstr::mksimple(0xf835, 16, "GLOBALID", exec_get_global_id)->require_version(4))
|
||||
.insert(OpcodeInstr::mksimple(0xf836, 16, "GETGASFEE", exec_get_gas_fee)->require_version(6))
|
||||
.insert(OpcodeInstr::mksimple(0xf837, 16, "GETSTORAGEFEE", exec_get_storage_fee)->require_version(6))
|
||||
|
@ -538,9 +545,10 @@ int exec_hash_ext(VmState* st, unsigned args) {
|
|||
VM_LOG(st) << "execute HASHEXT" << (append ? "A" : "") << (rev ? "R" : "") << " " << (hash_id == 255 ? -1 : hash_id);
|
||||
Stack& stack = st->get_stack();
|
||||
if (hash_id == 255) {
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
hash_id = stack.pop_smallint_range(254);
|
||||
}
|
||||
int cnt = stack.pop_smallint_range(stack.depth() - 1);
|
||||
int cnt = stack.pop_smallint_range(stack.depth() - 1 - (st->get_global_version() >= 9 ? (int)append : 0));
|
||||
Hasher hasher{hash_id};
|
||||
size_t total_bits = 0;
|
||||
long long gas_consumed = 0;
|
||||
|
@ -1293,7 +1301,7 @@ void register_ton_crypto_ops(OpcodeTable& cp0) {
|
|||
}
|
||||
|
||||
int exec_compute_data_size(VmState* st, int mode) {
|
||||
VM_LOG(st) << (mode & 2 ? 'S' : 'C') << "DATASIZE" << (mode & 1 ? "Q" : "");
|
||||
VM_LOG(st) << "execute " << (mode & 2 ? 'S' : 'C') << "DATASIZE" << (mode & 1 ? "Q" : "");
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(2);
|
||||
auto bound = stack.pop_int();
|
||||
|
@ -1753,6 +1761,10 @@ int exec_send_message(VmState* st) {
|
|||
vm::VmStorageStat stat(max_cells);
|
||||
CellSlice cs = load_cell_slice(msg_cell);
|
||||
cs.skip_first(cs.size());
|
||||
if (st->get_global_version() >= 10 && have_extra_currencies) {
|
||||
// Skip extra currency dict
|
||||
cs.advance_refs(1);
|
||||
}
|
||||
stat.add_storage(cs);
|
||||
|
||||
if (!ext_msg) {
|
||||
|
@ -1765,7 +1777,9 @@ int exec_send_message(VmState* st) {
|
|||
if (value.is_null()) {
|
||||
throw VmError{Excno::type_chk, "invalid param BALANCE"};
|
||||
}
|
||||
have_extra_currencies |= !tuple_index(balance, 1).as_cell().is_null();
|
||||
if (st->get_global_version() < 10) {
|
||||
have_extra_currencies |= !tuple_index(balance, 1).as_cell().is_null();
|
||||
}
|
||||
} else if (mode & 64) { // value += value of incoming message
|
||||
Ref<Tuple> balance = get_param(st, 11).as_tuple();
|
||||
if (balance.is_null()) {
|
||||
|
@ -1776,7 +1790,9 @@ int exec_send_message(VmState* st) {
|
|||
throw VmError{Excno::type_chk, "invalid param INCOMINGVALUE"};
|
||||
}
|
||||
value += balance_grams;
|
||||
have_extra_currencies |= !tuple_index(balance, 1).as_cell().is_null();
|
||||
if (st->get_global_version() < 10) {
|
||||
have_extra_currencies |= !tuple_index(balance, 1).as_cell().is_null();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "vm/log.h"
|
||||
#include "vm/vm.h"
|
||||
#include "cp0.h"
|
||||
#include "memo.h"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
namespace vm {
|
||||
|
@ -31,33 +33,8 @@ VmState::VmState() : cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), qu
|
|||
init_cregs();
|
||||
}
|
||||
|
||||
VmState::VmState(Ref<CellSlice> _code)
|
||||
: code(std::move(_code)), cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) {
|
||||
ensure_throw(init_cp(0));
|
||||
init_cregs();
|
||||
}
|
||||
|
||||
VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, int flags, Ref<Cell> _data, VmLog log,
|
||||
std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
|
||||
: code(std::move(_code))
|
||||
, stack(std::move(_stack))
|
||||
, cp(-1)
|
||||
, dispatch(&dummy_dispatch_table)
|
||||
, quit0(true, 0)
|
||||
, quit1(true, 1)
|
||||
, log(log)
|
||||
, libraries(std::move(_libraries))
|
||||
, stack_trace((flags >> 2) & 1) {
|
||||
ensure_throw(init_cp(0));
|
||||
set_c4(std::move(_data));
|
||||
if (init_c7.not_null()) {
|
||||
set_c7(std::move(init_c7));
|
||||
}
|
||||
init_cregs(flags & 1, flags & 2);
|
||||
}
|
||||
|
||||
VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas, int flags, Ref<Cell> _data, VmLog log,
|
||||
std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
|
||||
VmState::VmState(Ref<CellSlice> _code, int global_version, Ref<Stack> _stack, const GasLimits& gas, int flags,
|
||||
Ref<Cell> _data, VmLog log, std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
|
||||
: code(std::move(_code))
|
||||
, stack(std::move(_stack))
|
||||
, cp(-1)
|
||||
|
@ -67,7 +44,8 @@ VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas,
|
|||
, log(log)
|
||||
, gas(gas)
|
||||
, libraries(std::move(_libraries))
|
||||
, stack_trace((flags >> 2) & 1) {
|
||||
, stack_trace((flags >> 2) & 1)
|
||||
, global_version(global_version) {
|
||||
ensure_throw(init_cp(0));
|
||||
set_c4(std::move(_data));
|
||||
if (init_c7.not_null()) {
|
||||
|
@ -102,12 +80,24 @@ void VmState::init_cregs(bool same_c3, bool push_0) {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell) {
|
||||
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell, int global_version,
|
||||
const std::vector<Ref<Cell>>& libraries) {
|
||||
if (code_cell.is_null()) {
|
||||
return {};
|
||||
}
|
||||
Ref<CellSlice> csr{true, NoVmOrd(), code_cell};
|
||||
if (csr->is_valid()) {
|
||||
Ref<CellSlice> csr;
|
||||
if (global_version >= 9) {
|
||||
// Use DummyVmState instead of this to avoid consuming gas for cell loading
|
||||
DummyVmState dummy{libraries, global_version};
|
||||
Guard guard(&dummy);
|
||||
try {
|
||||
csr = load_cell_slice_ref(code_cell);
|
||||
} catch (VmError&) { // NOLINT(*-empty-catch)
|
||||
}
|
||||
} else {
|
||||
csr = td::Ref<CellSlice>{true, NoVmOrd(), code_cell};
|
||||
}
|
||||
if (csr.not_null() && csr->is_valid()) {
|
||||
return csr;
|
||||
}
|
||||
return load_cell_slice_ref(CellBuilder{}.store_ref(std::move(code_cell)).finalize());
|
||||
|
@ -257,6 +247,11 @@ int VmState::jump(Ref<Continuation> cont) {
|
|||
|
||||
// general jump to continuation cont
|
||||
int VmState::jump(Ref<Continuation> cont, int pass_args) {
|
||||
cont = adjust_jump_cont(std::move(cont), pass_args);
|
||||
return jump_to(std::move(cont));
|
||||
}
|
||||
|
||||
Ref<Continuation> VmState::adjust_jump_cont(Ref<Continuation> cont, int pass_args) {
|
||||
const ControlData* cont_data = cont->get_cdata();
|
||||
if (cont_data) {
|
||||
// first do the checks
|
||||
|
@ -297,7 +292,7 @@ int VmState::jump(Ref<Continuation> cont, int pass_args) {
|
|||
consume_stack_gas(copy);
|
||||
}
|
||||
}
|
||||
return jump_to(std::move(cont));
|
||||
return cont;
|
||||
} else {
|
||||
// have no continuation data, situation is somewhat simpler
|
||||
if (pass_args >= 0) {
|
||||
|
@ -309,7 +304,7 @@ int VmState::jump(Ref<Continuation> cont, int pass_args) {
|
|||
consume_stack_gas(pass_args);
|
||||
}
|
||||
}
|
||||
return jump_to(std::move(cont));
|
||||
return cont;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,6 +572,7 @@ int run_vm_code(Ref<CellSlice> code, Ref<Stack>& stack, int flags, Ref<Cell>* da
|
|||
GasLimits* gas_limits, std::vector<Ref<Cell>> libraries, Ref<Tuple> init_c7, Ref<Cell>* actions_ptr,
|
||||
int global_version) {
|
||||
VmState vm{code,
|
||||
global_version,
|
||||
std::move(stack),
|
||||
gas_limits ? *gas_limits : GasLimits{},
|
||||
flags,
|
||||
|
@ -584,7 +580,6 @@ int run_vm_code(Ref<CellSlice> code, Ref<Stack>& stack, int flags, Ref<Cell>* da
|
|||
log,
|
||||
std::move(libraries),
|
||||
std::move(init_c7)};
|
||||
vm.set_global_version(global_version);
|
||||
int res = vm.run();
|
||||
stack = vm.get_stack_ref();
|
||||
if (vm.committed() && data_ptr) {
|
||||
|
|
|
@ -164,14 +164,12 @@ class VmState final : public VmStateInterface {
|
|||
bls_pairing_element_gas_price = 11800
|
||||
};
|
||||
VmState();
|
||||
VmState(Ref<CellSlice> _code);
|
||||
VmState(Ref<CellSlice> _code, Ref<Stack> _stack, int flags = 0, Ref<Cell> _data = {}, VmLog log = {},
|
||||
std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {});
|
||||
VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0, Ref<Cell> _data = {},
|
||||
VmState(Ref<CellSlice> _code, int global_version, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0, Ref<Cell> _data = {},
|
||||
VmLog log = {}, std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {});
|
||||
template <typename... Args>
|
||||
VmState(Ref<Cell> code_cell, Args&&... args)
|
||||
: VmState(convert_code_cell(std::move(code_cell)), std::forward<Args>(args)...) {
|
||||
VmState(Ref<Cell> _code, int global_version, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0,
|
||||
Ref<Cell> _data = {}, VmLog log = {}, std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {})
|
||||
: VmState(convert_code_cell(std::move(_code), global_version, _libraries), global_version, std::move(_stack),
|
||||
_gas, flags, std::move(_data), std::move(log), _libraries, std::move(init_c7)) {
|
||||
}
|
||||
VmState(const VmState&) = delete;
|
||||
VmState(VmState&&) = default;
|
||||
|
@ -345,13 +343,11 @@ class VmState final : public VmStateInterface {
|
|||
int get_global_version() const override {
|
||||
return global_version;
|
||||
}
|
||||
void set_global_version(int version) {
|
||||
global_version = version;
|
||||
}
|
||||
int call(Ref<Continuation> cont);
|
||||
int call(Ref<Continuation> cont, int pass_args, int ret_args = -1);
|
||||
int jump(Ref<Continuation> cont);
|
||||
int jump(Ref<Continuation> cont, int pass_args);
|
||||
Ref<Continuation> adjust_jump_cont(Ref<Continuation> cont, int pass_args);
|
||||
int ret();
|
||||
int ret(int ret_args);
|
||||
int ret_alt();
|
||||
|
@ -379,10 +375,18 @@ class VmState final : public VmStateInterface {
|
|||
if (cnt > free_nested_cont_jump && global_version >= 9) {
|
||||
consume_gas(1);
|
||||
}
|
||||
if (cont.not_null() && global_version >= 9) {
|
||||
const ControlData* cont_data = cont->get_cdata();
|
||||
if (cont_data && (cont_data->stack.not_null() || cont_data->nargs >= 0)) {
|
||||
// if cont has non-empty stack or expects fixed number of arguments, jump is not simple
|
||||
cont = adjust_jump_cont(std::move(cont), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
|
||||
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell, int global_version,
|
||||
const std::vector<Ref<Cell>>& libraries);
|
||||
bool try_commit();
|
||||
void force_commit();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ Global version is a parameter specified in `ConfigParam 8` ([block.tlb](https://
|
|||
Various features are enabled depending on the global version.
|
||||
|
||||
## Version 4
|
||||
New features of version 4 are desctibed in detail in [the documentation](https://docs.ton.org/v3/documentation/tvm/changelog/tvm-upgrade-2023-07).
|
||||
|
||||
### New TVM instructions
|
||||
* `PREVMCBLOCKS`, `PREVKEYBLOCK`
|
||||
|
@ -47,7 +48,7 @@ Version 5 enables higher gas limits for special contracts.
|
|||
Previously only ticktock transactions had this limit, while ordinary transactions had a default limit of `gas_limit` gas (1M).
|
||||
* Gas usage of special contracts is not taken into account when checking block limits. This allows keeping masterchain block limits low
|
||||
while having high gas limits for elector.
|
||||
* Gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` is increased to `special_gas_limit * 2` until 2024-02-29.
|
||||
* Gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` is increased to 70M (`special_gas_limit * 2`) until 2024-02-29.
|
||||
See [this post](https://t.me/tonstatus/88) for details.
|
||||
|
||||
### Loading libraries
|
||||
|
@ -113,13 +114,45 @@ Operations for working with Merkle proofs, where cells can have non-zero level a
|
|||
|
||||
## Version 9
|
||||
|
||||
### c7 tuple
|
||||
c7 tuple parameter number **13** (previous blocks info tuple) now has the third element. It contains ids of the 16 last masterchain blocks with seqno divisible by 100.
|
||||
Example: if the last masterchain block seqno is `19071` then the list contains block ids with seqnos `19000`, `18900`, ..., `17500`.
|
||||
|
||||
### New TVM instructions
|
||||
- `SECP256K1_XONLY_PUBKEY_TWEAK_ADD` (`key tweak - 0 or f x y -1`) - performs [`secp256k1_xonly_pubkey_tweak_add`](https://github.com/bitcoin-core/secp256k1/blob/master/include/secp256k1_extrakeys.h#L120).
|
||||
`key` and `tweak` are 256-bit unsigned integers. 65-byte public key is returned as `uint8 f`, `uint256 x, y` (as in `ECRECOVER`). Gas cost: `1276`.
|
||||
- `mask SETCONTCTRMANY` (`cont - cont'`) - takes continuation, performs the equivalent of `c[i] PUSHCTR SWAP c[i] SETCONTCNR` for each `i` that is set in `mask` (mask is in `0..255`).
|
||||
- `SETCONTCTRMANYX` (`cont mask - cont'`) - same as `SETCONTCTRMANY`, but takes `mask` from stack.
|
||||
- `PREVMCBLOCKS_100` returns the third element of the previous block info tuple (see above).
|
||||
|
||||
### Other changes
|
||||
- Fix `RAWRESERVE` action with flag `4` (use original balance of the account) by explicitly setting `original_balance` to `balance - msg_balance_remaining`.
|
||||
- Previously it did not work if storage fee was greater than the original balance.
|
||||
- Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code).
|
||||
- Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code).
|
||||
- Support extra currencies in reserve action with `+2` mode.
|
||||
- Fix exception code in some TVM instructions: now `stk_und` has priority over other error codes.
|
||||
- `PFXDICTADD`, `PFXDICTSET`, `PFXDICTREPLACE`, `PFXDICTDEL`, `GETGASFEE`, `GETSTORAGEFEE`, `GETFORWARDFEE`, `GETORIGINALFWDFEE`, `GETGASFEESIMPLE`, `GETFORWARDFEESIMPLE`, `HASHEXT`
|
||||
- Now setting the contract code to a library cell does not consume additional gas on execution of the code.
|
||||
- Temporary increase gas limit for some accounts (see [this post](https://t.me/tondev_news/129) for details, `override_gas_limit` in `transaction.cpp` for the list of accounts).
|
||||
- Fix recursive jump to continuations with non-null control data.
|
||||
|
||||
## Version 10
|
||||
|
||||
### Extra currencies
|
||||
- Internal messages cannot carry more than 2 different extra currencies. The limit can be changed in size limits config (`ConfigParam 43`).
|
||||
- Amount of an extra currency in an output action "send message" can be zero.
|
||||
- In action phase zero values are automatically deleted from the dictionary before sending.
|
||||
- However, the size of the extra currency dictionary in the "send message" action should not be greater than 2 (or the value in size limits config).
|
||||
- Extra currency dictionary is not counted in message size and does not affect message fees.
|
||||
- Message mode `+64` (carry all remaining message balance) is now considered as "carry all remaining TONs from message balance".
|
||||
- Message mode `+128` (carry all remaining account balance) is now considered as "carry all remaining TONs from account balance".
|
||||
- Message mode `+32` (delete account if balance is zero) deletes account if it has zero TONs, regardless of extra currencies.
|
||||
- Deleted accounts with extra currencies become `account_uninit`, extra currencies remain on the account.
|
||||
- `SENDMSG` in TVM calculates message size and fees without extra currencies, uses new `+64` and `+128` mode behavior.
|
||||
- `SENDMSG` does not check the number of extra currencies.
|
||||
- Extra currency dictionary is not counted in the account size and does not affect storage fees.
|
||||
- Accounts with already existing extra currencies will get their sizes recomputed without EC only after modifying `AccountState`.
|
||||
|
||||
### TVM changes
|
||||
- `SENDMSG` calculates messages size and fees without extra currencies, uses new +64 and +128 mode behavior.
|
||||
- `SENDMSG` does not check the number of extra currencies.
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Use \"OFF\" for a static build." ON)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
option(EMULATOR_STATIC "Build emulator as static library" OFF)
|
||||
|
||||
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
|
||||
)
|
||||
|
@ -29,14 +20,22 @@ include(GenerateExportHeader)
|
|||
add_library(emulator_static STATIC ${EMULATOR_STATIC_SOURCE})
|
||||
target_link_libraries(emulator_static PUBLIC ton_crypto smc-envelope)
|
||||
|
||||
if (NOT USE_EMSCRIPTEN AND BUILD_SHARED_LIBS)
|
||||
add_library(emulator SHARED ${EMULATOR_SOURCE} ${EMULATOR_HEADERS})
|
||||
if (EMULATOR_STATIC OR USE_EMSCRIPTEN)
|
||||
add_library(emulator STATIC ${EMULATOR_SOURCE})
|
||||
else()
|
||||
add_library(emulator STATIC ${EMULATOR_SOURCE} ${EMULATOR_HEADERS})
|
||||
add_library(emulator SHARED ${EMULATOR_SOURCE})
|
||||
endif()
|
||||
|
||||
if (PORTABLE AND NOT APPLE)
|
||||
target_link_libraries(emulator PUBLIC emulator_static git -static-libgcc -static-libstdc++)
|
||||
else()
|
||||
target_link_libraries(emulator PUBLIC emulator_static git)
|
||||
endif()
|
||||
|
||||
target_link_libraries(emulator PUBLIC emulator_static git)
|
||||
generate_export_header(emulator EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/emulator_export.h)
|
||||
if (EMULATOR_STATIC OR USE_EMSCRIPTEN)
|
||||
target_compile_definitions(emulator PUBLIC EMULATOR_STATIC_DEFINE)
|
||||
endif()
|
||||
target_include_directories(emulator PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
|
|
|
@ -65,6 +65,7 @@ struct GetMethodParams {
|
|||
std::string address;
|
||||
uint32_t unixtime;
|
||||
uint64_t balance;
|
||||
std::string extra_currencies;
|
||||
std::string rand_seed_hex;
|
||||
int64_t gas_limit;
|
||||
int method_id;
|
||||
|
@ -108,6 +109,32 @@ td::Result<GetMethodParams> decode_get_method_params(const char* json) {
|
|||
TRY_RESULT(balance, td::to_integer_safe<td::uint64>(balance_field.get_string()));
|
||||
params.balance = balance;
|
||||
|
||||
TRY_RESULT(ec_field, td::get_json_object_field(obj, "extra_currencies", td::JsonValue::Type::Object, true));
|
||||
if (ec_field.type() != td::JsonValue::Type::Null) {
|
||||
if (ec_field.type() != td::JsonValue::Type::Object) {
|
||||
return td::Status::Error("EC must be of type Object");
|
||||
}
|
||||
td::StringBuilder ec_builder;
|
||||
auto& ec_obj = ec_field.get_object();
|
||||
bool is_first = true;
|
||||
for (auto &field_value : ec_obj) {
|
||||
auto currency_id = field_value.first;
|
||||
if (field_value.second.type() != td::JsonValue::Type::String) {
|
||||
return td::Status::Error(PSLICE() << "EC amount must be of type String");
|
||||
}
|
||||
auto amount = field_value.second.get_string();
|
||||
if (!is_first) {
|
||||
ec_builder << " ";
|
||||
is_first = false;
|
||||
}
|
||||
ec_builder << currency_id << "=" << amount;
|
||||
}
|
||||
if (ec_builder.is_error()) {
|
||||
return td::Status::Error(PSLICE() << "Error building extra currencies string");
|
||||
}
|
||||
params.extra_currencies = ec_builder.as_cslice().str();
|
||||
}
|
||||
|
||||
TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", false));
|
||||
params.rand_seed_hex = rand_seed_str;
|
||||
|
||||
|
@ -228,8 +255,8 @@ const char *run_get_method(const char *params, const char* stack, const char* co
|
|||
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.prev_blocks_info &&
|
||||
!tvm_emulator_set_prev_blocks_info(tvm, decoded_params.prev_blocks_info.value().c_str())) ||
|
||||
(decoded_params.extra_currencies.size() > 0 && !tvm_emulator_set_extra_currencies(tvm, decoded_params.extra_currencies.c_str())) ||
|
||||
(decoded_params.prev_blocks_info && !tvm_emulator_set_prev_blocks_info(tvm, decoded_params.prev_blocks_info.value().c_str())) ||
|
||||
(decoded_params.gas_limit > 0 && !tvm_emulator_set_gas_limit(tvm, decoded_params.gas_limit)) ||
|
||||
!tvm_emulator_set_debug_enabled(tvm, decoded_params.debug_enabled)) {
|
||||
tvm_emulator_destroy(tvm);
|
||||
|
|
|
@ -496,6 +496,59 @@ bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixt
|
|||
return true;
|
||||
}
|
||||
|
||||
bool tvm_emulator_set_extra_currencies(void *tvm_emulator, const char *extra_currencies) {
|
||||
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
||||
vm::Dictionary dict{32};
|
||||
td::Slice extra_currencies_str{extra_currencies};
|
||||
while (true) {
|
||||
auto next_space_pos = extra_currencies_str.find(' ');
|
||||
auto currency_id_amount = next_space_pos == td::Slice::npos ?
|
||||
extra_currencies_str.substr(0) : extra_currencies_str.substr(0, next_space_pos);
|
||||
|
||||
if (!currency_id_amount.empty()) {
|
||||
auto delim_pos = currency_id_amount.find('=');
|
||||
if (delim_pos == td::Slice::npos) {
|
||||
LOG(ERROR) << "Invalid extra currency format, missing '='";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto currency_id_str = currency_id_amount.substr(0, delim_pos);
|
||||
auto amount_str = currency_id_amount.substr(delim_pos + 1);
|
||||
|
||||
auto currency_id = td::to_integer_safe<uint32_t>(currency_id_str);
|
||||
if (currency_id.is_error()) {
|
||||
LOG(ERROR) << "Invalid extra currency id: " << currency_id_str;
|
||||
return false;
|
||||
}
|
||||
auto amount = td::dec_string_to_int256(amount_str);
|
||||
if (amount.is_null()) {
|
||||
LOG(ERROR) << "Invalid extra currency amount: " << amount_str;
|
||||
return false;
|
||||
}
|
||||
if (amount == 0) {
|
||||
continue;
|
||||
}
|
||||
if (amount < 0) {
|
||||
LOG(ERROR) << "Negative extra currency amount: " << amount_str;
|
||||
return false;
|
||||
}
|
||||
|
||||
vm::CellBuilder cb;
|
||||
block::tlb::t_VarUInteger_32.store_integer_value(cb, *amount);
|
||||
if (!dict.set_builder(td::BitArray<32>(currency_id.ok()), cb, vm::DictionaryBase::SetMode::Add)) {
|
||||
LOG(ERROR) << "Duplicate extra currency id";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (next_space_pos == td::Slice::npos) {
|
||||
break;
|
||||
}
|
||||
extra_currencies_str.remove_prefix(next_space_pos + 1);
|
||||
}
|
||||
emulator->set_extra_currencies(std::move(dict).extract_root_cell());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tvm_emulator_set_config_object(void* tvm_emulator, void* config) {
|
||||
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
||||
auto global_config = std::shared_ptr<block::Config>(static_cast<block::Config *>(config), config_deleter);
|
||||
|
@ -615,7 +668,7 @@ const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc
|
|||
emulator->set_vm_verbosity_level(0);
|
||||
emulator->set_gas_limit(gas_limit);
|
||||
emulator->set_c7_raw(c7->fetch(0).as_tuple());
|
||||
if (libs.is_empty()) {
|
||||
if (!libs.is_empty()) {
|
||||
emulator->set_libraries(std::move(libs));
|
||||
}
|
||||
auto result = emulator->run_get_method(int(method_id), stack);
|
||||
|
|
|
@ -182,6 +182,14 @@ EMULATOR_EXPORT bool tvm_emulator_set_libraries(void *tvm_emulator, const char *
|
|||
*/
|
||||
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 extra currencies balance
|
||||
* @param tvm_emulator Pointer to TVM emulator
|
||||
* @param extra_currencies String with extra currencies balance in format "currency_id1=balance1 currency_id2=balance2 ..."
|
||||
* @return true in case of success, false in case of error
|
||||
*/
|
||||
EMULATOR_EXPORT bool tvm_emulator_set_extra_currencies(void *tvm_emulator, const char *extra_currencies);
|
||||
|
||||
/**
|
||||
* @brief Set config for TVM emulator
|
||||
* @param tvm_emulator Pointer to TVM emulator
|
||||
|
|
|
@ -17,6 +17,7 @@ _emulator_config_destroy
|
|||
_tvm_emulator_create
|
||||
_tvm_emulator_set_libraries
|
||||
_tvm_emulator_set_c7
|
||||
_tvm_emulator_set_extra_currencies
|
||||
_tvm_emulator_set_config_object
|
||||
_tvm_emulator_set_prev_blocks_info
|
||||
_tvm_emulator_set_gas_limit
|
||||
|
|
|
@ -400,3 +400,58 @@ TEST(Emulator, tvm_emulator) {
|
|||
CHECK(stack_res->depth() == 1);
|
||||
CHECK(stack_res.write().pop_int()->to_long() == init_data.seqno);
|
||||
}
|
||||
|
||||
TEST(Emulator, tvm_emulator_extra_currencies) {
|
||||
void *tvm_emulator = tvm_emulator_create("te6cckEBBAEAHgABFP8A9KQT9LzyyAsBAgFiAgMABtBfBAAJofpP8E8XmGlj", "te6cckEBAQEAAgAAAEysuc0=", 1);
|
||||
std::string addr = "0:" + std::string(64, 'F');
|
||||
tvm_emulator_set_c7(tvm_emulator, addr.c_str(), 1337, 1000, std::string(64, 'F').c_str(), nullptr);
|
||||
CHECK(tvm_emulator_set_extra_currencies(tvm_emulator, "100=20000 200=1"));
|
||||
unsigned method_crc = td::crc16("get_balance");
|
||||
unsigned method_id = (method_crc & 0xffff) | 0x10000;
|
||||
|
||||
auto stack = td::make_ref<vm::Stack>();
|
||||
vm::CellBuilder stack_cb;
|
||||
CHECK(stack->serialize(stack_cb));
|
||||
auto stack_cell = stack_cb.finalize();
|
||||
auto stack_boc = td::base64_encode(std_boc_serialize(stack_cell).move_as_ok());
|
||||
|
||||
std::string tvm_res = tvm_emulator_run_get_method(tvm_emulator, method_id, stack_boc.c_str());
|
||||
|
||||
auto result_json = td::json_decode(td::MutableSlice(tvm_res));
|
||||
auto result = result_json.move_as_ok();
|
||||
auto& result_obj = result.get_object();
|
||||
|
||||
auto success_field = td::get_json_object_field(result_obj, "success", td::JsonValue::Type::Boolean, false);
|
||||
auto success = success_field.move_as_ok().get_boolean();
|
||||
CHECK(success);
|
||||
|
||||
auto stack_field = td::get_json_object_field(result_obj, "stack", td::JsonValue::Type::String, false);
|
||||
auto stack_val = stack_field.move_as_ok();
|
||||
auto& stack_obj = stack_val.get_string();
|
||||
auto stack_res_boc = td::base64_decode(stack_obj);
|
||||
auto stack_res_cell = vm::std_boc_deserialize(stack_res_boc.move_as_ok());
|
||||
td::Ref<vm::Stack> stack_res;
|
||||
auto stack_res_cs = vm::load_cell_slice(stack_res_cell.move_as_ok());
|
||||
CHECK(vm::Stack::deserialize_to(stack_res_cs, stack_res));
|
||||
CHECK(stack_res->depth() == 1);
|
||||
auto tuple = stack_res.write().pop_tuple();
|
||||
CHECK(tuple->size() == 2);
|
||||
|
||||
auto ton_balance = tuple->at(0).as_int();
|
||||
CHECK(ton_balance == 1000);
|
||||
|
||||
auto cell = tuple->at(1).as_cell();
|
||||
auto dict = vm::Dictionary{cell, 32};
|
||||
auto it = dict.begin();
|
||||
std::map<uint32_t, td::RefInt256> ec_balance;
|
||||
while (!it.eof()) {
|
||||
auto id = static_cast<uint32_t>(td::BitArray<32>(it.cur_pos()).to_ulong());
|
||||
auto value_cs = it.cur_value();
|
||||
auto value = block::tlb::t_VarUInteger_32.as_integer(value_cs);
|
||||
ec_balance[id] = value;
|
||||
++it;
|
||||
}
|
||||
CHECK(ec_balance.size() == 2);
|
||||
CHECK(ec_balance[100] == 20000);
|
||||
CHECK(ec_balance[200] == 1);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ td::Result<std::unique_ptr<TransactionEmulator::EmulationResult>> TransactionEmu
|
|||
block::StoragePhaseConfig storage_phase_cfg{&storage_prices};
|
||||
block::ComputePhaseConfig compute_phase_cfg;
|
||||
block::ActionPhaseConfig action_phase_cfg;
|
||||
block::SerializeConfig serialize_config;
|
||||
td::RefInt256 masterchain_create_fee, basechain_create_fee;
|
||||
|
||||
if (!utime) {
|
||||
|
@ -25,11 +26,9 @@ td::Result<std::unique_ptr<TransactionEmulator::EmulationResult>> TransactionEmu
|
|||
utime = (unsigned)std::time(nullptr);
|
||||
}
|
||||
|
||||
auto fetch_res = block::FetchConfigParams::fetch_config_params(*config_, prev_blocks_info_, &old_mparams,
|
||||
&storage_prices, &storage_phase_cfg,
|
||||
&rand_seed_, &compute_phase_cfg,
|
||||
&action_phase_cfg, &masterchain_create_fee,
|
||||
&basechain_create_fee, account.workchain, utime);
|
||||
auto fetch_res = block::FetchConfigParams::fetch_config_params(
|
||||
*config_, prev_blocks_info_, &old_mparams, &storage_prices, &storage_phase_cfg, &rand_seed_, &compute_phase_cfg,
|
||||
&action_phase_cfg, &serialize_config, &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 ");
|
||||
}
|
||||
|
@ -66,7 +65,7 @@ td::Result<std::unique_ptr<TransactionEmulator::EmulationResult>> TransactionEmu
|
|||
return std::make_unique<TransactionEmulator::EmulationExternalNotAccepted>(std::move(vm_log), vm_exit_code, elapsed);
|
||||
}
|
||||
|
||||
if (!trans->serialize()) {
|
||||
if (!trans->serialize(serialize_config)) {
|
||||
return td::Status::Error(-669,"cannot serialize new transaction for smart contract "s + trans->account.addr.to_hex());
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void set_extra_currencies(td::Ref<vm::Cell> extra_currencies) {
|
||||
args_.set_extra_currencies(std::move(extra_currencies));
|
||||
}
|
||||
|
||||
void set_c7_raw(td::Ref<vm::Tuple> c7) {
|
||||
args_.set_c7(std::move(c7));
|
||||
}
|
||||
|
|
|
@ -2227,7 +2227,7 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
// auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
|
||||
vm::GasLimits gas{gas_limit};
|
||||
LOG(DEBUG) << "creating VM";
|
||||
vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
|
||||
vm::VmState vm{code, ton::SUPPORTED_VERSION, std::move(stack), gas, 1, data, vm::VmLog()};
|
||||
vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()),
|
||||
balance)); // tuple with SmartContractInfo
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
|
|
|
@ -32,7 +32,7 @@ void OverlayOutboundFecBroadcast::alarm() {
|
|||
fec_type_.size(), flags_, std::move(X.data), X.id, fec_type_, date_);
|
||||
}
|
||||
|
||||
alarm_timestamp() = td::Timestamp::in(0.010);
|
||||
alarm_timestamp() = td::Timestamp::in(delay_);
|
||||
|
||||
if (seqno_ >= to_send_) {
|
||||
stop();
|
||||
|
@ -46,8 +46,9 @@ void OverlayOutboundFecBroadcast::start_up() {
|
|||
|
||||
OverlayOutboundFecBroadcast::OverlayOutboundFecBroadcast(td::BufferSlice data, td::uint32 flags,
|
||||
td::actor::ActorId<OverlayImpl> overlay,
|
||||
PublicKeyHash local_id)
|
||||
PublicKeyHash local_id, double speed_multiplier)
|
||||
: flags_(flags) {
|
||||
delay_ /= speed_multiplier;
|
||||
CHECK(data.size() <= (1 << 27));
|
||||
local_id_ = local_id;
|
||||
overlay_ = std::move(overlay);
|
||||
|
@ -63,9 +64,10 @@ OverlayOutboundFecBroadcast::OverlayOutboundFecBroadcast(td::BufferSlice data, t
|
|||
}
|
||||
|
||||
td::actor::ActorId<OverlayOutboundFecBroadcast> OverlayOutboundFecBroadcast::create(
|
||||
td::BufferSlice data, td::uint32 flags, td::actor::ActorId<OverlayImpl> overlay, PublicKeyHash local_id) {
|
||||
return td::actor::create_actor<OverlayOutboundFecBroadcast>(td::actor::ActorOptions().with_name("bcast"),
|
||||
std::move(data), flags, overlay, local_id)
|
||||
td::BufferSlice data, td::uint32 flags, td::actor::ActorId<OverlayImpl> overlay, PublicKeyHash local_id,
|
||||
double speed_multiplier) {
|
||||
return td::actor::create_actor<OverlayOutboundFecBroadcast>(
|
||||
td::actor::ActorOptions().with_name("bcast"), std::move(data), flags, overlay, local_id, speed_multiplier)
|
||||
.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ class OverlayOutboundFecBroadcast : public td::actor::Actor {
|
|||
PublicKeyHash local_id_;
|
||||
Overlay::BroadcastDataHash data_hash_;
|
||||
td::uint32 flags_ = 0;
|
||||
double delay_ = 0.010;
|
||||
td::int32 date_;
|
||||
std::unique_ptr<td::fec::Encoder> encoder_;
|
||||
td::actor::ActorId<OverlayImpl> overlay_;
|
||||
|
@ -45,9 +46,9 @@ class OverlayOutboundFecBroadcast : public td::actor::Actor {
|
|||
public:
|
||||
static td::actor::ActorId<OverlayOutboundFecBroadcast> create(td::BufferSlice data, td::uint32 flags,
|
||||
td::actor::ActorId<OverlayImpl> overlay,
|
||||
PublicKeyHash local_id);
|
||||
PublicKeyHash local_id, double speed_multiplier = 1.0);
|
||||
OverlayOutboundFecBroadcast(td::BufferSlice data, td::uint32 flags, td::actor::ActorId<OverlayImpl> overlay,
|
||||
PublicKeyHash local_id);
|
||||
PublicKeyHash local_id, double speed_multiplier = 1.0);
|
||||
|
||||
void alarm() override;
|
||||
void start_up() override;
|
||||
|
|
|
@ -63,7 +63,7 @@ td::actor::ActorOwn<Overlay> Overlay::create_private(
|
|||
return td::actor::create_actor<OverlayImpl>(
|
||||
overlay_actor_name(overlay_id), keyring, adnl, manager, dht_node, local_id, std::move(overlay_id),
|
||||
OverlayType::FixedMemberList, std::move(nodes), std::vector<PublicKeyHash>(), OverlayMemberCertificate{},
|
||||
std::move(callback), std::move(rules), std::move(scope));
|
||||
std::move(callback), std::move(rules), std::move(scope), std::move(opts));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<Overlay> Overlay::create_semiprivate(
|
||||
|
@ -99,6 +99,7 @@ OverlayImpl::OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor
|
|||
overlay_id_ = id_full_.compute_short_id();
|
||||
frequent_dht_lookup_ = opts_.frequent_dht_lookup_;
|
||||
peer_list_.local_member_flags_ = opts_.local_overlay_member_flags_;
|
||||
opts_.broadcast_speed_multiplier_ = std::max(opts_.broadcast_speed_multiplier_, 1e-9);
|
||||
|
||||
VLOG(OVERLAY_INFO) << this << ": creating";
|
||||
|
||||
|
@ -490,7 +491,8 @@ void OverlayImpl::send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td
|
|||
VLOG(OVERLAY_WARNING) << "broadcast source certificate is invalid";
|
||||
return;
|
||||
}
|
||||
OverlayOutboundFecBroadcast::create(std::move(data), flags, actor_id(this), send_as);
|
||||
OverlayOutboundFecBroadcast::create(std::move(data), flags, actor_id(this), send_as,
|
||||
opts_.broadcast_speed_multiplier_);
|
||||
}
|
||||
|
||||
void OverlayImpl::print(td::StringBuilder &sb) {
|
||||
|
|
|
@ -269,6 +269,7 @@ struct OverlayOptions {
|
|||
td::uint32 nodes_to_send_ = 4;
|
||||
td::uint32 propagate_broadcast_to_ = 5;
|
||||
td::uint32 default_permanent_members_flags_ = 0;
|
||||
double broadcast_speed_multiplier_ = 1.0;
|
||||
};
|
||||
|
||||
class Overlays : public td::actor::Actor {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
## 2024.12 Update
|
||||
## 2025.03 Update
|
||||
1. New extracurrency behavior introduced, check [GlobalVersions.md](./doc/GlobalVersions.md#version-10)
|
||||
2. Optmization of validation process, in particular CellStorageStat.
|
||||
3. Flag for speeding up broadcasts in various overlays.
|
||||
4. Fixes for static builds for emulator and tonlibjson
|
||||
5. Improving getstats output: add
|
||||
* Liteserver queries count
|
||||
* Collated/validated blocks count, number of active sessions
|
||||
* Persistent state sizes
|
||||
* Initial sync progress
|
||||
6. Fixes in logging, TON Storage, external message checking, persistent state downloading, UB in tonlib
|
||||
|
||||
1. FunC 0.4.6: Fix in try/catch handling, fixing pure flag for functions stored in variables
|
||||
2. Merging parts of Accelerator: support of specific shard monitoring, archive/liteserver slice format, support for partial liteservers, proxy liteserver, on-demand neighbour queue loading
|
||||
3. Fix of asynchronous cell loading
|
||||
4. Various improvements: caching certificates checks, better block overloading detection, `_malloc` in emulator
|
||||
5. Introduction of telemetry in overlays
|
||||
6. Use non-null local-id for tonlib-LS interaction - mitigates MitM attack.
|
||||
7. Adding `SECP256K1_XONLY_PUBKEY_TWEAK_ADD`, `SETCONTCTRMANY` instructions to TVM (activated by `Config8.version >= 9`)
|
||||
8. Private keys export via validator-engine-console - required for better backups
|
||||
9. Fix proof checking in tonlib, `hash` in `raw.Message` in tonlib_api
|
||||
|
||||
Besides the work of the core team, this update is based on the efforts of OtterSec and LayerZero (FunC), tg:@throwunless (FunC), Aviv Frenkel and Dima Kogan from Fordefi (LS MitM), @hacker-volodya (Tonlib), OKX team (async cell loading), @krigga (emulator)
|
||||
Besides the work of the core team, this update is based on the efforts of @Sild from StonFi(UB in tonlib).
|
||||
|
|
|
@ -251,7 +251,7 @@ void PeerActor::loop_update_init() {
|
|||
}
|
||||
s = s.substr(peer_init_offset_, UPDATE_INIT_BLOCK_SIZE);
|
||||
auto query = create_update_query(ton::create_tl_object<ton::ton_api::storage_updateInit>(
|
||||
td::BufferSlice(s), (int)peer_init_offset_, to_ton_api(node_state)));
|
||||
td::BufferSlice(s), (int)peer_init_offset_ * 8, to_ton_api(node_state)));
|
||||
|
||||
// take care about update_state_query initial state
|
||||
update_state_query_.state = node_state;
|
||||
|
@ -502,11 +502,11 @@ void PeerActor::process_update_peer_parts(const tl_object_ptr<ton_api::storage_U
|
|||
},
|
||||
[&](const ton::ton_api::storage_updateState &state) {},
|
||||
[&](const ton::ton_api::storage_updateInit &init) {
|
||||
LOG(DEBUG) << "Processing updateInit query (offset=" << init.have_pieces_offset_ * 8 << ")";
|
||||
LOG(DEBUG) << "Processing updateInit query (offset=" << init.have_pieces_offset_ << ")";
|
||||
td::Bitset new_bitset;
|
||||
new_bitset.set_raw(init.have_pieces_.as_slice().str());
|
||||
size_t offset = init.have_pieces_offset_ * 8;
|
||||
for (auto size = new_bitset.size(), i = size_t(0); i < size; i++) {
|
||||
size_t offset = init.have_pieces_offset_;
|
||||
for (auto size = new_bitset.size(), i = (size_t)0; i < size; i++) {
|
||||
if (new_bitset.get(i)) {
|
||||
add_piece(static_cast<PartId>(offset + i));
|
||||
}
|
||||
|
|
|
@ -63,7 +63,10 @@ class SpinLock {
|
|||
}
|
||||
|
||||
private:
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-pragma"
|
||||
std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
|
||||
#pragma clang diagnostic pop
|
||||
void unlock() {
|
||||
flag_.clear(std::memory_order_release);
|
||||
}
|
||||
|
|
|
@ -128,6 +128,10 @@ inline Timestamp &operator+=(Timestamp &a, double b) {
|
|||
return a;
|
||||
}
|
||||
|
||||
inline double operator-(const Timestamp &a, const Timestamp &b) {
|
||||
return a.at() - b.at();
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
void store(const Timestamp ×tamp, StorerT &storer) {
|
||||
storer.store_binary(timestamp.at() - Time::now() + Clocks::system());
|
||||
|
|
|
@ -176,7 +176,10 @@ void TsCerr::enterCritical() {
|
|||
void TsCerr::exitCritical() {
|
||||
lock_.clear(std::memory_order_release);
|
||||
}
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-pragma"
|
||||
TsCerr::Lock TsCerr::lock_ = ATOMIC_FLAG_INIT;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
class DefaultLog : public LogInterface {
|
||||
public:
|
||||
|
|
|
@ -264,8 +264,8 @@ class Logger {
|
|||
sb_ << other;
|
||||
return *this;
|
||||
}
|
||||
LambdaPrintHelper<td::Logger> operator<<(const LambdaPrint &) {
|
||||
return LambdaPrintHelper<td::Logger>{*this};
|
||||
LambdaPrintHelper<td::StringBuilder> operator<<(const LambdaPrint &) {
|
||||
return LambdaPrintHelper<td::StringBuilder>{sb_};
|
||||
}
|
||||
|
||||
MutableCSlice as_cslice() {
|
||||
|
@ -343,7 +343,10 @@ class TsLog : public LogInterface {
|
|||
|
||||
private:
|
||||
LogInterface *log_ = nullptr;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-pragma"
|
||||
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
|
||||
#pragma clang diagnostic pop
|
||||
void enter_critical() {
|
||||
while (lock_.test_and_set(std::memory_order_acquire)) {
|
||||
// spin
|
||||
|
|
|
@ -149,7 +149,10 @@ class PollableFdInfo : private ListNode {
|
|||
|
||||
private:
|
||||
NativeFd fd_{};
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-pragma"
|
||||
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
|
||||
#pragma clang diagnostic pop
|
||||
PollFlagsSet flags_;
|
||||
#if TD_PORT_WINDOWS
|
||||
SpinLock observer_lock_;
|
||||
|
|
|
@ -115,8 +115,9 @@ static size_t get_utf8_from_utf16_length(const jchar *p, jsize len) {
|
|||
for (jsize i = 0; i < len; i++) {
|
||||
unsigned int cur = p[i];
|
||||
if ((cur & 0xF800) == 0xD800) {
|
||||
++i;
|
||||
if (i < len) {
|
||||
unsigned int next = p[++i];
|
||||
unsigned int next = p[i];
|
||||
if ((next & 0xFC00) == 0xDC00 && (cur & 0x400) == 0) {
|
||||
result += 4;
|
||||
continue;
|
||||
|
|
|
@ -2,7 +2,7 @@ import "@stdlib/tvm-lowlevel"
|
|||
|
||||
fun pair_first<X, Y>(p: [X, Y]): X asm "FIRST";
|
||||
|
||||
fun one(dummy: tuple) {
|
||||
fun one(dummy: tuple?) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ fun test88(x: int) {
|
|||
}
|
||||
|
||||
@method_id(89)
|
||||
fun test89(last: int) {
|
||||
fun test89(last: int): (int, int, int, int) {
|
||||
var t: tuple = createEmptyTuple();
|
||||
t.tuplePush(1);
|
||||
t.tuplePush(2);
|
||||
|
@ -78,6 +78,17 @@ fun testStartBalanceCodegen2() {
|
|||
return first;
|
||||
}
|
||||
|
||||
global cur: [int, int, int];
|
||||
global next: [int, int, int];
|
||||
|
||||
@method_id(95)
|
||||
fun test95() {
|
||||
cur = [1, 2, 3];
|
||||
next = [2, 3, 4];
|
||||
(cur, next) = (next, [3, 4, 5]);
|
||||
return (cur, next);
|
||||
}
|
||||
|
||||
/**
|
||||
method_id | in | out
|
||||
@testcase | 0 | 101 15 | 100 1
|
||||
|
@ -90,6 +101,7 @@ fun testStartBalanceCodegen2() {
|
|||
@testcase | 89 | 4 | 1 4 1 4
|
||||
@testcase | 91 | | 10
|
||||
@testcase | 92 | | 10 32
|
||||
@testcase | 95 | | [ 2 3 4 ] [ 3 4 5 ]
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
|
@ -104,9 +116,9 @@ fun testStartBalanceCodegen2() {
|
|||
testDumpDontPolluteStack PROC:<{
|
||||
...
|
||||
DUMPSTK
|
||||
x{6d79} PUSHSLICE // f s _9
|
||||
x{6d79} PUSHSLICE // f s '5
|
||||
STRDUMP DROP
|
||||
SBITS // f _11
|
||||
SBITS // f '6
|
||||
}>
|
||||
"""
|
||||
|
||||
|
@ -127,4 +139,21 @@ fun testStartBalanceCodegen2() {
|
|||
FIRST // first
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test95 PROC:<{
|
||||
...
|
||||
next GETGLOB // g_next
|
||||
3 PUSHINT // g_next '14=3
|
||||
4 PUSHINT // g_next '14=3 '15=4
|
||||
5 PUSHINT // g_next '14=3 '15=4 '16=5
|
||||
TRIPLE // '10 '11
|
||||
SWAP
|
||||
cur SETGLOB
|
||||
next SETGLOB
|
||||
cur GETGLOB // g_cur
|
||||
next GETGLOB // g_cur g_next
|
||||
}>
|
||||
"""
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
fun f(a: int, b: int, c: int, d: int, e: int, f: int): (int, int) {
|
||||
// solve a 2x2 linear equation
|
||||
var D: int = a*d - b*c;;;; var Dx: int = e*d-b*f ;;;; var Dy: int = a * f - e * c;
|
||||
__expect_type(D, "int");
|
||||
__expect_type(D*D, "int");
|
||||
__expect_type(calc_phi, "() -> int");
|
||||
return (Dx/D,Dy/D);
|
||||
};;;;
|
||||
|
||||
|
@ -9,6 +12,7 @@ fun calc_phi(): int {
|
|||
repeat (70) { n*=10; };
|
||||
var p= 1;
|
||||
var `q`=1;
|
||||
_=`q`;
|
||||
do {
|
||||
(p,q)=(q,p+q);
|
||||
} while (q <= n); //;;
|
||||
|
@ -27,7 +31,7 @@ fun calc_sqrt2(): int {
|
|||
return mulDivRound(p, n, q);
|
||||
}
|
||||
|
||||
fun calc_root(m: auto): auto {
|
||||
fun calc_root(m: int) {
|
||||
var base: int=1;
|
||||
repeat(70) { base *= 10; }
|
||||
var (a, b, c) = (1,0,-m);
|
||||
|
|
|
@ -7,7 +7,7 @@ fun main(a: int, b: int, c: int, d: int, e: int, f: int): (int, int) {
|
|||
|
||||
@method_id(101)
|
||||
fun testDivMod(x: int, y: int) {
|
||||
return [divMod(x, y), modDiv(x, y), mulDivMod(x, y, 10)];
|
||||
return (divMod(x, y), modDiv(x, y), mulDivMod(x, y, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,5 +18,5 @@ fun testDivMod(x: int, y: int) {
|
|||
@testcase | 0 | 448 -433 -444 792 150012 -356232 | -218 -572
|
||||
@testcase | 0 | -40 -821 433 -734 -721629 -741724 | -206 889
|
||||
@testcase | 0 | -261 -98 -494 868 -166153 733738 | 263 995
|
||||
@testcase | 101 | 112 3 | [ 37 1 1 37 33 6 ]
|
||||
@testcase | 101 | 112 3 | 37 1 1 37 33 6
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@deprecated
|
||||
fun twice(f: auto, x: auto): auto {
|
||||
fun twice(f: int -> int, x: int) {
|
||||
return f (f (x));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,85 +2,114 @@ fun unsafe_tuple<X>(x: X): tuple
|
|||
asm "NOP";
|
||||
|
||||
fun inc(x: int, y: int): (int, int) {
|
||||
return (x + y, y * 10);
|
||||
return (x + y, y * 10);
|
||||
}
|
||||
fun `~inc`(mutate self: int, y: int): int {
|
||||
val (newX, newY) = inc(self, y);
|
||||
self = newX;
|
||||
return newY;
|
||||
val (newX, newY) = inc(self, y);
|
||||
self = newX;
|
||||
return newY;
|
||||
}
|
||||
|
||||
fun eq<X>(v: X): X { return v; }
|
||||
fun eq2(v: (int, int)) { return v; }
|
||||
fun mul2(mutate dest: int, v: int): int { dest = v*2; return dest; }
|
||||
fun multens(mutate self: (int, int), v: (int, int)): (int, int) { var (f, s) = self; var (m1, m2) = v; self = (f*m1, s*m2); return self; }
|
||||
|
||||
@method_id(11)
|
||||
fun test_return(x: int): (int, int, int, int, int, int, int) {
|
||||
return (x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||
return (x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||
}
|
||||
|
||||
@method_id(12)
|
||||
fun test_assign(x: int): (int, int, int, int, int, int, int) {
|
||||
var (x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int) = (x, x.`~inc`(x / 20), x, x=x*2, x, x+=1, x);
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
var (x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int) = (x, x.`~inc`(x / 20), x, x=x*2, x, x+=1, x);
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
}
|
||||
|
||||
@method_id(13)
|
||||
fun test_tuple(x: int): tuple {
|
||||
var t: tuple = unsafe_tuple([x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x]);
|
||||
return t;
|
||||
var t: tuple = unsafe_tuple([x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x]);
|
||||
return t;
|
||||
}
|
||||
|
||||
@method_id(14)
|
||||
fun test_tuple_assign(x: int): (int, int, int, int, int, int, int) {
|
||||
var [x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int] = [x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x];
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
var [x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int] = [x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x];
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
}
|
||||
|
||||
fun foo1(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int) {
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
}
|
||||
|
||||
@method_id(15)
|
||||
fun test_call_1(x: int): (int, int, int, int, int, int, int) {
|
||||
return foo1(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||
return foo1(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||
}
|
||||
|
||||
fun foo2(x1: int, x2: int, x3456: (int, int, int, int), x7: int): (int, int, int, int, int, int, int) {
|
||||
var (x3: int, x4: int, x5: int, x6: int) = x3456;
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
var (x3: int, x4: int, x5: int, x6: int) = x3456;
|
||||
return (x1, x2, x3, x4, x5, x6, x7);
|
||||
}
|
||||
|
||||
@method_id(16)
|
||||
fun test_call_2(x: int): (int, int, int, int, int, int, int) {
|
||||
return foo2(x, x.`~inc`(x / 20), (x, x = x * 2, x, x += 1), x);
|
||||
return foo2(x, x.`~inc`(x / 20), (x, x = x * 2, x, x += 1), x);
|
||||
}
|
||||
|
||||
fun asm_func(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int)
|
||||
asm
|
||||
(x4 x5 x6 x7 x1 x2 x3->0 1 2 3 4 5 6) "NOP";
|
||||
asm (x4 x5 x6 x7 x1 x2 x3->0 1 2 3 4 5 6) "NOP";
|
||||
|
||||
@method_id(17)
|
||||
fun test_call_asm_old(x: int): (int, int, int, int, int, int, int) {
|
||||
return asm_func(x, x += 1, x, x, x.`~inc`(x / 20), x, x = x * 2);
|
||||
return asm_func(x, x += 1, x, x, x.`~inc`(x / 20), x, x = x * 2);
|
||||
}
|
||||
|
||||
@method_id(18)
|
||||
fun test_call_asm_new(x: int): (int, int, int, int, int, int, int) {
|
||||
return asm_func(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||
return asm_func(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||
}
|
||||
|
||||
global xx: int;
|
||||
@method_id(19)
|
||||
fun test_global(x: int): (int, int, int, int, int, int, int) {
|
||||
xx = x;
|
||||
return (xx, xx.`~inc`(xx / 20), xx, xx = xx * 2, xx, xx += 1, xx);
|
||||
fun test_global(x: int) {
|
||||
xx = x;
|
||||
return (x, xx, xx.`~inc`(xx / 20), eq(xx += (x *= 0)), xx = xx * 2, xx, xx += 1, xx, x);
|
||||
}
|
||||
|
||||
@method_id(20)
|
||||
fun test_if_else(x: int): (int, int, int, int, int) {
|
||||
if (x > 10) {
|
||||
return (x.`~inc`(8), x + 1, x = 1, x <<= 3, x);
|
||||
} else {
|
||||
xx = 9;
|
||||
return (x, x.`~inc`(-4), x.`~inc`(-1), x >= 1, x = x + xx);
|
||||
}
|
||||
if (x > 10) {
|
||||
return (x.`~inc`(8), x + 1, x = 1, x <<= 3, x);
|
||||
} else {
|
||||
xx = 9;
|
||||
return (x, x.`~inc`(-4), x.`~inc`(-1), (x >= 1) as int, x = x + xx);
|
||||
}
|
||||
}
|
||||
|
||||
@method_id(21)
|
||||
fun test_assign_with_inner(x: int) {
|
||||
var result = (x, x += 10, [x, x += 20, eq(x -= 50), x], eq2((x, x *= eq(x /= 2))));
|
||||
return result;
|
||||
}
|
||||
|
||||
@method_id(22)
|
||||
fun test_assign_with_mutate(x: int) {
|
||||
var (result, _) = ((x, mul2(mutate x, x += 5), x.`~inc`(mul2(mutate x, x)), x), 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@method_id(23)
|
||||
fun test_assign_tensor(x: (int, int)) {
|
||||
var fs = (0, 0);
|
||||
return (x, x = (20, 30), fs = x.multens((1, 2)), fs.multens(multens(mutate x, (-1, -1))), x, fs);
|
||||
}
|
||||
|
||||
global fs: (int, int);
|
||||
@method_id(24)
|
||||
fun test_assign_tensor_global(x: (int, int)) {
|
||||
fs = (0, 0);
|
||||
return (x, x = (20, 30), fs = x.multens((1, 2)), fs.multens(multens(mutate x, (-1, -1))), x, fs);
|
||||
}
|
||||
|
||||
fun main() {
|
||||
|
@ -96,9 +125,13 @@ fun main() {
|
|||
@testcase | 16 | 100 | 100 50 105 210 210 211 211
|
||||
@testcase | 17 | 100 | 101 50 106 212 100 101 101
|
||||
@testcase | 18 | 100 | 210 210 211 211 100 50 105
|
||||
@testcase | 19 | 100 | 100 50 105 210 210 211 211
|
||||
@testcase | 19 | 100 | 100 100 50 105 210 210 211 211 0
|
||||
@testcase | 20 | 80 | 80 89 1 8 8
|
||||
@testcase | 20 | 9 | 9 -40 -10 -1 13
|
||||
@testcase | 21 | 100 | 100 110 [ 110 130 80 80 ] 80 3200
|
||||
@testcase | 22 | 100 | 100 210 4200 630
|
||||
@testcase | 23 | 1 1 | 1 1 20 30 20 60 -400 -3600 -20 -60 -400 -3600
|
||||
@testcase | 24 | 1 1 | 1 1 20 30 20 60 -400 -3600 -20 -60 -400 -3600
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
|
@ -107,5 +140,12 @@ fun main() {
|
|||
inc CALLDICT // self newY
|
||||
}>
|
||||
"""
|
||||
@code_hash 97139400653362069936987769894397430077752335662822462908581556703209313861576
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test_assign_tensor_global PROC:<{
|
||||
// x.0 x.1
|
||||
"""
|
||||
|
||||
@code_hash 61280273714870328160131559159866470128402169974050439159015534193532598351244
|
||||
*/
|
||||
|
|
250
tolk-tester/tests/assignment-tests.tolk
Normal file
250
tolk-tester/tests/assignment-tests.tolk
Normal file
|
@ -0,0 +1,250 @@
|
|||
fun extractFromTypedTuple(params: [int]) {
|
||||
var [payload: int] = params;
|
||||
return payload + 10;
|
||||
}
|
||||
|
||||
@method_id(101)
|
||||
fun test101(x: int) {
|
||||
var params = [x];
|
||||
return extractFromTypedTuple(params);
|
||||
}
|
||||
|
||||
fun autoInferIntNull(x: int) {
|
||||
if (x > 10) { return null; }
|
||||
return x;
|
||||
}
|
||||
|
||||
fun typesAsIdentifiers(builder: builder) {
|
||||
var int = 1;
|
||||
var cell = builder.endCell();
|
||||
var slice = cell.beginParse();
|
||||
{
|
||||
var cell: cell = cell;
|
||||
var tuple: tuple = createEmptyTuple();
|
||||
var bool: bool = tuple.tupleAt<int>(0) > 0;
|
||||
}
|
||||
return int;
|
||||
}
|
||||
|
||||
global callOrder: tuple;
|
||||
|
||||
fun getTensor_12() {
|
||||
callOrder.tuplePush(100);
|
||||
return (1, 2);
|
||||
}
|
||||
fun getTensor_1X(x: int) {
|
||||
callOrder.tuplePush(101);
|
||||
return (1, x);
|
||||
}
|
||||
fun getTuple_12() {
|
||||
callOrder.tuplePush(110);
|
||||
return [1, 2];
|
||||
}
|
||||
fun getTuple_1X(x: int) {
|
||||
callOrder.tuplePush(111);
|
||||
return [1, x];
|
||||
}
|
||||
fun getUntypedTuple_12() {
|
||||
callOrder.tuplePush(120);
|
||||
var t = createEmptyTuple(); t.tuplePush(1); t.tuplePush(2);
|
||||
return t;
|
||||
}
|
||||
fun getUntypedTuple_1X(x: int) {
|
||||
callOrder.tuplePush(121);
|
||||
var t = createEmptyTuple(); t.tuplePush(1); t.tuplePush(x);
|
||||
return t;
|
||||
}
|
||||
fun getIntValue5() {
|
||||
callOrder.tuplePush(10);
|
||||
return 5;
|
||||
}
|
||||
fun getIntValueX(x: int) {
|
||||
callOrder.tuplePush(11);
|
||||
return x;
|
||||
}
|
||||
|
||||
@method_id(102)
|
||||
fun test102() {
|
||||
callOrder = createEmptyTuple();
|
||||
var x = 0;
|
||||
getTensor_12().0 = getIntValue5();
|
||||
getTensor_1X(5).1 = getIntValue5();
|
||||
getTensor_1X(x = 10).0 = getIntValueX(x);
|
||||
return (callOrder, x);
|
||||
}
|
||||
|
||||
@method_id(103)
|
||||
fun test103() {
|
||||
callOrder = createEmptyTuple();
|
||||
var x = 0;
|
||||
getTuple_12().0 = getIntValue5();
|
||||
getTuple_1X(5).1 = getIntValue5();
|
||||
getTuple_1X(x = 10).0 = getIntValueX(x);
|
||||
return (callOrder, x);
|
||||
}
|
||||
|
||||
@method_id(104)
|
||||
fun test104() {
|
||||
callOrder = createEmptyTuple();
|
||||
var x = 0;
|
||||
getUntypedTuple_12().0 = getIntValue5();
|
||||
getUntypedTuple_1X(5).1 = getIntValue5();
|
||||
getUntypedTuple_1X(x = 10).0 = getIntValueX(x);
|
||||
return (callOrder, x);
|
||||
}
|
||||
|
||||
@method_id(105)
|
||||
fun test105() {
|
||||
callOrder = createEmptyTuple();
|
||||
getTensor_12().0 = getTensor_1X(getIntValue5()).1 = getIntValueX(getTensor_12().1);
|
||||
return callOrder;
|
||||
}
|
||||
|
||||
@method_id(106)
|
||||
fun test106() {
|
||||
callOrder = createEmptyTuple();
|
||||
getTuple_12().0 = getTuple_1X(getIntValue5()).1 = getIntValueX(getTuple_12().1);
|
||||
return callOrder;
|
||||
}
|
||||
|
||||
global t107: (int, int);
|
||||
|
||||
@method_id(107)
|
||||
fun test107() {
|
||||
((t107 = (1, 2)).0, (t107 = (3, 4)).1) = (5, 6);
|
||||
return t107;
|
||||
}
|
||||
|
||||
global g108: int;
|
||||
fun assertEq(a: int, b: int) {
|
||||
assert(a == b, 10);
|
||||
return b;
|
||||
}
|
||||
|
||||
@method_id(108)
|
||||
fun test108() {
|
||||
callOrder = createEmptyTuple();
|
||||
g108 = 0;
|
||||
getTensor_1X(g108 = 8).1 = assertEq(g108, 8);
|
||||
return (callOrder, g108);
|
||||
}
|
||||
|
||||
@method_id(109)
|
||||
fun test109() {
|
||||
callOrder = createEmptyTuple();
|
||||
var x = 0;
|
||||
[getTuple_12().0, getTuple_1X(x = getIntValue5()).1, getTuple_1X(x += 10).0] = [getIntValue5(), getIntValue5(), getIntValueX(x)];
|
||||
return (callOrder, x);
|
||||
}
|
||||
|
||||
global g110: int;
|
||||
global t110: (int, int);
|
||||
|
||||
@method_id(110)
|
||||
fun test110() {
|
||||
callOrder = createEmptyTuple();
|
||||
var xy = [0, 0];
|
||||
[xy.0, getTuple_1X(g110 = 8).0] = [g110 += 5, getIntValueX(g110 += 10)];
|
||||
[xy.1, getTuple_1X((t110 = (8, 9)).0).1] = [t110.0 += 5, getIntValueX(t110.1 += 10)];
|
||||
return (xy, callOrder, g110, t110);
|
||||
}
|
||||
|
||||
@method_id(111)
|
||||
fun test111() {
|
||||
callOrder = createEmptyTuple();
|
||||
var z = -1;
|
||||
var xy = [0, z = 0];
|
||||
var rhs = [getIntValueX(xy.1 += 10), xy.1, xy.0, z += 50];
|
||||
[xy.0, getTuple_1X(g110 = 8 + getIntValueX(xy.1)).0, xy.1, z] = rhs;
|
||||
return (xy, g110, callOrder, z);
|
||||
}
|
||||
|
||||
@method_id(112)
|
||||
fun test112() {
|
||||
var xy = [1, 2];
|
||||
((((xy))).0, ((xy.1))) = ((xy).1, ((xy.0)));
|
||||
return xy;
|
||||
}
|
||||
|
||||
@method_id(113)
|
||||
fun test113() {
|
||||
var (a, t, z) = (1, [2,3], (-1,-1));
|
||||
(a, t, a, z, t.1, z.1) = (10, [a,12], 13, (a, t.1), 14, t.1);
|
||||
return (a, t, z);
|
||||
}
|
||||
|
||||
global g114: int;
|
||||
global t114: [int, int];
|
||||
global z114: (int, int);
|
||||
|
||||
@method_id(114)
|
||||
fun test114() {
|
||||
g114 = 1;
|
||||
t114 = [2, 3];
|
||||
(g114, t114, g114, z114, t114.1, z114.1) = (10, [g114,12], 13, (g114, t114.1), 14, t114.1);
|
||||
return (g114, t114, z114);
|
||||
}
|
||||
|
||||
@method_id(115)
|
||||
fun test115() {
|
||||
callOrder = createEmptyTuple();
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
[getTensor_1X(x = 5).0, y] = getTuple_1X(x = 9);
|
||||
return (callOrder, x, y);
|
||||
}
|
||||
|
||||
@method_id(116)
|
||||
fun test116() {
|
||||
var (a,b,c,d) = (0,0,0,0);
|
||||
var rhs = [1, 2, 3, 4];
|
||||
var rhs2 = ([a,b,c,d] = rhs);
|
||||
__expect_type(rhs2, "[int, int, int, int]");
|
||||
return (a, b, c, d, rhs2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun main(value: int) {
|
||||
var (x: int?, y) = (autoInferIntNull(value), autoInferIntNull(value * 2));
|
||||
if (x == null && y == null) { return null; }
|
||||
return x == null || y == null ? -1 : x! + y!;
|
||||
}
|
||||
|
||||
/**
|
||||
@testcase | 0 | 3 | 9
|
||||
@testcase | 0 | 6 | -1
|
||||
@testcase | 0 | 11 | (null)
|
||||
@testcase | 101 | 78 | 88
|
||||
@testcase | 102 | | [ 100 10 101 10 101 11 ] 10
|
||||
@testcase | 103 | | [ 110 10 111 10 111 11 ] 10
|
||||
@testcase | 104 | | [ 120 10 121 10 121 11 ] 10
|
||||
@testcase | 105 | | [ 100 10 101 100 11 ]
|
||||
@testcase | 106 | | [ 110 10 111 110 11 ]
|
||||
@testcase | 107 | | 3 4
|
||||
@testcase | 108 | | [ 101 ] 8
|
||||
@testcase | 109 | | [ 110 10 111 111 10 10 11 ] 15
|
||||
@testcase | 110 | | [ 13 13 ] [ 111 11 111 11 ] 23 13 19
|
||||
@testcase | 111 | | [ 10 0 ] 18 [ 11 11 111 ] 50
|
||||
@testcase | 112 | | [ 2 1 ]
|
||||
@testcase | 113 | | 13 [ 1 14 ] 1 3
|
||||
@testcase | 114 | | 13 [ 1 14 ] 1 3
|
||||
@testcase | 115 | | [ 101 111 ] 9 9
|
||||
@testcase | 116 | | 1 2 3 4 [ 1 2 3 4 ]
|
||||
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test116 PROC:<{
|
||||
//
|
||||
1 PUSHINT // '10=1
|
||||
2 PUSHINT // '10=1 '11=2
|
||||
3 PUSHINT // '10=1 '11=2 '12=3
|
||||
4 PUSHINT // '10=1 '11=2 '12=3 '13=4
|
||||
4 TUPLE // rhs
|
||||
DUP // rhs rhs
|
||||
4 UNTUPLE // rhs2 a b c d
|
||||
4 ROLL // a b c d rhs2
|
||||
}>
|
||||
"""
|
||||
*/
|
|
@ -1,20 +1,20 @@
|
|||
fun lshift(): int {
|
||||
fun lshift(): bool {
|
||||
return (1 << 0) == 1;
|
||||
}
|
||||
|
||||
fun rshift(): int {
|
||||
fun rshift(): bool {
|
||||
return (1 >> 0) == 1;
|
||||
}
|
||||
|
||||
fun lshift_var(i: int): int {
|
||||
fun lshift_var(i: int): bool {
|
||||
return (1 << i) == 1;
|
||||
}
|
||||
|
||||
fun rshift_var(i: int): int {
|
||||
fun rshift_var(i: int): bool {
|
||||
return (1 >> i) == 1;
|
||||
}
|
||||
|
||||
fun main(x: int): int {
|
||||
fun main(x: int): bool {
|
||||
if (x == 0) {
|
||||
return lshift();
|
||||
} else if (x == 1) {
|
||||
|
@ -31,12 +31,71 @@ fun main(x: int): int {
|
|||
}
|
||||
|
||||
@method_id(11)
|
||||
fun is_claimed(index: int): int {
|
||||
fun is_claimed(index: int): bool {
|
||||
var claim_bit_index: int = index % 256;
|
||||
var mask: int = 1 << claim_bit_index;
|
||||
return (255 & mask) == mask;
|
||||
}
|
||||
|
||||
@method_id(12)
|
||||
fun bit_not(i: int, b: bool): (int, bool, bool, bool, int, bool) {
|
||||
var i2 = ~i;
|
||||
var b2 = !b;
|
||||
var (i3: int, b3: bool) = (i2, b2);
|
||||
return (i3, b3, !i, !b, ~~~i, !!!b);
|
||||
}
|
||||
|
||||
@method_id(13)
|
||||
fun boolWithBitwiseConst() {
|
||||
var found = true;
|
||||
return (found & false, found | true, found ^ true, found & found);
|
||||
}
|
||||
|
||||
global g14: int;
|
||||
fun getBool() { return (g14 += 1) > 2; }
|
||||
|
||||
@method_id(14)
|
||||
fun boolWithBitwise(b: bool) {
|
||||
g14 = 0;
|
||||
return (b & getBool(), !b & getBool(), b | getBool(), !b | getBool(), b ^ getBool(), !b & getBool(), g14);
|
||||
}
|
||||
|
||||
@method_id(15)
|
||||
fun boolWithBitwiseSet(b1: bool, b2: bool) {
|
||||
b1 &= b2;
|
||||
b2 |= true;
|
||||
b1 |= b1 == false;
|
||||
b2 ^= (b1 ^= b2);
|
||||
return (b1, b2);
|
||||
}
|
||||
|
||||
@method_id(16)
|
||||
fun testDoUntilCodegen(i: bool, n: int) {
|
||||
var cnt = 0;
|
||||
do { cnt += 1; } while (i);
|
||||
do { cnt += 1; } while (!!i);
|
||||
do { cnt += 1; } while (n);
|
||||
return (cnt, !i, !n);
|
||||
}
|
||||
|
||||
@method_id(17)
|
||||
fun testConstNegateCodegen() {
|
||||
return (!0, !1, !true, !false, !!true, !!false);
|
||||
}
|
||||
|
||||
@method_id(18)
|
||||
fun testBoolNegateOptimized(x: bool) {
|
||||
return (x, !x, !!x, !!!x, !!!!true);
|
||||
}
|
||||
|
||||
fun eqX(x: bool) { return x; }
|
||||
|
||||
@method_id(19)
|
||||
fun testBoolCompareOptimized(x: bool) {
|
||||
return (x == true, x != true, eqX(x) == false, eqX(x) != false, !!(x == !false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
method_id | in | out
|
||||
|
@ -50,4 +109,96 @@ fun is_claimed(index: int): int {
|
|||
@testcase | 11 | 1 | -1
|
||||
@testcase | 11 | 256 | -1
|
||||
@testcase | 11 | 8 | 0
|
||||
@testcase | 12 | 0 0 | -1 -1 -1 -1 -1 -1
|
||||
@testcase | 12 | -1 -1 | 0 0 0 0 0 0
|
||||
@testcase | 12 | 7 0 | -8 -1 0 -1 -8 -1
|
||||
@testcase | 14 | -1 | 0 0 -1 -1 0 0 6
|
||||
@testcase | 14 | 0 | 0 0 -1 -1 -1 -1 6
|
||||
@testcase | 15 | -1 -1 | 0 -1
|
||||
@testcase | 15 | -1 0 | 0 -1
|
||||
@testcase | 16 | 0 0 | 3 -1 -1
|
||||
@testcase | 17 | | -1 0 0 -1 -1 0
|
||||
@testcase | 18 | 0 | 0 -1 0 -1 -1
|
||||
@testcase | 18 | -1 | -1 0 -1 0 -1
|
||||
@testcase | 19 | 0 | 0 -1 -1 0 0
|
||||
@testcase | 19 | -1 | -1 0 0 -1 -1
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
boolWithBitwiseConst PROC:<{
|
||||
//
|
||||
0 PUSHINT // '3
|
||||
-1 PUSHINT // '3 '5
|
||||
0 PUSHINT // '3 '5 '7
|
||||
-1 PUSHINT // '3 '5 '7 '8
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
testDoUntilCodegen PROC:<{
|
||||
// i n
|
||||
0 PUSHINT // i n cnt=0
|
||||
UNTIL:<{
|
||||
INC // i n cnt
|
||||
s2 PUSH // i n cnt i
|
||||
NOT // i n cnt '6
|
||||
}> // i n cnt
|
||||
UNTIL:<{
|
||||
INC // i n cnt
|
||||
s2 PUSH // i n cnt i
|
||||
NOT // i n cnt '9
|
||||
}> // i n cnt
|
||||
UNTIL:<{
|
||||
INC // i n cnt
|
||||
OVER // i n cnt n
|
||||
0 EQINT // i n cnt '12
|
||||
}> // i n cnt
|
||||
s0 s2 XCHG // cnt n i
|
||||
NOT // cnt n '13
|
||||
SWAP // cnt '13 n
|
||||
0 EQINT // cnt '13 '14
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
testConstNegateCodegen PROC:<{
|
||||
//
|
||||
TRUE // '0
|
||||
FALSE // '0 '1
|
||||
FALSE // '0 '1 '2
|
||||
TRUE // '0 '1 '2 '3
|
||||
TRUE // '0 '1 '2 '3 '4
|
||||
FALSE // '0 '1 '2 '3 '4 '5
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
testBoolNegateOptimized PROC:<{
|
||||
// x
|
||||
DUP // x x
|
||||
NOT // x '1
|
||||
OVER // x '1 x
|
||||
NOT // x '1 '2
|
||||
s2 s(-1) PUXC
|
||||
TRUE // x '1 x '2 '3
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
testBoolCompareOptimized PROC:<{
|
||||
// x
|
||||
DUP // x x
|
||||
NOT // x '1
|
||||
OVER // x '1 x
|
||||
eqX CALLDICT // x '1 '2
|
||||
NOT // x '1 '3
|
||||
s2 PUSH // x '1 '3 x
|
||||
eqX CALLDICT // x '1 '3 '4
|
||||
s3 PUSH // x '1 '3 '4 x
|
||||
}>
|
||||
"""
|
||||
*/
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
global op: (int, int) -> int;
|
||||
|
||||
fun check_assoc(a: int, b: int, c: int): int {
|
||||
fun check_assoc(a: int, b: int, c: int): bool {
|
||||
return op(op(a, b), c) == op(a, op(b, c));
|
||||
}
|
||||
|
||||
fun unnamed_args(_: int, _: slice, _: auto): auto {
|
||||
fun unnamed_args(_: int, _: slice, _: int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fun main(x: int, y: int, z: int): int {
|
||||
fun main(x: int, y: int, z: int): bool? {
|
||||
op = `_+_`;
|
||||
if (0) { return null; }
|
||||
return check_assoc(x, y, z);
|
||||
}
|
||||
|
||||
@method_id(101)
|
||||
fun test101(x: int, z: int): auto {
|
||||
fun test101(x: int, z: int) {
|
||||
return unnamed_args(x, "asdf", z);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
fun check_assoc(op: auto, a: int, b: int, c: int) {
|
||||
fun check_assoc(op: (int, int) -> int, a: int, b: int, c: int) {
|
||||
return op(op(a, b), c) == op(a, op(b, c));
|
||||
}
|
||||
|
||||
fun main(x: int, y: int, z: int): int {
|
||||
fun main(x: int, y: int, z: int): bool {
|
||||
return check_assoc(`_+_`, x, y, z);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ fun test1(): [int,int,int,int,int] {
|
|||
fun test2(): [int,int,int] {
|
||||
var b: builder = beginCell().myStoreInt(1, 32);
|
||||
b = b.myStoreInt(2, 32);
|
||||
b.myStoreInt(3, 32);
|
||||
// operator ! here and below is used just for testing purposes, it doesn't affect the result
|
||||
b!.myStoreInt(3, 32);
|
||||
|
||||
var cs: slice = b.endCell().beginParse();
|
||||
var one: int = cs.myLoadInt(32);
|
||||
|
@ -43,14 +44,14 @@ fun test2(): [int,int,int] {
|
|||
|
||||
@method_id(103)
|
||||
fun test3(ret: int): int {
|
||||
val same: int = beginCell().storeUint(ret,32).endCell().beginParse().loadUint(32);
|
||||
val same: int = beginCell()!.storeUint(ret,32).endCell().beginParse().loadUint(32);
|
||||
return same;
|
||||
}
|
||||
|
||||
@method_id(104)
|
||||
fun test4(): [int,int] {
|
||||
var b: builder = beginCell().myStoreInt(1, 32);
|
||||
b = b.storeInt(2, 32).storeInt(3, 32);
|
||||
var b: builder = (beginCell() as builder).myStoreInt(1, 32);
|
||||
b = b!.storeInt(2, 32)!.storeInt(3, 32);
|
||||
|
||||
var cs: slice = b.endCell().beginParse();
|
||||
var (one, _, three) = (cs.getFirstBits(32).loadUint(32), cs.skipBits(64), cs.load_u32());
|
||||
|
@ -116,7 +117,7 @@ fun test10() {
|
|||
fun test11() {
|
||||
var s: slice = beginCell().storeInt(1, 32).storeInt(2, 32).storeInt(3, 32).storeInt(4, 32).storeInt(5, 32).storeInt(6, 32).storeInt(7, 32).endCell().beginParse();
|
||||
var size1 = getRemainingBitsCount(s);
|
||||
s.skipBits(32);
|
||||
s!.skipBits(32);
|
||||
var s1: slice = s.getFirstBits(64);
|
||||
var n1 = s1.loadInt(32);
|
||||
var size2 = getRemainingBitsCount(s);
|
||||
|
@ -162,8 +163,8 @@ fun test13() {
|
|||
}
|
||||
|
||||
@method_id(114)
|
||||
fun test110(x: int) {
|
||||
var s = beginCell().storeBool(x < 0).storeBool(0).storeBool(x).endCell().beginParse();
|
||||
fun test110(x: bool) {
|
||||
var s = beginCell().storeBool(x == true).storeBool(false).storeBool(x).endCell().beginParse();
|
||||
return (s.loadBool(), s.loadBool(), s.loadBool());
|
||||
}
|
||||
|
||||
|
@ -179,15 +180,15 @@ fun test111() {
|
|||
if (s.addressIsNone()) {
|
||||
s.skipBits(2);
|
||||
}
|
||||
if (s.loadBool() == 0) {
|
||||
assert(s.loadBool() == 0) throw 444;
|
||||
if (s.loadBool() == false) {
|
||||
assert(!s.loadBool()) throw 444;
|
||||
s.skipBouncedPrefix();
|
||||
}
|
||||
var op2 = s.loadMessageOp();
|
||||
var q2 = s.loadMessageQueryId();
|
||||
s.skipBits(64);
|
||||
s.assertEndOfSlice();
|
||||
assert(isMessageBounced(0x001)) throw 444;
|
||||
assert(isMessageBounced(0x001) && !isMessageBounced(0x002)) throw 444;
|
||||
return (op1, q1, op2, q2);
|
||||
}
|
||||
|
||||
|
@ -216,16 +217,16 @@ Note, that since 'compute-asm-ltr' became on be default, chaining methods codege
|
|||
"""
|
||||
test6 PROC:<{
|
||||
//
|
||||
NEWC // _1
|
||||
1 PUSHINT // _1 _2=1
|
||||
SWAP // _2=1 _1
|
||||
32 STU // _0
|
||||
2 PUSHINT // _0 _6=2
|
||||
SWAP // _6=2 _0
|
||||
32 STU // _0
|
||||
3 PUSHINT // _0 _10=3
|
||||
SWAP // _10=3 _0
|
||||
32 STU // _0
|
||||
NEWC // '0
|
||||
1 PUSHINT // '0 '1=1
|
||||
SWAP // '1=1 '0
|
||||
32 STU // '0
|
||||
2 PUSHINT // '0 '4=2
|
||||
SWAP // '4=2 '0
|
||||
32 STU // '0
|
||||
3 PUSHINT // '0 '7=3
|
||||
SWAP // '7=3 '0
|
||||
32 STU // '0
|
||||
}>
|
||||
"""
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@method_id(101)
|
||||
fun test1(): int {
|
||||
var x = false;
|
||||
if (x == true) {
|
||||
var x: int = false as int;
|
||||
if (x == true as int) {
|
||||
x= 100500;
|
||||
}
|
||||
return x;
|
||||
|
@ -35,7 +35,7 @@ Below, I just give examples of @fif_codegen tag:
|
|||
"""
|
||||
main PROC:<{
|
||||
// s
|
||||
17 PUSHINT // s _3=17
|
||||
17 PUSHINT // s '3=17
|
||||
OVER // s z=17 t
|
||||
WHILE:<{
|
||||
...
|
||||
|
@ -63,7 +63,7 @@ main PROC:<{
|
|||
@fif_codegen
|
||||
"""
|
||||
OVER
|
||||
0 GTINT // s z t _5
|
||||
0 GTINT // s z t '5
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
|
@ -83,7 +83,7 @@ FALSE
|
|||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen NOT // _8
|
||||
@fif_codegen NOT // '8
|
||||
@fif_codegen main PROC:<{
|
||||
|
||||
@fif_codegen_avoid PROCINLINE
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue