mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 19:22:37 +00:00
Merge pull request #1016 from ton-blockchain/testnet
Merge developer branch
This commit is contained in:
commit
5c392e0f2d
89 changed files with 2313 additions and 706 deletions
25
.github/workflows/build-ton-macos-arm64-shared.yml
vendored
Normal file
25
.github/workflows/build-ton-macos-arm64-shared.yml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
name: MacOS TON build (shared, 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: |
|
||||
cp assembly/native/build-macos-shared.sh .
|
||||
chmod +x build-macos-shared.sh
|
||||
./build-macos-shared.sh -t -a
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-binaries-macos-14
|
||||
path: artifacts
|
107
.github/workflows/create-release.yml
vendored
107
.github/workflows/create-release.yml
vendored
|
@ -35,6 +35,14 @@ jobs:
|
|||
workflow_conclusion: success
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download Mac arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: ton-arm64-macos.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
skip_unpack: true
|
||||
|
||||
- name: Download and unzip Mac x86-64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
|
@ -43,6 +51,14 @@ jobs:
|
|||
workflow_conclusion: success
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download and unzip arm64 artifacts
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: ton-arm64-macos.yml
|
||||
path: artifacts
|
||||
workflow_conclusion: success
|
||||
skip_unpack: false
|
||||
|
||||
- name: Download Windows artifacts
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
|
@ -297,6 +313,97 @@ jobs:
|
|||
asset_name: tonlib-cli-mac-x86-64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
|
||||
# mac arm64
|
||||
|
||||
- name: Upload Mac arm64 artifacts
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries.zip
|
||||
asset_name: ton-mac-arm64.zip
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - fift
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/fift
|
||||
asset_name: fift-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - func
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/func
|
||||
asset_name: func-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - lite-client
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/lite-client
|
||||
asset_name: lite-client-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - rldp-http-proxy
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/rldp-http-proxy
|
||||
asset_name: rldp-http-proxy-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - http-proxy
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/http-proxy
|
||||
asset_name: http-proxy-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - storage-daemon-cli
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/storage-daemon-cli
|
||||
asset_name: storage-daemon-cli-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - storage-daemon
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/storage-daemon
|
||||
asset_name: storage-daemon-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - tonlibjson
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/libtonlibjson.dylib
|
||||
asset_name: tonlibjson-mac-arm64.dylib
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - libemulator
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/libemulator.dylib
|
||||
asset_name: libemulator-mac-arm64.dylib
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Upload Mac arm64 single artifact - tonlib-cli
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: artifacts/ton-arm64-macos-binaries/tonlib-cli
|
||||
asset_name: tonlib-cli-mac-arm64
|
||||
tag: ${{ steps.tag.outputs.TAG }}
|
||||
|
||||
# linux x86-64
|
||||
|
||||
- name: Upload Linux x86-64 artifacts
|
||||
|
|
37
.github/workflows/ton-arm64-macos.yml
vendored
Normal file
37
.github/workflows/ton-arm64-macos.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
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: |
|
||||
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
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-arm64-macos-binaries
|
||||
path: artifacts
|
13
Changelog.md
13
Changelog.md
|
@ -1,3 +1,16 @@
|
|||
## 2024.06 Update
|
||||
|
||||
1. Make Jemalloc default allocator
|
||||
2. Add candidate broadcasting and caching
|
||||
3. Limit per address speed for external messages broadcast by reasonably large number
|
||||
4. Overlay improvements: fix dropping peers in small custom overlays, fix wrong certificate on missed keyblocks
|
||||
5. Extended statistics and logs for celldb usage, session stats, persistent state serialization
|
||||
6. Tonlib and explorer fixes
|
||||
7. Flags for precize control of Celldb: `--celldb-cache-size`, `--celldb-direct-io` and `--celldb-preload-all`
|
||||
8. Add valiator-console command to stop persistent state serialization
|
||||
9. Use `@` path separator for defining include path in fift and create-state utilities on Windows only.
|
||||
|
||||
|
||||
## 2024.04 Update
|
||||
|
||||
1. Emulator: Single call optimized runGetMethod added
|
||||
|
|
|
@ -15,8 +15,6 @@ while getopts 't' flag; do
|
|||
done
|
||||
|
||||
cp assembly/nix/linux-arm64* .
|
||||
cp assembly/nix/microhttpd.nix .
|
||||
cp assembly/nix/openssl.nix .
|
||||
export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
|
@ -30,7 +28,9 @@ cp ./result/bin/* artifacts/
|
|||
test $? -eq 0 || { echo "No artifacts have been built..."; exit 1; }
|
||||
chmod +x artifacts/*
|
||||
rm -rf result
|
||||
|
||||
nix-build linux-arm64-tonlib.nix
|
||||
|
||||
cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
|
||||
cp ./result/lib/libemulator.so artifacts/
|
||||
cp ./result/lib/fift/* artifacts/lib/
|
||||
|
|
|
@ -15,8 +15,6 @@ while getopts 't' flag; do
|
|||
done
|
||||
|
||||
cp assembly/nix/linux-x86-64* .
|
||||
cp assembly/nix/microhttpd.nix .
|
||||
cp assembly/nix/openssl.nix .
|
||||
export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
|
@ -30,7 +28,9 @@ cp ./result/bin/* artifacts/
|
|||
test $? -eq 0 || { echo "No artifacts have been built..."; exit 1; }
|
||||
chmod +x artifacts/*
|
||||
rm -rf result
|
||||
|
||||
nix-build linux-x86-64-tonlib.nix
|
||||
|
||||
cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
|
||||
cp ./result/lib/libemulator.so artifacts/
|
||||
cp ./result/lib/fift/* artifacts/lib/
|
||||
|
|
|
@ -28,7 +28,9 @@ cp ./result-bin/bin/* artifacts/
|
|||
test $? -eq 0 || { echo "No artifacts have been built..."; exit 1; }
|
||||
chmod +x artifacts/*
|
||||
rm -rf result-bin
|
||||
|
||||
nix-build macos-tonlib.nix
|
||||
|
||||
cp ./result/lib/libtonlibjson.dylib artifacts/
|
||||
cp ./result/lib/libemulator.dylib artifacts/
|
||||
cp ./result/lib/fift/* artifacts/lib/
|
||||
|
|
|
@ -6,9 +6,23 @@
|
|||
, testing ? false
|
||||
}:
|
||||
let
|
||||
microhttpdmy = (import ./microhttpd.nix) {};
|
||||
staticOptions = pkg: pkg.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--without-shared" "--disable-shared" "--disable-tests" ];
|
||||
});
|
||||
|
||||
secp256k1Static = (staticOptions pkgs.secp256k1);
|
||||
libsodiumStatic = (staticOptions pkgs.libsodium);
|
||||
jemallocStatic = (staticOptions pkgs.jemalloc);
|
||||
|
||||
microhttpdStatic = pkgs.libmicrohttpd.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--enable-static" "--disable-tests" "--disable-benchmark" "--disable-shared" "--disable-https" "--with-pic" ];
|
||||
});
|
||||
|
||||
in
|
||||
with import microhttpdmy;
|
||||
stdenv.mkDerivation {
|
||||
pname = "ton";
|
||||
version = "dev-bin";
|
||||
|
@ -16,31 +30,33 @@ stdenv.mkDerivation {
|
|||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs;
|
||||
[
|
||||
cmake ninja git pkg-config
|
||||
];
|
||||
[ cmake ninja git pkg-config ];
|
||||
|
||||
buildInputs = with pkgs;
|
||||
[
|
||||
pkgsStatic.openssl microhttpdmy pkgsStatic.zlib pkgsStatic.libsodium.dev pkgsStatic.secp256k1 glibc.static pkgsStatic.lz4
|
||||
(openssl.override { static = true; }).dev
|
||||
microhttpdStatic.dev
|
||||
(zlib.override { shared = false; }).dev
|
||||
(lz4.override { enableStatic = true; enableShared = false; }).dev
|
||||
jemallocStatic
|
||||
secp256k1Static
|
||||
libsodiumStatic.dev
|
||||
glibc.static
|
||||
];
|
||||
|
||||
makeStatic = true;
|
||||
doCheck = testing;
|
||||
|
||||
cmakeFlags = [
|
||||
"-DTON_USE_ABSEIL=OFF"
|
||||
"-DNIX=ON"
|
||||
"-DBUILD_SHARED_LIBS=OFF"
|
||||
"-DCMAKE_LINK_SEARCH_START_STATIC=ON"
|
||||
"-DCMAKE_LINK_SEARCH_END_STATIC=ON"
|
||||
"-DMHD_FOUND=1"
|
||||
"-DMHD_INCLUDE_DIR=${microhttpdmy}/usr/local/include"
|
||||
"-DMHD_LIBRARY=${microhttpdmy}/usr/local/lib/libmicrohttpd.a"
|
||||
"-DCMAKE_CTEST_ARGUMENTS=--timeout;1800"
|
||||
"-DTON_USE_JEMALLOC=ON"
|
||||
];
|
||||
|
||||
makeStatic = true;
|
||||
doCheck = testing;
|
||||
|
||||
LDFLAGS = [
|
||||
"-static-libgcc" "-static-libstdc++" "-static"
|
||||
"-static-libgcc" "-static-libstdc++" "-static"
|
||||
];
|
||||
}
|
||||
|
|
|
@ -5,9 +5,21 @@
|
|||
, stdenv ? pkgs.stdenv
|
||||
}:
|
||||
let
|
||||
microhttpdmy = (import ./microhttpd.nix) {};
|
||||
staticOptions = pkg: pkg.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--without-shared" "--disable-shared" "--disable-tests" ];
|
||||
});
|
||||
|
||||
secp256k1Static = (staticOptions pkgs.secp256k1);
|
||||
libsodiumStatic = (staticOptions pkgs.libsodium);
|
||||
|
||||
microhttpdStatic = pkgs.libmicrohttpd.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--enable-static" "--disable-tests" "--disable-benchmark" "--disable-shared" "--disable-https" "--with-pic" ];
|
||||
});
|
||||
in
|
||||
with import microhttpdmy;
|
||||
pkgs.llvmPackages_16.stdenv.mkDerivation {
|
||||
pname = "ton";
|
||||
version = "dev-lib";
|
||||
|
@ -21,7 +33,12 @@ pkgs.llvmPackages_16.stdenv.mkDerivation {
|
|||
|
||||
buildInputs = with pkgs;
|
||||
[
|
||||
pkgsStatic.openssl microhttpdmy pkgsStatic.zlib pkgsStatic.libsodium.dev pkgsStatic.secp256k1 pkgsStatic.lz4
|
||||
(openssl.override { static = true; }).dev
|
||||
microhttpdStatic.dev
|
||||
(zlib.override { shared = false; }).dev
|
||||
(lz4.override { enableStatic = true; enableShared = false; }).dev
|
||||
secp256k1Static
|
||||
libsodiumStatic.dev
|
||||
];
|
||||
|
||||
dontAddStaticConfigureFlags = false;
|
||||
|
@ -29,9 +46,6 @@ pkgs.llvmPackages_16.stdenv.mkDerivation {
|
|||
cmakeFlags = [
|
||||
"-DTON_USE_ABSEIL=OFF"
|
||||
"-DNIX=ON"
|
||||
"-DMHD_FOUND=1"
|
||||
"-DMHD_INCLUDE_DIR=${microhttpdmy}/usr/local/include"
|
||||
"-DMHD_LIBRARY=${microhttpdmy}/usr/local/lib/libmicrohttpd.a"
|
||||
];
|
||||
|
||||
LDFLAGS = [
|
||||
|
|
|
@ -6,9 +6,23 @@
|
|||
, testing ? false
|
||||
}:
|
||||
let
|
||||
microhttpdmy = (import ./microhttpd.nix) {};
|
||||
staticOptions = pkg: pkg.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--without-shared" "--disable-shared" "--disable-tests" ];
|
||||
});
|
||||
|
||||
secp256k1Static = (staticOptions pkgs.secp256k1);
|
||||
libsodiumStatic = (staticOptions pkgs.libsodium);
|
||||
jemallocStatic = (staticOptions pkgs.jemalloc);
|
||||
|
||||
microhttpdStatic = pkgs.libmicrohttpd.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--enable-static" "--disable-tests" "--disable-benchmark" "--disable-shared" "--disable-https" "--with-pic" ];
|
||||
});
|
||||
|
||||
in
|
||||
with import microhttpdmy;
|
||||
stdenv.mkDerivation {
|
||||
pname = "ton";
|
||||
version = "dev-bin";
|
||||
|
@ -16,31 +30,33 @@ stdenv.mkDerivation {
|
|||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs;
|
||||
[
|
||||
cmake ninja git pkg-config
|
||||
];
|
||||
[ cmake ninja git pkg-config ];
|
||||
|
||||
buildInputs = with pkgs;
|
||||
[
|
||||
pkgsStatic.openssl microhttpdmy pkgsStatic.zlib pkgsStatic.libsodium.dev pkgsStatic.secp256k1 glibc.static pkgsStatic.lz4
|
||||
(openssl.override { static = true; }).dev
|
||||
microhttpdStatic.dev
|
||||
(zlib.override { shared = false; }).dev
|
||||
(lz4.override { enableStatic = true; enableShared = false; }).dev
|
||||
jemallocStatic
|
||||
secp256k1Static
|
||||
libsodiumStatic.dev
|
||||
glibc.static
|
||||
];
|
||||
|
||||
makeStatic = true;
|
||||
doCheck = testing;
|
||||
|
||||
cmakeFlags = [
|
||||
"-DTON_USE_ABSEIL=OFF"
|
||||
"-DNIX=ON"
|
||||
"-DBUILD_SHARED_LIBS=OFF"
|
||||
"-DCMAKE_LINK_SEARCH_START_STATIC=ON"
|
||||
"-DCMAKE_LINK_SEARCH_END_STATIC=ON"
|
||||
"-DMHD_FOUND=1"
|
||||
"-DMHD_INCLUDE_DIR=${microhttpdmy}/usr/local/include"
|
||||
"-DMHD_LIBRARY=${microhttpdmy}/usr/local/lib/libmicrohttpd.a"
|
||||
"-DCMAKE_CTEST_ARGUMENTS=--timeout;1800"
|
||||
"-DTON_USE_JEMALLOC=ON"
|
||||
];
|
||||
|
||||
makeStatic = true;
|
||||
doCheck = testing;
|
||||
|
||||
LDFLAGS = [
|
||||
"-static-libgcc" "-static-libstdc++" "-static"
|
||||
"-static-libgcc" "-static-libstdc++" "-fPIC"
|
||||
];
|
||||
}
|
||||
|
|
|
@ -7,20 +7,35 @@
|
|||
, stdenv ? pkgs.stdenv
|
||||
}:
|
||||
let
|
||||
system = builtins.currentSystem;
|
||||
system = builtins.currentSystem;
|
||||
|
||||
nixos1909 = (import (builtins.fetchTarball {
|
||||
url = "https://channels.nixos.org/nixos-19.09/nixexprs.tar.xz";
|
||||
sha256 = "1vp1h2gkkrckp8dzkqnpcc6xx5lph5d2z46sg2cwzccpr8ay58zy";
|
||||
}) { inherit system; });
|
||||
glibc227 = nixos1909.glibc // { pname = "glibc"; };
|
||||
stdenv227 = let
|
||||
cc = pkgs.wrapCCWith {
|
||||
cc = nixos1909.buildPackages.gcc-unwrapped;
|
||||
libc = glibc227;
|
||||
bintools = pkgs.binutils.override { libc = glibc227; };
|
||||
};
|
||||
in (pkgs.overrideCC pkgs.stdenv cc);
|
||||
staticOptions = pkg: pkg.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--without-shared" "--disable-shared" "--disable-tests" ];
|
||||
});
|
||||
|
||||
secp256k1Static = (staticOptions pkgs.secp256k1);
|
||||
libsodiumStatic = (staticOptions pkgs.libsodium);
|
||||
|
||||
microhttpdStatic = pkgs.libmicrohttpd.overrideAttrs(oldAttrs: {
|
||||
dontDisableStatic = true;
|
||||
enableSharedExecutables = false;
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ [ "--enable-static" "--disable-tests" "--disable-benchmark" "--disable-shared" "--disable-https" "--with-pic" ];
|
||||
});
|
||||
|
||||
nixos1909 = (import (builtins.fetchTarball {
|
||||
url = "https://channels.nixos.org/nixos-19.09/nixexprs.tar.xz";
|
||||
sha256 = "1vp1h2gkkrckp8dzkqnpcc6xx5lph5d2z46sg2cwzccpr8ay58zy";
|
||||
}) { inherit system; });
|
||||
glibc227 = nixos1909.glibc // { pname = "glibc"; };
|
||||
stdenv227 = let
|
||||
cc = pkgs.wrapCCWith {
|
||||
cc = nixos1909.buildPackages.gcc-unwrapped;
|
||||
libc = glibc227;
|
||||
bintools = pkgs.binutils.override { libc = glibc227; };
|
||||
};
|
||||
in (pkgs.overrideCC pkgs.stdenv cc);
|
||||
|
||||
in
|
||||
stdenv227.mkDerivation {
|
||||
|
@ -34,7 +49,12 @@ stdenv227.mkDerivation {
|
|||
|
||||
buildInputs = with pkgs;
|
||||
[
|
||||
pkgsStatic.openssl pkgsStatic.zlib pkgsStatic.libmicrohttpd.dev pkgsStatic.libsodium.dev pkgsStatic.secp256k1 pkgsStatic.lz4
|
||||
(openssl.override { static = true; }).dev
|
||||
microhttpdStatic.dev
|
||||
(zlib.override { shared = false; }).dev
|
||||
(lz4.override { enableStatic = true; enableShared = false; }).dev
|
||||
secp256k1Static
|
||||
libsodiumStatic.dev
|
||||
];
|
||||
|
||||
dontAddStaticConfigureFlags = false;
|
||||
|
|
|
@ -17,7 +17,7 @@ pkgs.llvmPackages_14.stdenv.mkDerivation {
|
|||
|
||||
buildInputs = with pkgs;
|
||||
lib.forEach [
|
||||
secp256k1 libsodium.dev libmicrohttpd.dev gmp.dev nettle.dev libtasn1.dev libidn2.dev libunistring.dev gettext (gnutls.override { withP11-kit = false; }).dev
|
||||
secp256k1 libsodium.dev libmicrohttpd.dev gmp.dev nettle.dev libtasn1.dev libidn2.dev libunistring.dev gettext jemalloc (gnutls.override { withP11-kit = false; }).dev
|
||||
]
|
||||
(x: x.overrideAttrs(oldAttrs: rec { configureFlags = (oldAttrs.configureFlags or []) ++ [ "--enable-static" "--disable-shared" "--disable-tests" ]; dontDisableStatic = true; }))
|
||||
++ [
|
||||
|
@ -38,13 +38,13 @@ pkgs.llvmPackages_14.stdenv.mkDerivation {
|
|||
cmakeFlags = [
|
||||
"-DTON_USE_ABSEIL=OFF"
|
||||
"-DNIX=ON"
|
||||
"-DTON_USE_JEMALLOC=ON"
|
||||
"-DCMAKE_CROSSCOMPILING=OFF"
|
||||
"-DCMAKE_LINK_SEARCH_START_STATIC=ON"
|
||||
"-DCMAKE_LINK_SEARCH_END_STATIC=ON"
|
||||
"-DBUILD_SHARED_LIBS=OFF"
|
||||
"-DCMAKE_CXX_FLAGS=-stdlib=libc++"
|
||||
"-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=11.3"
|
||||
"-DCMAKE_CTEST_ARGUMENTS=--timeout;1800"
|
||||
];
|
||||
|
||||
LDFLAGS = [
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
|
||||
, stdenv ? pkgs.stdenv
|
||||
, fetchgit ? pkgs.fetchgit
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
name = "microhttpdmy";
|
||||
|
||||
|
||||
src = fetchgit {
|
||||
url = "https://git.gnunet.org/libmicrohttpd.git";
|
||||
rev = "refs/tags/v0.9.77";
|
||||
sha256 = "sha256-x+nfB07PbZwBlFc6kZZFYiRpk0a3QN/ByHB+hC8na/o=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = with pkgs; [ automake libtool autoconf texinfo ];
|
||||
|
||||
buildInputs = with pkgs; [ ];
|
||||
|
||||
configurePhase = ''
|
||||
./autogen.sh
|
||||
./configure --enable-static --disable-tests --disable-benchmark --disable-shared --disable-https --with-pic
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
make install DESTDIR=$out
|
||||
'';
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
|
||||
, stdenv ? pkgs.stdenv
|
||||
, fetchFromGitHub ? pkgs.fetchFromGitHub
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
name = "opensslmy";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "openssl";
|
||||
repo = "openssl";
|
||||
rev = "refs/tags/openssl-3.1.4";
|
||||
sha256 = "sha256-Vvf1wiNb4ikg1lIS9U137aodZ2JzM711tSWMJFYWtWI=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = with pkgs; [ perl ];
|
||||
|
||||
buildInputs = with pkgs; [ ];
|
||||
|
||||
postPatch = ''
|
||||
patchShebangs Configure
|
||||
'';
|
||||
|
||||
configurePhase = ''
|
||||
./Configure no-shared
|
||||
'';
|
||||
installPhase = ''
|
||||
make install DESTDIR=$out
|
||||
'';
|
||||
}
|
|
@ -50,32 +50,6 @@
|
|||
#include "vm/vm.h"
|
||||
#include "vm/cp0.h"
|
||||
|
||||
namespace {
|
||||
|
||||
td::Ref<vm::Tuple> prepare_vm_c7(ton::UnixTime now, ton::LogicalTime lt, td::Ref<vm::CellSlice> my_addr,
|
||||
const block::CurrencyCollection &balance) {
|
||||
td::BitArray<256> rand_seed;
|
||||
td::RefInt256 rand_seed_int{true};
|
||||
td::Random::secure_bytes(rand_seed.as_slice());
|
||||
if (!rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false)) {
|
||||
return {};
|
||||
}
|
||||
auto tuple = vm::make_tuple_ref(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(lt), // block_lt:Integer
|
||||
td::make_refint(lt), // trans_lt:Integer
|
||||
std::move(rand_seed_int), // rand_seed:Integer
|
||||
balance.as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||
my_addr, // myself:MsgAddressInt
|
||||
vm::StackEntry()); // global_config:(Maybe Cell) ] = SmartContractInfo;
|
||||
LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
|
||||
return vm::make_tuple_ref(std::move(tuple));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
td::Result<ton::BlockIdExt> parse_block_id(std::map<std::string, std::string> &opts, bool allow_empty) {
|
||||
if (allow_empty) {
|
||||
if (opts.count("workchain") == 0 && opts.count("shard") == 0 && opts.count("seqno") == 0) {
|
||||
|
@ -1343,111 +1317,71 @@ void HttpQueryRunMethod::start_up_query() {
|
|||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &HttpQueryRunMethod::abort_query, R.move_as_error_prefix("litequery failed: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &HttpQueryRunMethod::got_account, R.move_as_ok());
|
||||
td::actor::send_closure(SelfId, &HttpQueryRunMethod::got_result, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
|
||||
auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
|
||||
ton::create_tl_lite_block_id(block_id_), std::move(a)),
|
||||
true);
|
||||
td::int64 method_id = (td::crc16(td::Slice{method_name_}) & 0xffff) | 0x10000;
|
||||
|
||||
// serialize params
|
||||
vm::CellBuilder cb;
|
||||
td::Ref<vm::Cell> cell;
|
||||
if (!(vm::Stack{params_}.serialize(cb) && cb.finalize_to(cell))) {
|
||||
return abort_query(td::Status::Error("cannot serialize stack with get-method parameters"));
|
||||
}
|
||||
auto params_serialized = vm::std_boc_serialize(std::move(cell));
|
||||
if (params_serialized.is_error()) {
|
||||
return abort_query(params_serialized.move_as_error_prefix("cannot serialize stack with get-method parameters : "));
|
||||
}
|
||||
|
||||
auto query = ton::serialize_tl_object(
|
||||
ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>(
|
||||
0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()),
|
||||
true);
|
||||
td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
|
||||
std::move(query), std::move(P));
|
||||
}
|
||||
|
||||
void HttpQueryRunMethod::got_account(td::BufferSlice data) {
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(std::move(data), true);
|
||||
void HttpQueryRunMethod::got_result(td::BufferSlice data) {
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_runMethodResult>(std::move(data), true);
|
||||
if (F.is_error()) {
|
||||
abort_query(F.move_as_error());
|
||||
return;
|
||||
return abort_query(F.move_as_error());
|
||||
}
|
||||
|
||||
auto f = F.move_as_ok();
|
||||
data_ = std::move(f->state_);
|
||||
proof_ = std::move(f->proof_);
|
||||
shard_proof_ = std::move(f->shard_proof_);
|
||||
block_id_ = ton::create_block_id(f->id_);
|
||||
res_block_id_ = ton::create_block_id(f->shardblk_);
|
||||
|
||||
finish_query();
|
||||
}
|
||||
|
||||
void HttpQueryRunMethod::finish_query() {
|
||||
if (promise_) {
|
||||
auto page = [&]() -> std::string {
|
||||
HttpAnswer A{"account", prefix_};
|
||||
A.set_account_id(addr_);
|
||||
A.set_block_id(res_block_id_);
|
||||
|
||||
block::AccountState account_state;
|
||||
account_state.blk = block_id_;
|
||||
account_state.shard_blk = res_block_id_;
|
||||
account_state.shard_proof = std::move(shard_proof_);
|
||||
account_state.proof = std::move(proof_);
|
||||
account_state.state = std::move(data_);
|
||||
auto r_info = account_state.validate(block_id_, addr_);
|
||||
if (r_info.is_error()) {
|
||||
A.abort(r_info.move_as_error());
|
||||
return A.finish();
|
||||
}
|
||||
auto info = r_info.move_as_ok();
|
||||
if (info.root.is_null()) {
|
||||
A.abort(PSTRING() << "account state of " << addr_ << " is empty (cannot run method `" << method_name_ << "`)");
|
||||
return A.finish();
|
||||
}
|
||||
block::gen::Account::Record_account acc;
|
||||
block::gen::AccountStorage::Record store;
|
||||
block::CurrencyCollection balance;
|
||||
if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) &&
|
||||
balance.validate_unpack(store.balance))) {
|
||||
A.abort("error unpacking account state");
|
||||
return A.finish();
|
||||
}
|
||||
int tag = block::gen::t_AccountState.get_tag(*store.state);
|
||||
switch (tag) {
|
||||
case block::gen::AccountState::account_uninit:
|
||||
A.abort(PSTRING() << "account " << addr_ << " not initialized yet (cannot run any methods)");
|
||||
return A.finish();
|
||||
case block::gen::AccountState::account_frozen:
|
||||
A.abort(PSTRING() << "account " << addr_ << " frozen (cannot run any methods)");
|
||||
return A.finish();
|
||||
}
|
||||
|
||||
CHECK(store.state.write().fetch_ulong(1) == 1); // account_init$1 _:StateInit = AccountState;
|
||||
block::gen::StateInit::Record state_init;
|
||||
CHECK(tlb::csr_unpack(store.state, state_init));
|
||||
auto code = state_init.code->prefetch_ref();
|
||||
auto data = state_init.data->prefetch_ref();
|
||||
auto stack = td::make_ref<vm::Stack>(std::move(params_));
|
||||
td::int64 method_id = (td::crc16(td::Slice{method_name_}) & 0xffff) | 0x10000;
|
||||
stack.write().push_smallint(method_id);
|
||||
long long gas_limit = vm::GasLimits::infty;
|
||||
// OstreamLogger ostream_logger(ctx.error_stream);
|
||||
// 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.set_c7(prepare_vm_c7(info.gen_utime, info.gen_lt, acc.addr, balance)); // tuple with SmartContractInfo
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
int exit_code = ~vm.run();
|
||||
if (exit_code != 0) {
|
||||
A.abort(PSTRING() << "VM terminated with error code " << exit_code);
|
||||
return A.finish();
|
||||
}
|
||||
stack = vm.get_stack_ref();
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "result: ";
|
||||
stack->dump(os, 3);
|
||||
|
||||
A << HttpAnswer::CodeBlock{os.str()};
|
||||
}
|
||||
|
||||
auto page = [&]() -> std::string {
|
||||
HttpAnswer A{"account", prefix_};
|
||||
A.set_account_id(addr_);
|
||||
A.set_block_id(ton::create_block_id(f->id_));
|
||||
if (f->exit_code_ != 0) {
|
||||
A.abort(PSTRING() << "VM terminated with error code " << f->exit_code_);
|
||||
return A.finish();
|
||||
}();
|
||||
auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
|
||||
MHD_add_response_header(R, "Content-Type", "text/html");
|
||||
promise_.set_value(std::move(R));
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
os << "result: ";
|
||||
if (f->result_.empty()) {
|
||||
os << "<none>";
|
||||
} else {
|
||||
auto r_cell = vm::std_boc_deserialize(f->result_);
|
||||
if (r_cell.is_error()) {
|
||||
A.abort(PSTRING() << "cannot deserialize VM result boc: " << r_cell.move_as_error());
|
||||
return A.finish();
|
||||
}
|
||||
auto cs = vm::load_cell_slice(r_cell.move_as_ok());
|
||||
td::Ref<vm::Stack> stack;
|
||||
if (!(vm::Stack::deserialize_to(cs, stack, 0) && cs.empty_ext())) {
|
||||
A.abort("VM result boc cannot be deserialized");
|
||||
return A.finish();
|
||||
}
|
||||
stack->dump(os, 3);
|
||||
}
|
||||
A << HttpAnswer::CodeBlock{os.str()};
|
||||
return A.finish();
|
||||
}();
|
||||
auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
|
||||
MHD_add_response_header(R, "Content-Type", "text/html");
|
||||
promise_.set_value(std::move(R));
|
||||
stop();
|
||||
}
|
||||
HttpQueryStatus::HttpQueryStatus(std::string prefix, td::Promise<MHD_Response *> promise)
|
||||
|
|
|
@ -311,22 +311,14 @@ class HttpQueryRunMethod : public HttpQueryCommon {
|
|||
std::vector<vm::StackEntry> params, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryRunMethod(std::map<std::string, std::string> opts, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_account(td::BufferSlice result);
|
||||
void got_result(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt block_id_;
|
||||
block::StdAddress addr_;
|
||||
|
||||
std::string method_name_;
|
||||
std::vector<vm::StackEntry> params_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
td::BufferSlice proof_;
|
||||
td::BufferSlice shard_proof_;
|
||||
ton::BlockIdExt res_block_id_;
|
||||
};
|
||||
|
||||
class HttpQueryStatus : public HttpQueryCommon {
|
||||
|
|
|
@ -246,7 +246,10 @@ class HardforkCreator : public td::actor::Actor {
|
|||
}
|
||||
void send_shard_block_info(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::BufferSlice data) override {
|
||||
}
|
||||
void send_broadcast(ton::BlockBroadcast broadcast) override {
|
||||
void send_block_candidate(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) override {
|
||||
}
|
||||
void send_broadcast(ton::BlockBroadcast broadcast, bool custom_overlays_only) override {
|
||||
}
|
||||
void download_block(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ton::ReceivedBlock> promise) override {
|
||||
|
|
|
@ -479,10 +479,17 @@ if (NOT CMAKE_CROSSCOMPILING OR USE_EMSCRIPTEN)
|
|||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DEST_FIF}
|
||||
)
|
||||
set(ARG_DEST_CPP "${ARG_DEST}.cpp")
|
||||
|
||||
if (WIN32)
|
||||
set(ARG_LIB_DIR "fift/lib@smartcont")
|
||||
else()
|
||||
set(ARG_LIB_DIR "fift/lib:smartcont")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
COMMENT "Generate ${ARG_DEST_CPP}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND fift -Ifift/lib:smartcont -s asm-to-cpp.fif ${ARG_DEST_FIF} ${ARG_DEST_CPP} ${ARG_NAME}
|
||||
COMMAND fift -I${ARG_LIB_DIR} -s asm-to-cpp.fif ${ARG_DEST_FIF} ${ARG_DEST_CPP} ${ARG_NAME}
|
||||
MAIN_DEPENDENCY ${ARG_SOURCE}
|
||||
DEPENDS fift ${ARG_DEST_FIF} smartcont/asm-to-cpp.fif fift/lib/Asm.fif
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DEST_CPP}
|
||||
|
|
|
@ -814,11 +814,16 @@ void usage(const char* progname) {
|
|||
void parse_include_path_set(std::string include_path_set, std::vector<std::string>& res) {
|
||||
td::Parser parser(include_path_set);
|
||||
while (!parser.empty()) {
|
||||
auto path = parser.read_till_nofail(':');
|
||||
#if TD_WINDOWS
|
||||
auto path_separator = '@';
|
||||
#else
|
||||
auto path_separator = ':';
|
||||
#endif
|
||||
auto path = parser.read_till_nofail(path_separator);
|
||||
if (!path.empty()) {
|
||||
res.push_back(path.str());
|
||||
}
|
||||
parser.skip_nofail(':');
|
||||
parser.skip_nofail(path_separator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ void usage(const char* progname) {
|
|||
<< " [-i] [-n] [-I <source-include-path>] {-L <library-fif-file>} <source-file1-fif> <source-file2-fif> ...\n";
|
||||
std::cerr << "\t-n\tDo not preload standard preamble file `Fift.fif`\n"
|
||||
"\t-i\tForce interactive mode even if explicit source file names are indicated\n"
|
||||
"\t-I<source-search-path>\tSets colon-separated library source include path. If not indicated, "
|
||||
"\t-I<source-search-path>\tSets colon-separated (unix) or at-separated (windows) library source include path. If not indicated, "
|
||||
"$FIFTPATH is used instead.\n"
|
||||
"\t-L<library-fif-file>\tPre-loads a library source file\n"
|
||||
"\t-d<ton-db-path>\tUse a ton database\n"
|
||||
|
@ -75,11 +75,16 @@ void usage(const char* progname) {
|
|||
void parse_include_path_set(std::string include_path_set, std::vector<std::string>& res) {
|
||||
td::Parser parser(include_path_set);
|
||||
while (!parser.empty()) {
|
||||
auto path = parser.read_till_nofail(':');
|
||||
#if TD_WINDOWS
|
||||
auto path_separator = '@';
|
||||
#else
|
||||
auto path_separator = ':';
|
||||
#endif
|
||||
auto path = parser.read_till_nofail(path_separator);
|
||||
if (!path.empty()) {
|
||||
res.push_back(path.str());
|
||||
}
|
||||
parser.skip_nofail(':');
|
||||
parser.skip_nofail(path_separator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/utils/CancellationToken.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include "vm/db/DynamicBagOfCellsDb.h"
|
||||
|
@ -331,7 +333,7 @@ td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data,
|
|||
int max_roots = BagOfCells::default_max_roots);
|
||||
td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> root, int mode = 0);
|
||||
|
||||
td::Status std_boc_serialize_to_file_large(std::shared_ptr<CellDbReader> reader, Cell::Hash root_hash,
|
||||
td::FileFd& fd, int mode = 0);
|
||||
td::Status std_boc_serialize_to_file_large(std::shared_ptr<CellDbReader> reader, Cell::Hash root_hash, td::FileFd& fd,
|
||||
int mode = 0, td::CancellationToken cancellation_token = {});
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "td/utils/Time.h"
|
||||
#include "td/utils/Timer.h"
|
||||
|
||||
#include <map>
|
||||
#include "vm/boc.h"
|
||||
#include "vm/boc-writers.h"
|
||||
|
@ -30,7 +33,9 @@ class LargeBocSerializer {
|
|||
public:
|
||||
using Hash = Cell::Hash;
|
||||
|
||||
explicit LargeBocSerializer(std::shared_ptr<CellDbReader> reader) : reader(std::move(reader)) {}
|
||||
explicit LargeBocSerializer(std::shared_ptr<CellDbReader> reader, td::CancellationToken cancellation_token = {})
|
||||
: reader(std::move(reader)), cancellation_token(std::move(cancellation_token)) {
|
||||
}
|
||||
|
||||
void add_root(Hash root);
|
||||
td::Status import_cells();
|
||||
|
@ -65,7 +70,8 @@ class LargeBocSerializer {
|
|||
std::map<Hash, CellInfo> cells;
|
||||
std::vector<std::pair<const Hash, CellInfo>*> cell_list;
|
||||
struct RootInfo {
|
||||
RootInfo(Hash hash, int idx) : hash(hash), idx(idx) {}
|
||||
RootInfo(Hash hash, int idx) : hash(hash), idx(idx) {
|
||||
}
|
||||
Hash hash;
|
||||
int idx;
|
||||
};
|
||||
|
@ -78,6 +84,11 @@ class LargeBocSerializer {
|
|||
void reorder_cells();
|
||||
int revisit(int cell_idx, int force = 0);
|
||||
td::uint64 compute_sizes(int mode, int& r_size, int& o_size);
|
||||
|
||||
td::CancellationToken cancellation_token;
|
||||
td::Timestamp log_speed_at_;
|
||||
size_t processed_cells_ = 0;
|
||||
static constexpr double LOG_SPEED_PERIOD = 120.0;
|
||||
};
|
||||
|
||||
void LargeBocSerializer::add_root(Hash root) {
|
||||
|
@ -85,12 +96,16 @@ void LargeBocSerializer::add_root(Hash root) {
|
|||
}
|
||||
|
||||
td::Status LargeBocSerializer::import_cells() {
|
||||
td::Timer timer;
|
||||
log_speed_at_ = td::Timestamp::in(LOG_SPEED_PERIOD);
|
||||
processed_cells_ = 0;
|
||||
for (auto& root : roots) {
|
||||
TRY_RESULT(idx, import_cell(root.hash));
|
||||
root.idx = idx;
|
||||
}
|
||||
reorder_cells();
|
||||
CHECK(!cell_list.empty());
|
||||
LOG(ERROR) << "serializer: import_cells took " << timer.elapsed() << "s, " << cell_count << " cells";
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -98,6 +113,15 @@ td::Result<int> LargeBocSerializer::import_cell(Hash hash, int depth) {
|
|||
if (depth > Cell::max_depth) {
|
||||
return td::Status::Error("error while importing a cell into a bag of cells: cell depth too large");
|
||||
}
|
||||
++processed_cells_;
|
||||
if (processed_cells_ % 1000 == 0) {
|
||||
TRY_STATUS(cancellation_token.check());
|
||||
}
|
||||
if (log_speed_at_.is_in_past()) {
|
||||
log_speed_at_ += LOG_SPEED_PERIOD;
|
||||
LOG(WARNING) << "serializer: import_cells " << (double)processed_cells_ / LOG_SPEED_PERIOD << " cells/s";
|
||||
processed_cells_ = 0;
|
||||
}
|
||||
auto it = cells.find(hash);
|
||||
if (it != cells.end()) {
|
||||
it->second.should_cache = true;
|
||||
|
@ -282,6 +306,7 @@ td::uint64 LargeBocSerializer::compute_sizes(int mode, int& r_size, int& o_size)
|
|||
}
|
||||
|
||||
td::Status LargeBocSerializer::serialize(td::FileFd& fd, int mode) {
|
||||
td::Timer timer;
|
||||
using Mode = BagOfCells::Mode;
|
||||
BagOfCells::Info info;
|
||||
if ((mode & Mode::WithCacheBits) && !(mode & Mode::WithIndex)) {
|
||||
|
@ -313,13 +338,9 @@ td::Status LargeBocSerializer::serialize(td::FileFd& fd, int mode) {
|
|||
return td::Status::Error("bag of cells is too large");
|
||||
}
|
||||
|
||||
boc_writers::FileWriter writer{fd, (size_t) info.total_size};
|
||||
auto store_ref = [&](unsigned long long value) {
|
||||
writer.store_uint(value, info.ref_byte_size);
|
||||
};
|
||||
auto store_offset = [&](unsigned long long value) {
|
||||
writer.store_uint(value, info.offset_byte_size);
|
||||
};
|
||||
boc_writers::FileWriter writer{fd, (size_t)info.total_size};
|
||||
auto store_ref = [&](unsigned long long value) { writer.store_uint(value, info.ref_byte_size); };
|
||||
auto store_offset = [&](unsigned long long value) { writer.store_uint(value, info.offset_byte_size); };
|
||||
|
||||
writer.store_uint(info.magic, 4);
|
||||
|
||||
|
@ -371,6 +392,8 @@ td::Status LargeBocSerializer::serialize(td::FileFd& fd, int mode) {
|
|||
}
|
||||
DCHECK(writer.position() == info.data_offset);
|
||||
size_t keep_position = writer.position();
|
||||
log_speed_at_ = td::Timestamp::in(LOG_SPEED_PERIOD);
|
||||
processed_cells_ = 0;
|
||||
for (int i = 0; i < cell_count; ++i) {
|
||||
auto hash = cell_list[cell_count - 1 - i]->first;
|
||||
const auto& dc_info = cell_list[cell_count - 1 - i]->second;
|
||||
|
@ -389,6 +412,15 @@ td::Status LargeBocSerializer::serialize(td::FileFd& fd, int mode) {
|
|||
DCHECK(k > i && k < cell_count);
|
||||
store_ref(k);
|
||||
}
|
||||
++processed_cells_;
|
||||
if (processed_cells_ % 1000 == 0) {
|
||||
TRY_STATUS(cancellation_token.check());
|
||||
}
|
||||
if (log_speed_at_.is_in_past()) {
|
||||
log_speed_at_ += LOG_SPEED_PERIOD;
|
||||
LOG(WARNING) << "serializer: serialize " << (double)processed_cells_ / LOG_SPEED_PERIOD << " cells/s";
|
||||
processed_cells_ = 0;
|
||||
}
|
||||
}
|
||||
DCHECK(writer.position() - keep_position == info.data_size);
|
||||
if (info.has_crc32c) {
|
||||
|
@ -396,17 +428,23 @@ td::Status LargeBocSerializer::serialize(td::FileFd& fd, int mode) {
|
|||
writer.store_uint(td::bswap32(crc), 4);
|
||||
}
|
||||
DCHECK(writer.empty());
|
||||
return writer.finalize();
|
||||
}
|
||||
TRY_STATUS(writer.finalize());
|
||||
LOG(ERROR) << "serializer: serialize took " << timer.elapsed() << "s, " << cell_count << " cells, "
|
||||
<< writer.position() << " bytes";
|
||||
return td::Status::OK();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
td::Status std_boc_serialize_to_file_large(std::shared_ptr<CellDbReader> reader, Cell::Hash root_hash,
|
||||
td::FileFd& fd, int mode) {
|
||||
td::Status std_boc_serialize_to_file_large(std::shared_ptr<CellDbReader> reader, Cell::Hash root_hash, td::FileFd& fd,
|
||||
int mode, td::CancellationToken cancellation_token) {
|
||||
td::Timer timer;
|
||||
CHECK(reader != nullptr)
|
||||
LargeBocSerializer serializer(reader);
|
||||
LargeBocSerializer serializer(reader, std::move(cancellation_token));
|
||||
serializer.add_root(root_hash);
|
||||
TRY_STATUS(serializer.import_cells());
|
||||
return serializer.serialize(fd, mode);
|
||||
TRY_STATUS(serializer.serialize(fd, mode));
|
||||
LOG(ERROR) << "serialization took " << timer.elapsed() << "s";
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace vm
|
||||
|
|
|
@ -170,7 +170,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
return ton::create_tl_object<ton::ton_api::engine_validator_config>(
|
||||
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec),
|
||||
ton::PublicKeyHash::zero().tl(), std::move(full_node_slaves_vec), std::move(full_node_masters_vec),
|
||||
nullptr, std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
|
||||
nullptr, nullptr, std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
|
||||
|
|
|
@ -229,7 +229,7 @@ void OverlayImpl::update_neighbours(td::uint32 nodes_to_change) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (X->get_version() <= td::Clocks::system() - 600) {
|
||||
if (public_ && X->get_version() <= td::Clocks::system() - 600) {
|
||||
if (X->is_neighbour()) {
|
||||
bool found = false;
|
||||
for (auto &n : neighbours_) {
|
||||
|
@ -301,7 +301,7 @@ void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers,
|
|||
auto t = td::Clocks::system();
|
||||
while (v.size() < max_peers && v.size() < peers_.size() - bad_peers_.size()) {
|
||||
auto P = peers_.get_random();
|
||||
if (P->get_version() + 3600 < t) {
|
||||
if (public_ && P->get_version() + 3600 < t) {
|
||||
VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id();
|
||||
del_peer(P->get_id());
|
||||
} else if (P->is_alive()) {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
## 2024.04 Update
|
||||
|
||||
1. Emulator: Single call optimized runGetMethod added
|
||||
2. Tonlib: a series of proof improvements, also breaking Change in `liteServer.getAllShardsInfo` method (see below)
|
||||
3. DB: usage statistics now collected, outdated persistent states are not serialized
|
||||
4. LS: fast `getOutMsgQueueSizes` added, preliminary support of non-final block requests
|
||||
5. Network: lz4 compression of block candidates (disabled by default).
|
||||
6. Overlays: add custom overlays
|
||||
7. Transaction Executor: fixed issue with due_payment collection
|
||||
|
||||
* `liteServer.getAllShardsInfo` method was updated for better efficiency. Previously, field proof contained BoC with two roots: one for BlockState from block's root and another for ShardHashes from BlockState. Now, it returns a single-root proof BoC, specifically the merkle proof of ShardHashes directly from the block's root, streamlining data access and integrity. Checking of the proof requires to check that ShardHashes in the `data` correspond to ShardHashes from the block.
|
||||
|
||||
Besides the work of the core team, this update is based on the efforts of @akifoq (due_payment issue).
|
||||
1. Make Jemalloc default allocator
|
||||
2. Add candidate broadcasting and caching
|
||||
3. Limit per address speed for external messages broadcast by reasonably large number
|
||||
4. Overlay improvements: fix dropping peers in small custom overlays, fix wrong certificate on missed keyblocks
|
||||
5. Extended statistics and logs for celldb usage, session stats, persistent state serialization
|
||||
6. Tonlib and explorer fixes
|
||||
7. Flags for precize control of Celldb: `--celldb-cache-size`, `--celldb-direct-io` and `--celldb-preload-all`
|
||||
8. Add valiator-console command to stop persistent state serialization
|
||||
9. Use `@` path separator for defining include path in fift and create-state utilities on Windows only.
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include <functional>
|
||||
namespace td {
|
||||
class KeyValueReader {
|
||||
public:
|
||||
|
@ -27,6 +28,9 @@ class KeyValueReader {
|
|||
|
||||
virtual Result<GetStatus> get(Slice key, std::string &value) = 0;
|
||||
virtual Result<size_t> count(Slice prefix) = 0;
|
||||
virtual Status for_each(std::function<Status(Slice, Slice)> f) {
|
||||
return Status::Error("for_each is not supported");
|
||||
}
|
||||
};
|
||||
|
||||
class PrefixedKeyValueReader : public KeyValueReader {
|
||||
|
|
|
@ -56,41 +56,45 @@ RocksDb::~RocksDb() {
|
|||
}
|
||||
|
||||
RocksDb RocksDb::clone() const {
|
||||
return RocksDb{db_, statistics_};
|
||||
return RocksDb{db_, options_};
|
||||
}
|
||||
|
||||
Result<RocksDb> RocksDb::open(std::string path, std::shared_ptr<rocksdb::Statistics> statistics) {
|
||||
Result<RocksDb> RocksDb::open(std::string path, RocksDbOptions options) {
|
||||
rocksdb::OptimisticTransactionDB *db;
|
||||
{
|
||||
rocksdb::Options options;
|
||||
rocksdb::Options db_options;
|
||||
|
||||
static auto cache = rocksdb::NewLRUCache(1 << 30);
|
||||
static auto default_cache = rocksdb::NewLRUCache(1 << 30);
|
||||
if (options.block_cache == nullptr) {
|
||||
options.block_cache = default_cache;
|
||||
}
|
||||
|
||||
rocksdb::BlockBasedTableOptions table_options;
|
||||
table_options.block_cache = cache;
|
||||
options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(table_options));
|
||||
table_options.block_cache = options.block_cache;
|
||||
db_options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(table_options));
|
||||
|
||||
options.manual_wal_flush = true;
|
||||
options.create_if_missing = true;
|
||||
options.max_background_compactions = 4;
|
||||
options.max_background_flushes = 2;
|
||||
options.bytes_per_sync = 1 << 20;
|
||||
options.writable_file_max_buffer_size = 2 << 14;
|
||||
options.statistics = statistics;
|
||||
db_options.use_direct_reads = options.use_direct_reads;
|
||||
db_options.manual_wal_flush = true;
|
||||
db_options.create_if_missing = true;
|
||||
db_options.max_background_compactions = 4;
|
||||
db_options.max_background_flushes = 2;
|
||||
db_options.bytes_per_sync = 1 << 20;
|
||||
db_options.writable_file_max_buffer_size = 2 << 14;
|
||||
db_options.statistics = options.statistics;
|
||||
rocksdb::OptimisticTransactionDBOptions occ_options;
|
||||
occ_options.validate_policy = rocksdb::OccValidationPolicy::kValidateSerial;
|
||||
rocksdb::ColumnFamilyOptions cf_options(options);
|
||||
rocksdb::ColumnFamilyOptions cf_options(db_options);
|
||||
std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
|
||||
column_families.push_back(rocksdb::ColumnFamilyDescriptor(rocksdb::kDefaultColumnFamilyName, cf_options));
|
||||
std::vector<rocksdb::ColumnFamilyHandle *> handles;
|
||||
TRY_STATUS(from_rocksdb(
|
||||
rocksdb::OptimisticTransactionDB::Open(options, occ_options, std::move(path), column_families, &handles, &db)));
|
||||
TRY_STATUS(from_rocksdb(rocksdb::OptimisticTransactionDB::Open(db_options, occ_options, std::move(path),
|
||||
column_families, &handles, &db)));
|
||||
CHECK(handles.size() == 1);
|
||||
// i can delete the handle since DBImpl is always holding a reference to
|
||||
// default column family
|
||||
delete handles[0];
|
||||
}
|
||||
return RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB>(db), std::move(statistics));
|
||||
return RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB>(db), std::move(options));
|
||||
}
|
||||
|
||||
std::shared_ptr<rocksdb::Statistics> RocksDb::create_statistics() {
|
||||
|
@ -105,6 +109,10 @@ void RocksDb::reset_statistics(const std::shared_ptr<rocksdb::Statistics> statis
|
|||
statistics->Reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<rocksdb::Cache> RocksDb::create_cache(size_t capacity) {
|
||||
return rocksdb::NewLRUCache(capacity);
|
||||
}
|
||||
|
||||
std::unique_ptr<KeyValueReader> RocksDb::snapshot() {
|
||||
auto res = std::make_unique<RocksDb>(clone());
|
||||
res->begin_snapshot().ensure();
|
||||
|
@ -116,7 +124,6 @@ std::string RocksDb::stats() const {
|
|||
db_->GetProperty("rocksdb.stats", &out);
|
||||
//db_->GetProperty("rocksdb.cur-size-all-mem-tables", &out);
|
||||
return out;
|
||||
return statistics_->ToString();
|
||||
}
|
||||
|
||||
Result<RocksDb::GetStatus> RocksDb::get(Slice key, std::string &value) {
|
||||
|
@ -183,6 +190,28 @@ Result<size_t> RocksDb::count(Slice prefix) {
|
|||
return res;
|
||||
}
|
||||
|
||||
Status RocksDb::for_each(std::function<Status(Slice, Slice)> f) {
|
||||
rocksdb::ReadOptions options;
|
||||
options.snapshot = snapshot_.get();
|
||||
std::unique_ptr<rocksdb::Iterator> iterator;
|
||||
if (snapshot_ || !transaction_) {
|
||||
iterator.reset(db_->NewIterator(options));
|
||||
} else {
|
||||
iterator.reset(transaction_->GetIterator(options));
|
||||
}
|
||||
|
||||
iterator->SeekToFirst();
|
||||
for (; iterator->Valid(); iterator->Next()) {
|
||||
auto key = from_rocksdb(iterator->key());
|
||||
auto value = from_rocksdb(iterator->value());
|
||||
TRY_STATUS(f(key, value));
|
||||
}
|
||||
if (!iterator->status().ok()) {
|
||||
return from_rocksdb(iterator->status());
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDb::begin_write_batch() {
|
||||
CHECK(!transaction_);
|
||||
write_batch_ = std::make_unique<rocksdb::WriteBatch>();
|
||||
|
@ -239,7 +268,7 @@ Status RocksDb::end_snapshot() {
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
RocksDb::RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB> db, std::shared_ptr<rocksdb::Statistics> statistics)
|
||||
: db_(std::move(db)), statistics_(std::move(statistics)) {
|
||||
RocksDb::RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB> db, RocksDbOptions options)
|
||||
: db_(std::move(db)), options_(options) {
|
||||
}
|
||||
} // namespace td
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
|
||||
#include "td/db/KeyValue.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/optional.h"
|
||||
|
||||
namespace rocksdb {
|
||||
class Cache;
|
||||
class OptimisticTransactionDB;
|
||||
class Transaction;
|
||||
class WriteBatch;
|
||||
|
@ -34,16 +36,24 @@ class Statistics;
|
|||
} // namespace rocksdb
|
||||
|
||||
namespace td {
|
||||
|
||||
struct RocksDbOptions {
|
||||
std::shared_ptr<rocksdb::Statistics> statistics = nullptr;
|
||||
std::shared_ptr<rocksdb::Cache> block_cache; // Default - one 1G cache for all RocksDb
|
||||
bool use_direct_reads = false;
|
||||
};
|
||||
|
||||
class RocksDb : public KeyValue {
|
||||
public:
|
||||
static Status destroy(Slice path);
|
||||
RocksDb clone() const;
|
||||
static Result<RocksDb> open(std::string path, std::shared_ptr<rocksdb::Statistics> statistics = nullptr);
|
||||
static Result<RocksDb> open(std::string path, RocksDbOptions options = {});
|
||||
|
||||
Result<GetStatus> get(Slice key, std::string &value) override;
|
||||
Status set(Slice key, Slice value) override;
|
||||
Status erase(Slice key) override;
|
||||
Result<size_t> count(Slice prefix) override;
|
||||
Status for_each(std::function<Status(Slice, Slice)> f) override;
|
||||
|
||||
Status begin_write_batch() override;
|
||||
Status commit_write_batch() override;
|
||||
|
@ -64,6 +74,8 @@ class RocksDb : public KeyValue {
|
|||
static std::string statistics_to_string(const std::shared_ptr<rocksdb::Statistics> statistics);
|
||||
static void reset_statistics(const std::shared_ptr<rocksdb::Statistics> statistics);
|
||||
|
||||
static std::shared_ptr<rocksdb::Cache> create_cache(size_t capacity);
|
||||
|
||||
RocksDb(RocksDb &&);
|
||||
RocksDb &operator=(RocksDb &&);
|
||||
~RocksDb();
|
||||
|
@ -74,7 +86,7 @@ class RocksDb : public KeyValue {
|
|||
|
||||
private:
|
||||
std::shared_ptr<rocksdb::OptimisticTransactionDB> db_;
|
||||
std::shared_ptr<rocksdb::Statistics> statistics_;
|
||||
RocksDbOptions options_;
|
||||
|
||||
std::unique_ptr<rocksdb::Transaction> transaction_;
|
||||
std::unique_ptr<rocksdb::WriteBatch> write_batch_;
|
||||
|
@ -87,7 +99,6 @@ class RocksDb : public KeyValue {
|
|||
};
|
||||
std::unique_ptr<const rocksdb::Snapshot, UnreachableDeleter> snapshot_;
|
||||
|
||||
explicit RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB> db,
|
||||
std::shared_ptr<rocksdb::Statistics> statistics);
|
||||
explicit RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB> db, RocksDbOptions options);
|
||||
};
|
||||
} // namespace td
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "Status.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
|
@ -38,6 +39,12 @@ class CancellationToken {
|
|||
}
|
||||
return token_->is_cancelled_.load(std::memory_order_acquire);
|
||||
}
|
||||
Status check() const {
|
||||
if (*this) {
|
||||
return Status::Error(653, "cancelled"); // cancelled = 653
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
CancellationToken() = default;
|
||||
explicit CancellationToken(std::shared_ptr<detail::RawCancellationToken> token) : token_(std::move(token)) {
|
||||
}
|
||||
|
|
|
@ -87,4 +87,8 @@ void PerfWarningTimer::reset() {
|
|||
start_at_ = 0;
|
||||
}
|
||||
|
||||
double PerfWarningTimer::elapsed() const {
|
||||
return Time::now() - start_at_;
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -53,6 +53,7 @@ class PerfWarningTimer {
|
|||
PerfWarningTimer &operator=(PerfWarningTimer &&) = delete;
|
||||
~PerfWarningTimer();
|
||||
void reset();
|
||||
double elapsed() const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
|
|
|
@ -347,7 +347,10 @@ class TestNode : public td::actor::Actor {
|
|||
}
|
||||
}
|
||||
}
|
||||
void send_broadcast(ton::BlockBroadcast broadcast) override {
|
||||
void send_block_candidate(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) override {
|
||||
}
|
||||
void send_broadcast(ton::BlockBroadcast broadcast, bool custom_overlays_only) override {
|
||||
}
|
||||
void download_block(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ton::ReceivedBlock> promise) override {
|
||||
|
|
|
@ -98,7 +98,7 @@ liteServer.getLibrariesWithProof id:tonNode.blockIdExt mode:# library_list:(vect
|
|||
liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof;
|
||||
liteServer.getOutMsgQueueSizes mode:# wc:mode.0?int shard:mode.0?long = liteServer.OutMsgQueueSizes;
|
||||
|
||||
liteServer.nonfinal.getValidatorGroups mode:# wc:mode.0?int shard:mode.1?long = liteServer.nonfinal.ValidatorGroups;
|
||||
liteServer.nonfinal.getValidatorGroups mode:# wc:mode.0?int shard:mode.0?long = liteServer.nonfinal.ValidatorGroups;
|
||||
liteServer.nonfinal.getCandidate id:liteServer.nonfinal.candidateId = liteServer.nonfinal.Candidate;
|
||||
|
||||
liteServer.queryPrefix = Object;
|
||||
|
|
Binary file not shown.
|
@ -396,6 +396,11 @@ tonNode.blockBroadcastCompressed id:tonNode.blockIdExt catchain_seqno:int valida
|
|||
tonNode.ihrMessageBroadcast message:tonNode.ihrMessage = tonNode.Broadcast;
|
||||
tonNode.externalMessageBroadcast message:tonNode.externalMessage = tonNode.Broadcast;
|
||||
tonNode.newShardBlockBroadcast block:tonNode.newShardBlock = tonNode.Broadcast;
|
||||
// signature may be empty, at least for now
|
||||
tonNode.newBlockCandidateBroadcast id:tonNode.blockIdExt catchain_seqno:int validator_set_hash:int
|
||||
collator_signature:tonNode.blockSignature data:bytes = tonNode.Broadcast;
|
||||
tonNode.newBlockCandidateBroadcastCompressed id:tonNode.blockIdExt catchain_seqno:int validator_set_hash:int
|
||||
collator_signature:tonNode.blockSignature flags:# compressed:bytes = tonNode.Broadcast;
|
||||
|
||||
tonNode.shardPublicOverlayId workchain:int shard:long zero_state_file_hash:int256 = tonNode.ShardPublicOverlayId;
|
||||
|
||||
|
@ -587,15 +592,17 @@ engine.dht.config dht:(vector engine.dht) gc:engine.gc = engine.dht.Config;
|
|||
engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNodeMaster;
|
||||
engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
|
||||
engine.validator.fullNodeConfig ext_messages_broadcast_disabled:Bool = engine.validator.FullNodeConfig;
|
||||
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
|
||||
engine.validator.extraConfig state_serializer_enabled:Bool = engine.validator.ExtraConfig;
|
||||
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
|
||||
dht:(vector engine.dht)
|
||||
validators:(vector engine.validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave)
|
||||
fullnodemasters:(vector engine.validator.fullNodeMaster)
|
||||
fullnodeconfig:engine.validator.fullNodeConfig
|
||||
extraconfig:engine.validator.extraConfig
|
||||
liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
|
||||
gc:engine.gc = engine.validator.Config;
|
||||
|
||||
engine.validator.customOverlayNode adnl_id:int256 msg_sender:Bool msg_sender_priority:int = engine.validator.CustomOverlayNode;
|
||||
engine.validator.customOverlayNode adnl_id:int256 msg_sender:Bool msg_sender_priority:int block_sender:Bool = engine.validator.CustomOverlayNode;
|
||||
engine.validator.customOverlay name:string nodes:(vector engine.validator.customOverlayNode) = engine.validator.CustomOverlay;
|
||||
engine.validator.customOverlaysConfig overlays:(vector engine.validator.customOverlay) = engine.validator.CustomOverlaysConfig;
|
||||
|
||||
|
@ -706,6 +713,8 @@ engine.validator.addCustomOverlay overlay:engine.validator.customOverlay = engin
|
|||
engine.validator.delCustomOverlay name:string = engine.validator.Success;
|
||||
engine.validator.showCustomOverlays = engine.validator.CustomOverlaysConfig;
|
||||
|
||||
engine.validator.setStateSerializerEnabled enabled:Bool = engine.validator.Success;
|
||||
|
||||
---types---
|
||||
|
||||
storage.pong = storage.Pong;
|
||||
|
@ -752,15 +761,26 @@ http.server.config dhs:(vector http.server.dnsEntry) local_hosts:(vector http.se
|
|||
|
||||
---types---
|
||||
|
||||
validatorSession.statsProducer id:int256 candidate_id:int256 block_status:int block_timestamp:long comment:string = validatorSession.StatsProducer;
|
||||
validatorSession.statsProducer id:int256 candidate_id:int256 block_status:int comment:string
|
||||
block_timestamp:double is_accepted:Bool is_ours:Bool got_submit_at:double
|
||||
collation_time:double collated_at:double collation_cached:Bool
|
||||
validation_time:double validated_at:double validation_cached:Bool
|
||||
gen_utime:double
|
||||
approved_weight:long approved_33pct_at:double approved_66pct_at:double
|
||||
signed_weight:long signed_33pct_at:double signed_66pct_at:double
|
||||
serialize_time:double deserialize_time:double serialized_size:int = validatorSession.StatsProducer;
|
||||
|
||||
validatorSession.statsRound timestamp:long producers:(vector validatorSession.statsProducer) = validatorSession.StatsRound;
|
||||
validatorSession.statsRound timestamp:double producers:(vector validatorSession.statsProducer) = validatorSession.StatsRound;
|
||||
|
||||
validatorSession.stats success:Bool id:tonNode.blockIdExt timestamp:long self:int256 session_id:int256 cc_seqno:int
|
||||
validatorSession.stats success:Bool id:tonNode.blockIdExt timestamp:double self:int256 session_id:int256 cc_seqno:int
|
||||
creator:int256 total_validators:int total_weight:long
|
||||
signatures:int signatures_weight:long approve_signatures:int approve_signatures_weight:long
|
||||
first_round:int rounds:(vector validatorSession.statsRound) = validatorSession.Stats;
|
||||
|
||||
validatorSession.newValidatorGroupStats.node id:int256 weight:long = validatorSession.newValidatorGroupStats.Node;
|
||||
validatorSession.newValidatorGroupStats session_id:int256 workchain:int shard:long cc_seqno:int timestamp:double
|
||||
self_idx:int nodes:(vector validatorSession.newValidatorGroupStats.node) = validatorSession.NewValidatorGroupStats;
|
||||
|
||||
---functions---
|
||||
|
||||
---types---
|
||||
|
|
Binary file not shown.
|
@ -344,6 +344,10 @@ struct BlockSignature {
|
|||
struct ReceivedBlock {
|
||||
BlockIdExt id;
|
||||
td::BufferSlice data;
|
||||
|
||||
ReceivedBlock clone() const {
|
||||
return ReceivedBlock{id, data.clone()};
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockBroadcast {
|
||||
|
|
|
@ -1891,7 +1891,9 @@ class RunEmulator : public TonlibQueryActor {
|
|||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
get_block_id([self = this](td::Result<FullBlockId>&& block_id) { self->set_block_id(std::move(block_id)); });
|
||||
get_block_id([SelfId = actor_id(this)](td::Result<FullBlockId>&& block_id) {
|
||||
td::actor::send_closure(SelfId, &RunEmulator::set_block_id, std::move(block_id));
|
||||
});
|
||||
}
|
||||
|
||||
void set_block_id(td::Result<FullBlockId>&& block_id) {
|
||||
|
@ -1900,8 +1902,12 @@ class RunEmulator : public TonlibQueryActor {
|
|||
} else {
|
||||
block_id_ = block_id.move_as_ok();
|
||||
|
||||
get_mc_state_root([self = this](td::Result<td::Ref<vm::Cell>>&& mc_state_root) { self->set_mc_state_root(std::move(mc_state_root)); });
|
||||
get_account_state([self = this](td::Result<td::unique_ptr<AccountState>>&& state) { self->set_account_state(std::move(state)); });
|
||||
get_mc_state_root([SelfId = actor_id(this)](td::Result<td::Ref<vm::Cell>>&& mc_state_root) {
|
||||
td::actor::send_closure(SelfId, &RunEmulator::set_mc_state_root, std::move(mc_state_root));
|
||||
});
|
||||
get_account_state([SelfId = actor_id(this)](td::Result<td::unique_ptr<AccountState>>&& state) {
|
||||
td::actor::send_closure(SelfId, &RunEmulator::set_account_state, std::move(state));
|
||||
});
|
||||
check(get_transactions(0));
|
||||
|
||||
inc();
|
||||
|
@ -1923,7 +1929,9 @@ class RunEmulator : public TonlibQueryActor {
|
|||
} else {
|
||||
account_state_ = account_state.move_as_ok();
|
||||
send_query(int_api::ScanAndLoadGlobalLibs{account_state_->get_raw_state()},
|
||||
[self = this](td::Result<vm::Dictionary> R) { self->set_global_libraries(std::move(R)); });
|
||||
[SelfId = actor_id(this)](td::Result<vm::Dictionary> R) {
|
||||
td::actor::send_closure(SelfId, &RunEmulator::set_global_libraries, std::move(R));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5521,7 +5529,7 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getShards& request,
|
|||
}
|
||||
|
||||
block::ShardConfig sh_conf;
|
||||
if (!sh_conf.unpack(mc_extra.shard_hashes)) {
|
||||
if (!sh_conf.unpack(data_csr)) {
|
||||
return td::Status::Error("cannot extract shard block list from shard configuration");
|
||||
}
|
||||
auto ids = sh_conf.get_shard_hash_ids(true);
|
||||
|
@ -5544,7 +5552,9 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getShards& request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>& result, int mode, ton::BlockId blkid, ton::BlockIdExt client_mc_blkid, td::uint64 lt, td::uint32 utime);
|
||||
td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>& result, int mode,
|
||||
ton::BlockId blkid, ton::BlockIdExt client_mc_blkid, td::uint64 lt,
|
||||
td::uint32 utime);
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& request,
|
||||
td::Promise<object_ptr<tonlib_api::ton_blockIdExt>>&& promise) {
|
||||
|
@ -5730,7 +5740,7 @@ auto to_tonlib_api(const ton::lite_api::liteServer_transactionId& txid)
|
|||
|
||||
td::Status check_block_transactions_proof(lite_api_ptr<ton::lite_api::liteServer_blockTransactions>& bTxes, int32_t mode,
|
||||
ton::LogicalTime start_lt, td::Bits256 start_addr, td::Bits256 root_hash, int req_count) {
|
||||
if (mode & ton::lite_api::liteServer_listBlockTransactions::WANT_PROOF_MASK == 0) {
|
||||
if ((mode & ton::lite_api::liteServer_listBlockTransactions::WANT_PROOF_MASK) == 0) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
constexpr int max_answer_transactions = 256;
|
||||
|
|
|
@ -1423,7 +1423,8 @@ class TonlibCli : public td::actor::Actor {
|
|||
if (r_cell.is_error()) {
|
||||
sb << "<INVALID_CELL>";
|
||||
}
|
||||
auto cs = vm::load_cell_slice(r_cell.move_as_ok());
|
||||
bool spec = true;
|
||||
auto cs = vm::load_cell_slice_special(r_cell.move_as_ok(), spec);
|
||||
std::stringstream ss;
|
||||
cs.print_rec(ss);
|
||||
sb << ss.str();
|
||||
|
|
|
@ -1171,11 +1171,35 @@ td::Status ShowCustomOverlaysQuery::receive(td::BufferSlice data) {
|
|||
td::TerminalIO::out() << "Overlay \"" << overlay->name_ << "\": " << overlay->nodes_.size() << " nodes\n";
|
||||
for (const auto &node : overlay->nodes_) {
|
||||
td::TerminalIO::out() << " " << node->adnl_id_
|
||||
<< (node->msg_sender_ ? (PSTRING() << " (sender, p=" << node->msg_sender_priority_ << ")")
|
||||
: "")
|
||||
<< "\n";
|
||||
<< (node->msg_sender_
|
||||
? (PSTRING() << " (msg sender, p=" << node->msg_sender_priority_ << ")")
|
||||
: "")
|
||||
<< (node->block_sender_ ? " (block sender)" : "") << "\n";
|
||||
}
|
||||
td::TerminalIO::out() << "\n";
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status SetStateSerializerEnabledQuery::run() {
|
||||
TRY_RESULT(value, tokenizer_.get_token<int>());
|
||||
if (value != 0 && value != 1) {
|
||||
return td::Status::Error("expected 0 or 1");
|
||||
}
|
||||
TRY_STATUS(tokenizer_.check_endl());
|
||||
enabled_ = value;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status SetStateSerializerEnabledQuery::send() {
|
||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_setStateSerializerEnabled>(enabled_);
|
||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status SetStateSerializerEnabledQuery::receive(td::BufferSlice data) {
|
||||
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
|
||||
"received incorrect answer: ");
|
||||
td::TerminalIO::out() << "success\n";
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
|
|
@ -1207,3 +1207,25 @@ class ShowCustomOverlaysQuery : public Query {
|
|||
return get_name();
|
||||
}
|
||||
};
|
||||
|
||||
class SetStateSerializerEnabledQuery : public Query {
|
||||
public:
|
||||
SetStateSerializerEnabledQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||
: Query(console, std::move(tokenizer)) {
|
||||
}
|
||||
td::Status run() override;
|
||||
td::Status send() override;
|
||||
td::Status receive(td::BufferSlice data) override;
|
||||
static std::string get_name() {
|
||||
return "setstateserializerenabled";
|
||||
}
|
||||
static std::string get_help() {
|
||||
return "setstateserializerenabled <value>\tdisable or enable persistent state serializer; value is 0 or 1";
|
||||
}
|
||||
std::string name() const override {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
private:
|
||||
bool enabled_;
|
||||
};
|
||||
|
|
|
@ -146,6 +146,7 @@ void ValidatorEngineConsole::run() {
|
|||
add_query_runner(std::make_unique<QueryRunnerImpl<AddCustomOverlayQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<DelCustomOverlayQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<ShowCustomOverlaysQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<SetStateSerializerEnabledQuery>>());
|
||||
}
|
||||
|
||||
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include "block-parse.h"
|
||||
#include "common/delay.h"
|
||||
#include "block/precompiled-smc/PrecompiledSmartContract.h"
|
||||
#include "interfaces/validator-manager.h"
|
||||
|
||||
Config::Config() {
|
||||
out_port = 3278;
|
||||
|
@ -155,6 +156,11 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
|
|||
if (config.fullnodeconfig_) {
|
||||
full_node_config = ton::validator::fullnode::FullNodeConfig(config.fullnodeconfig_);
|
||||
}
|
||||
if (config.extraconfig_) {
|
||||
state_serializer_enabled = config.extraconfig_->state_serializer_enabled_;
|
||||
} else {
|
||||
state_serializer_enabled = true;
|
||||
}
|
||||
|
||||
for (auto &serv : config.liteservers_) {
|
||||
config_add_lite_server(ton::PublicKeyHash{serv->id_}, serv->port_).ensure();
|
||||
|
@ -231,6 +237,12 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
full_node_config_obj = full_node_config.tl();
|
||||
}
|
||||
|
||||
ton::tl_object_ptr<ton::ton_api::engine_validator_extraConfig> extra_config_obj = {};
|
||||
if (!state_serializer_enabled) {
|
||||
// Non-default values
|
||||
extra_config_obj = ton::create_tl_object<ton::ton_api::engine_validator_extraConfig>(state_serializer_enabled);
|
||||
}
|
||||
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::engine_liteServer>> liteserver_vec;
|
||||
for (auto &x : liteservers) {
|
||||
liteserver_vec.push_back(ton::create_tl_object<ton::ton_api::engine_liteServer>(x.second.tl(), x.first));
|
||||
|
@ -253,7 +265,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
return ton::create_tl_object<ton::ton_api::engine_validator_config>(
|
||||
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), full_node.tl(),
|
||||
std::move(full_node_slaves_vec), std::move(full_node_masters_vec), std::move(full_node_config_obj),
|
||||
std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
|
||||
std::move(extra_config_obj), std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
|
||||
|
@ -1369,6 +1381,17 @@ td::Status ValidatorEngine::load_global_config() {
|
|||
validator_options_.write().set_archive_preload_period(archive_preload_period_);
|
||||
validator_options_.write().set_disable_rocksdb_stats(disable_rocksdb_stats_);
|
||||
validator_options_.write().set_nonfinal_ls_queries_enabled(nonfinal_ls_queries_enabled_);
|
||||
if (celldb_cache_size_) {
|
||||
validator_options_.write().set_celldb_cache_size(celldb_cache_size_.value());
|
||||
}
|
||||
if (!celldb_cache_size_ || celldb_cache_size_.value() < (30ULL << 30)) {
|
||||
celldb_direct_io_ = false;
|
||||
}
|
||||
validator_options_.write().set_celldb_direct_io(celldb_direct_io_);
|
||||
validator_options_.write().set_celldb_preload_all(celldb_preload_all_);
|
||||
if (catchain_max_block_delay_) {
|
||||
validator_options_.write().set_catchain_max_block_delay(catchain_max_block_delay_.value());
|
||||
}
|
||||
|
||||
std::vector<ton::BlockIdExt> h;
|
||||
for (auto &x : conf.validator_->hardforks_) {
|
||||
|
@ -1388,6 +1411,7 @@ td::Status ValidatorEngine::load_global_config() {
|
|||
h.push_back(b);
|
||||
}
|
||||
validator_options_.write().set_hardforks(std::move(h));
|
||||
validator_options_.write().set_state_serializer_enabled(config_.state_serializer_enabled);
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -2357,16 +2381,9 @@ void ValidatorEngine::load_custom_overlays_config() {
|
|||
}
|
||||
|
||||
for (auto &overlay : custom_overlays_config_->overlays_) {
|
||||
std::vector<ton::adnl::AdnlNodeIdShort> nodes;
|
||||
std::map<ton::adnl::AdnlNodeIdShort, int> senders;
|
||||
for (const auto &node : overlay->nodes_) {
|
||||
nodes.emplace_back(node->adnl_id_);
|
||||
if (node->msg_sender_) {
|
||||
senders[ton::adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
|
||||
}
|
||||
}
|
||||
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_ext_msg_overlay, std::move(nodes),
|
||||
std::move(senders), overlay->name_, [](td::Result<td::Unit> R) { R.ensure(); });
|
||||
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_custom_overlay,
|
||||
ton::validator::fullnode::CustomOverlayParams::fetch(*overlay),
|
||||
[](td::Result<td::Unit> R) { R.ensure(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3571,11 +3588,10 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCustom
|
|||
senders[ton::adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
|
||||
}
|
||||
}
|
||||
std::string name = overlay->name_;
|
||||
auto params = ton::validator::fullnode::CustomOverlayParams::fetch(*query.overlay_);
|
||||
td::actor::send_closure(
|
||||
full_node_, &ton::validator::fullnode::FullNode::add_ext_msg_overlay, std::move(nodes), std::move(senders),
|
||||
std::move(name),
|
||||
[SelfId = actor_id(this), overlay = std::move(overlay),
|
||||
full_node_, &ton::validator::fullnode::FullNode::add_custom_overlay, std::move(params),
|
||||
[SelfId = actor_id(this), overlay = std::move(query.overlay_),
|
||||
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
|
@ -3605,7 +3621,7 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delCustom
|
|||
return;
|
||||
}
|
||||
td::actor::send_closure(
|
||||
full_node_, &ton::validator::fullnode::FullNode::del_ext_msg_overlay, query.name_,
|
||||
full_node_, &ton::validator::fullnode::FullNode::del_custom_overlay, query.name_,
|
||||
[SelfId = actor_id(this), name = query.name_, promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
|
@ -3639,6 +3655,34 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_showCusto
|
|||
custom_overlays_config_, true));
|
||||
}
|
||||
|
||||
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_setStateSerializerEnabled &query,
|
||||
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
||||
return;
|
||||
}
|
||||
if (!started_) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
||||
return;
|
||||
}
|
||||
if (query.enabled_ == validator_options_->get_state_serializer_enabled()) {
|
||||
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_success>());
|
||||
return;
|
||||
}
|
||||
validator_options_.write().set_state_serializer_enabled(query.enabled_);
|
||||
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
|
||||
validator_options_);
|
||||
config_.state_serializer_enabled = query.enabled_;
|
||||
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
} else {
|
||||
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_success>());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
|
||||
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
@ -3853,7 +3897,7 @@ int main(int argc, char *argv[]) {
|
|||
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_max_mempool_num, v); });
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_checked_option('b', "block-ttl", "blocks will be gc'd after this time (in seconds) default=7*86400",
|
||||
p.add_checked_option('b', "block-ttl", "blocks will be gc'd after this time (in seconds) default=86400",
|
||||
[&](td::Slice fname) {
|
||||
auto v = td::to_double(fname);
|
||||
if (v <= 0) {
|
||||
|
@ -3863,7 +3907,7 @@ int main(int argc, char *argv[]) {
|
|||
return td::Status::OK();
|
||||
});
|
||||
p.add_checked_option(
|
||||
'A', "archive-ttl", "archived blocks will be deleted after this time (in seconds) default=365*86400",
|
||||
'A', "archive-ttl", "archived blocks will be deleted after this time (in seconds) default=7*86400",
|
||||
[&](td::Slice fname) {
|
||||
auto v = td::to_double(fname);
|
||||
if (v <= 0) {
|
||||
|
@ -3975,6 +4019,33 @@ int main(int argc, char *argv[]) {
|
|||
p.add_option('\0', "nonfinal-ls", "enable special LS queries to non-finalized blocks", [&]() {
|
||||
acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_nonfinal_ls_queries_enabled); });
|
||||
});
|
||||
p.add_checked_option(
|
||||
'\0', "celldb-cache-size", "block cache size for RocksDb in CellDb, in bytes (default: 1G)",
|
||||
[&](td::Slice s) -> td::Status {
|
||||
TRY_RESULT(v, td::to_integer_safe<td::uint64>(s));
|
||||
if (v == 0) {
|
||||
return td::Status::Error("celldb-cache-size should be positive");
|
||||
}
|
||||
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_celldb_cache_size, v); });
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option(
|
||||
'\0', "celldb-direct-io", "enable direct I/O mode for RocksDb in CellDb (doesn't apply when celldb cache is < 30G)",
|
||||
[&]() { acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_celldb_direct_io, true); }); });
|
||||
p.add_option(
|
||||
'\0', "celldb-preload-all",
|
||||
"preload all cells from CellDb on startup (recommended to use with big enough celldb-cache-size and celldb-direct-io)",
|
||||
[&]() { acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_celldb_preload_all, true); }); });
|
||||
p.add_checked_option(
|
||||
'\0', "catchain-max-block-delay", "delay before creating a new catchain block, in seconds (default: 0.5)",
|
||||
[&](td::Slice s) -> td::Status {
|
||||
auto v = td::to_double(s);
|
||||
if (v < 0) {
|
||||
return td::Status::Error("catchain-max-block-delay should be non-negative");
|
||||
}
|
||||
acts.push_back([&x, v]() { td::actor::send_closure(x, &ValidatorEngine::set_catchain_max_block_delay, v); });
|
||||
return td::Status::OK();
|
||||
});
|
||||
auto S = p.run(argc, argv);
|
||||
if (S.is_error()) {
|
||||
LOG(ERROR) << "failed to parse options: " << S.move_as_error();
|
||||
|
|
|
@ -90,6 +90,8 @@ struct Config {
|
|||
std::map<td::int32, Control> controls;
|
||||
std::set<ton::PublicKeyHash> gc;
|
||||
|
||||
bool state_serializer_enabled = true;
|
||||
|
||||
void decref(ton::PublicKeyHash key);
|
||||
void incref(ton::PublicKeyHash key) {
|
||||
keys_refcnt[key]++;
|
||||
|
@ -209,6 +211,10 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
double archive_preload_period_ = 0.0;
|
||||
bool disable_rocksdb_stats_ = false;
|
||||
bool nonfinal_ls_queries_enabled_ = false;
|
||||
td::optional<td::uint64> celldb_cache_size_ = 1LL << 30;
|
||||
bool celldb_direct_io_ = false;
|
||||
bool celldb_preload_all_ = false;
|
||||
td::optional<double> catchain_max_block_delay_;
|
||||
bool read_config_ = false;
|
||||
bool started_keyring_ = false;
|
||||
bool started_ = false;
|
||||
|
@ -281,6 +287,18 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
void set_nonfinal_ls_queries_enabled() {
|
||||
nonfinal_ls_queries_enabled_ = true;
|
||||
}
|
||||
void set_celldb_cache_size(td::uint64 value) {
|
||||
celldb_cache_size_ = value;
|
||||
}
|
||||
void set_celldb_direct_io(bool value) {
|
||||
celldb_direct_io_ = value;
|
||||
}
|
||||
void set_celldb_preload_all(bool value) {
|
||||
celldb_preload_all_ = value;
|
||||
}
|
||||
void set_catchain_max_block_delay(double value) {
|
||||
catchain_max_block_delay_ = value;
|
||||
}
|
||||
void start_up() override;
|
||||
ValidatorEngine() {
|
||||
}
|
||||
|
@ -457,6 +475,8 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_showCustomOverlays &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_setStateSerializerEnabled &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
template <class T>
|
||||
void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "candidate-serializer.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "vm/boc.h"
|
||||
|
|
|
@ -76,11 +76,60 @@ struct ValidatorSessionStats {
|
|||
PublicKeyHash id = PublicKeyHash::zero();
|
||||
ValidatorSessionCandidateId candidate_id = ValidatorSessionCandidateId::zero();
|
||||
int block_status = status_none;
|
||||
td::uint64 block_timestamp = 0;
|
||||
double block_timestamp = -1.0;
|
||||
std::string comment;
|
||||
|
||||
bool is_accepted = false;
|
||||
bool is_ours = false;
|
||||
double got_submit_at = -1.0;
|
||||
double collation_time = -1.0;
|
||||
double validation_time = -1.0;
|
||||
double collated_at = -1.0;
|
||||
double validated_at = -1.0;
|
||||
bool collation_cached = false;
|
||||
bool validation_cached = false;
|
||||
double gen_utime = -1.0;
|
||||
|
||||
std::vector<bool> approvers, signers;
|
||||
ValidatorWeight approved_weight = 0;
|
||||
ValidatorWeight signed_weight = 0;
|
||||
double approved_33pct_at = -1.0;
|
||||
double approved_66pct_at = -1.0;
|
||||
double signed_33pct_at = -1.0;
|
||||
double signed_66pct_at = -1.0;
|
||||
|
||||
double serialize_time = -1.0;
|
||||
double deserialize_time = -1.0;
|
||||
td::int32 serialized_size = -1;
|
||||
|
||||
void set_approved_by(td::uint32 id, ValidatorWeight weight, ValidatorWeight total_weight) {
|
||||
if (!approvers.at(id)) {
|
||||
approvers.at(id) = true;
|
||||
approved_weight += weight;
|
||||
if (approved_33pct_at <= 0.0 && approved_weight >= total_weight / 3 + 1) {
|
||||
approved_33pct_at = td::Clocks::system();
|
||||
}
|
||||
if (approved_66pct_at <= 0.0 && approved_weight >= (total_weight * 2) / 3 + 1) {
|
||||
approved_66pct_at = td::Clocks::system();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_signed_by(td::uint32 id, ValidatorWeight weight, ValidatorWeight total_weight) {
|
||||
if (!signers.at(id)) {
|
||||
signers.at(id) = true;
|
||||
signed_weight += weight;
|
||||
if (signed_33pct_at <= 0.0 && signed_weight >= total_weight / 3 + 1) {
|
||||
signed_33pct_at = td::Clocks::system();
|
||||
}
|
||||
if (signed_66pct_at <= 0.0 && signed_weight >= (total_weight * 2) / 3 + 1) {
|
||||
signed_66pct_at = td::Clocks::system();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
struct Round {
|
||||
td::uint64 timestamp = 0;
|
||||
double timestamp = -1.0;
|
||||
std::vector<Producer> producers;
|
||||
};
|
||||
|
||||
|
@ -90,7 +139,7 @@ struct ValidatorSessionStats {
|
|||
bool success = false;
|
||||
ValidatorSessionId session_id = ValidatorSessionId::zero();
|
||||
CatchainSeqno cc_seqno = 0;
|
||||
td::uint64 timestamp = 0;
|
||||
double timestamp = -1.0;
|
||||
PublicKeyHash self = PublicKeyHash::zero();
|
||||
PublicKeyHash creator = PublicKeyHash::zero();
|
||||
td::uint32 total_validators = 0;
|
||||
|
@ -101,6 +150,20 @@ struct ValidatorSessionStats {
|
|||
ValidatorWeight approve_signatures_weight = 0;
|
||||
};
|
||||
|
||||
struct NewValidatorGroupStats {
|
||||
struct Node {
|
||||
PublicKeyHash id = PublicKeyHash::zero();
|
||||
ValidatorWeight weight = 0;
|
||||
};
|
||||
|
||||
ValidatorSessionId session_id = ValidatorSessionId::zero();
|
||||
ShardIdFull shard{masterchainId};
|
||||
CatchainSeqno cc_seqno = 0;
|
||||
double timestamp = -1.0;
|
||||
td::uint32 self_idx = 0;
|
||||
std::vector<Node> nodes;
|
||||
};
|
||||
|
||||
} // namespace validatorsession
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "td/utils/Random.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "candidate-serializer.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -86,6 +87,7 @@ void ValidatorSessionImpl::process_blocks(std::vector<catchain::CatChainBlock *>
|
|||
|
||||
for (auto &msg : msgs) {
|
||||
VLOG(VALIDATOR_SESSION_INFO) << this << ": applying action: " << msg.get();
|
||||
stats_process_action(local_idx(), *msg);
|
||||
real_state_ = ValidatorSessionState::action(description(), real_state_, local_idx(), att, msg.get());
|
||||
}
|
||||
|
||||
|
@ -167,6 +169,7 @@ void ValidatorSessionImpl::preprocess_block(catchain::CatChainBlock *block) {
|
|||
for (auto &msg : B->actions_) {
|
||||
VLOG(VALIDATOR_SESSION_INFO) << this << "[node " << description().get_source_id(block->source()) << "][block "
|
||||
<< block->hash() << "]: applying action " << msg.get();
|
||||
stats_process_action(block->source(), *msg);
|
||||
state = ValidatorSessionState::action(description(), state, block->source(), att, msg.get());
|
||||
}
|
||||
state = ValidatorSessionState::make_all(description(), state, block->source(), att);
|
||||
|
@ -222,9 +225,11 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
|
|||
// Note: src is not necessarily equal to the sender of this message:
|
||||
// If requested using get_broadcast_p2p, src is the creator of the block, sender possibly is some other node.
|
||||
auto src_idx = description().get_source_idx(src);
|
||||
td::Timer deserialize_timer;
|
||||
auto R =
|
||||
deserialize_candidate(data, compress_block_candidates_,
|
||||
description().opts().max_block_size + description().opts().max_collated_data_size + 1024);
|
||||
double deserialize_time = deserialize_timer.elapsed();
|
||||
if (R.is_error()) {
|
||||
VLOG(VALIDATOR_SESSION_WARNING) << this << "[node " << src << "][broadcast " << sha256_bits256(data.as_slice())
|
||||
<< "]: failed to parse: " << R.move_as_error();
|
||||
|
@ -255,6 +260,18 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
|
|||
return;
|
||||
}
|
||||
|
||||
auto stat = stats_get_candidate_stat(block_round, src, block_id);
|
||||
if (stat) {
|
||||
if (stat->block_status == ValidatorSessionStats::status_none) {
|
||||
stat->block_status = ValidatorSessionStats::status_received;
|
||||
}
|
||||
if (stat->block_timestamp <= 0.0) {
|
||||
stat->block_timestamp = td::Clocks::system();
|
||||
}
|
||||
stat->deserialize_time = deserialize_time;
|
||||
stat->serialized_size = data.size();
|
||||
}
|
||||
|
||||
if ((td::int32)block_round < (td::int32)cur_round_ - MAX_PAST_ROUND_BLOCK ||
|
||||
block_round >= cur_round_ + MAX_FUTURE_ROUND_BLOCK) {
|
||||
VLOG(VALIDATOR_SESSION_NOTICE) << this << "[node " << src << "][broadcast " << block_id
|
||||
|
@ -291,7 +308,6 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
|
|||
CHECK(!pending_reject_.count(block_id));
|
||||
CHECK(!rejected_.count(block_id));
|
||||
|
||||
stats_set_candidate_status(cur_round_, src, block_id, ValidatorSessionStats::status_received);
|
||||
auto v = virtual_state_->choose_blocks_to_approve(description(), local_idx());
|
||||
for (auto &b : v) {
|
||||
if (b && SentBlock::get_block_id(b) == block_id) {
|
||||
|
@ -363,9 +379,16 @@ void ValidatorSessionImpl::process_query(PublicKeyHash src, td::BufferSlice data
|
|||
}
|
||||
|
||||
void ValidatorSessionImpl::candidate_decision_fail(td::uint32 round, ValidatorSessionCandidateId hash,
|
||||
std::string result, td::uint32 src, td::BufferSlice proof) {
|
||||
stats_set_candidate_status(round, description().get_source_id(src), hash, ValidatorSessionStats::status_rejected,
|
||||
result);
|
||||
std::string result, td::uint32 src, td::BufferSlice proof,
|
||||
double validation_time, bool validation_cached) {
|
||||
auto stat = stats_get_candidate_stat(round, description().get_source_id(src), hash);
|
||||
if (stat) {
|
||||
stat->block_status = ValidatorSessionStats::status_rejected;
|
||||
stat->comment = result;
|
||||
stat->validation_time = validation_time;
|
||||
stat->validated_at = td::Clocks::system();
|
||||
stat->validation_cached = validation_cached;
|
||||
}
|
||||
if (round != cur_round_) {
|
||||
return;
|
||||
}
|
||||
|
@ -379,9 +402,17 @@ void ValidatorSessionImpl::candidate_decision_fail(td::uint32 round, ValidatorSe
|
|||
}
|
||||
|
||||
void ValidatorSessionImpl::candidate_decision_ok(td::uint32 round, ValidatorSessionCandidateId hash, RootHash root_hash,
|
||||
FileHash file_hash, td::uint32 src, td::uint32 ok_from) {
|
||||
stats_set_candidate_status(round, description().get_source_id(src), hash, ValidatorSessionStats::status_approved,
|
||||
PSTRING() << "ts=" << ok_from);
|
||||
FileHash file_hash, td::uint32 src, td::uint32 ok_from,
|
||||
double validation_time, bool validation_cached) {
|
||||
auto stat = stats_get_candidate_stat(round, description().get_source_id(src), hash);
|
||||
if (stat) {
|
||||
stat->block_status = ValidatorSessionStats::status_approved;
|
||||
stat->comment = PSTRING() << "ts=" << ok_from;
|
||||
stat->validation_time = validation_time;
|
||||
stat->gen_utime = (double)ok_from;
|
||||
stat->validated_at = td::Clocks::system();
|
||||
stat->validation_cached = validation_cached;
|
||||
}
|
||||
if (round != cur_round_) {
|
||||
return;
|
||||
}
|
||||
|
@ -418,10 +449,8 @@ void ValidatorSessionImpl::candidate_approved_signed(td::uint32 round, Validator
|
|||
}
|
||||
|
||||
void ValidatorSessionImpl::generated_block(td::uint32 round, ValidatorSessionCandidateId root_hash,
|
||||
td::BufferSlice data, td::BufferSlice collated_data) {
|
||||
if (round != cur_round_) {
|
||||
return;
|
||||
}
|
||||
td::BufferSlice data, td::BufferSlice collated_data, double collation_time,
|
||||
bool collation_cached) {
|
||||
if (data.size() > description().opts().max_block_size ||
|
||||
collated_data.size() > description().opts().max_collated_data_size) {
|
||||
LOG(ERROR) << this << ": generated candidate is too big. Dropping. size=" << data.size() << " "
|
||||
|
@ -430,13 +459,27 @@ void ValidatorSessionImpl::generated_block(td::uint32 round, ValidatorSessionCan
|
|||
}
|
||||
auto file_hash = sha256_bits256(data.as_slice());
|
||||
auto collated_data_file_hash = sha256_bits256(collated_data.as_slice());
|
||||
auto block_id = description().candidate_id(local_idx(), root_hash, file_hash, collated_data_file_hash);
|
||||
|
||||
auto stat = stats_get_candidate_stat(round, local_id(), block_id);
|
||||
if (stat) {
|
||||
stat->block_status = ValidatorSessionStats::status_received;
|
||||
stat->collation_time = collation_time;
|
||||
stat->collated_at = td::Clocks::system();
|
||||
stat->block_timestamp = td::Clocks::system();
|
||||
stat->collation_cached = collation_cached;
|
||||
}
|
||||
if (round != cur_round_) {
|
||||
return;
|
||||
}
|
||||
td::Timer serialize_timer;
|
||||
auto b = create_tl_object<ton_api::validatorSession_candidate>(local_id().tl(), round, root_hash, std::move(data),
|
||||
std::move(collated_data));
|
||||
|
||||
auto B = serialize_candidate(b, compress_block_candidates_).move_as_ok();
|
||||
|
||||
auto block_id = description().candidate_id(local_idx(), root_hash, file_hash, collated_data_file_hash);
|
||||
if (stat) {
|
||||
stat->serialize_time = serialize_timer.elapsed();
|
||||
stat->serialized_size = B.size();
|
||||
}
|
||||
|
||||
td::actor::send_closure(catchain_, &catchain::CatChain::send_broadcast, std::move(B));
|
||||
|
||||
|
@ -496,11 +539,11 @@ void ValidatorSessionImpl::check_generate_slot() {
|
|||
td::PerfWarningTimer timer{"too long block generation", 1.0};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), print_id = print_id(), timer = std::move(timer),
|
||||
round = cur_round_](td::Result<BlockCandidate> R) {
|
||||
round = cur_round_](td::Result<GeneratedCandidate> R) {
|
||||
if (R.is_ok()) {
|
||||
auto c = R.move_as_ok();
|
||||
auto c = std::move(R.ok_ref().candidate);
|
||||
td::actor::send_closure(SelfId, &ValidatorSessionImpl::generated_block, round, c.id.root_hash,
|
||||
c.data.clone(), c.collated_data.clone());
|
||||
c.data.clone(), c.collated_data.clone(), timer.elapsed(), R.ok().is_cached);
|
||||
} else {
|
||||
LOG(WARNING) << print_id << ": failed to generate block candidate: " << R.move_as_error();
|
||||
}
|
||||
|
@ -550,6 +593,16 @@ void ValidatorSessionImpl::try_approve_block(const SentBlock *block) {
|
|||
it->second->round_ = std::max<td::uint32>(it->second->round_, cur_round_);
|
||||
td::PerfWarningTimer timer{"too long block validation", 1.0};
|
||||
auto &B = it->second;
|
||||
auto stat = stats_get_candidate_stat(B->round_, PublicKeyHash{B->src_});
|
||||
if (stat) {
|
||||
// Can happen if block is cached from previous round
|
||||
if (stat->block_status == ValidatorSessionStats::status_none) {
|
||||
stat->block_status = ValidatorSessionStats::status_received;
|
||||
}
|
||||
if (stat->block_timestamp <= 0.0) {
|
||||
stat->block_timestamp = td::Clocks::system();
|
||||
}
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([round = cur_round_, hash = block_id, root_hash = block->get_root_hash(),
|
||||
file_hash = block->get_file_hash(), timer = std::move(timer),
|
||||
|
@ -563,10 +616,10 @@ void ValidatorSessionImpl::try_approve_block(const SentBlock *block) {
|
|||
auto R = res.move_as_ok();
|
||||
if (R.is_ok()) {
|
||||
td::actor::send_closure(SelfId, &ValidatorSessionImpl::candidate_decision_ok, round, hash, root_hash,
|
||||
file_hash, src, R.ok_from());
|
||||
file_hash, src, R.ok_from(), timer.elapsed(), R.is_cached());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidatorSessionImpl::candidate_decision_fail, round, hash, R.reason(),
|
||||
src, R.proof());
|
||||
src, R.proof(), timer.elapsed(), R.is_cached());
|
||||
}
|
||||
});
|
||||
pending_approve_.insert(block_id);
|
||||
|
@ -754,8 +807,8 @@ void ValidatorSessionImpl::request_new_block(bool now) {
|
|||
} else {
|
||||
double lambda = 10.0 / description().get_total_nodes();
|
||||
double x = -1 / lambda * log(td::Random::fast(1, 999) * 0.001);
|
||||
if (x > 0.5) {
|
||||
x = 0.5;
|
||||
if (x > catchain_max_block_delay_) { // default = 0.5
|
||||
x = catchain_max_block_delay_;
|
||||
}
|
||||
td::actor::send_closure(catchain_, &catchain::CatChain::need_new_block, td::Timestamp::in(x));
|
||||
}
|
||||
|
@ -818,28 +871,40 @@ void ValidatorSessionImpl::on_new_round(td::uint32 round) {
|
|||
callback_->on_block_skipped(cur_round_);
|
||||
} else {
|
||||
cur_stats_.success = true;
|
||||
cur_stats_.timestamp = (td::uint64)td::Clocks::system();
|
||||
cur_stats_.timestamp = td::Clocks::system();
|
||||
cur_stats_.signatures = (td::uint32)export_sigs.size();
|
||||
cur_stats_.signatures_weight = signatures_weight;
|
||||
cur_stats_.approve_signatures = (td::uint32)export_approve_sigs.size();
|
||||
cur_stats_.approve_signatures_weight = approve_signatures_weight;
|
||||
cur_stats_.creator = description().get_source_id(block->get_src_idx());
|
||||
auto stat = stats_get_candidate_stat(cur_round_, cur_stats_.creator);
|
||||
if (stat) {
|
||||
stat->is_accepted = true;
|
||||
}
|
||||
auto stats = cur_stats_;
|
||||
while (!stats.rounds.empty() && stats.rounds.size() + stats.first_round - 1 > cur_round_) {
|
||||
stats.rounds.pop_back();
|
||||
}
|
||||
|
||||
if (it == blocks_.end()) {
|
||||
callback_->on_block_committed(cur_round_, description().get_source_public_key(block->get_src_idx()),
|
||||
block->get_root_hash(), block->get_file_hash(), td::BufferSlice(),
|
||||
std::move(export_sigs), std::move(export_approve_sigs), std::move(cur_stats_));
|
||||
std::move(export_sigs), std::move(export_approve_sigs), std::move(stats));
|
||||
} else {
|
||||
callback_->on_block_committed(cur_round_, description().get_source_public_key(block->get_src_idx()),
|
||||
block->get_root_hash(), block->get_file_hash(), it->second->data_.clone(),
|
||||
std::move(export_sigs), std::move(export_approve_sigs), std::move(cur_stats_));
|
||||
std::move(export_sigs), std::move(export_approve_sigs), std::move(stats));
|
||||
}
|
||||
}
|
||||
cur_round_++;
|
||||
if (have_block) {
|
||||
stats_init();
|
||||
} else {
|
||||
stats_add_round();
|
||||
size_t round_idx = cur_round_ - cur_stats_.first_round;
|
||||
while (round_idx >= cur_stats_.rounds.size()) {
|
||||
stats_add_round();
|
||||
}
|
||||
cur_stats_.rounds[round_idx].timestamp = td::Clocks::system();
|
||||
}
|
||||
auto it2 = blocks_.begin();
|
||||
while (it2 != blocks_.end()) {
|
||||
|
@ -929,9 +994,7 @@ void ValidatorSessionImpl::destroy() {
|
|||
}
|
||||
|
||||
void ValidatorSessionImpl::get_current_stats(td::Promise<ValidatorSessionStats> promise) {
|
||||
ValidatorSessionStats stats = cur_stats_;
|
||||
stats.timestamp = (td::uint64)td::Clocks::system();
|
||||
promise.set_result(std::move(stats));
|
||||
promise.set_result(cur_stats_);
|
||||
}
|
||||
|
||||
void ValidatorSessionImpl::get_validator_group_info_for_litequery(
|
||||
|
@ -997,52 +1060,149 @@ void ValidatorSessionImpl::start_up() {
|
|||
}
|
||||
|
||||
void ValidatorSessionImpl::stats_init() {
|
||||
auto old_rounds = std::move(cur_stats_.rounds);
|
||||
if (stats_inited_ && cur_stats_.first_round + old_rounds.size() > cur_round_) {
|
||||
old_rounds.erase(old_rounds.begin(), old_rounds.end() - (cur_stats_.first_round + old_rounds.size() - cur_round_));
|
||||
} else {
|
||||
old_rounds.clear();
|
||||
}
|
||||
cur_stats_ = ValidatorSessionStats();
|
||||
cur_stats_.rounds = std::move(old_rounds);
|
||||
cur_stats_.first_round = cur_round_;
|
||||
cur_stats_.session_id = unique_hash_;
|
||||
cur_stats_.total_validators = description().get_total_nodes();
|
||||
cur_stats_.total_weight = description().get_total_weight();
|
||||
cur_stats_.self = description().get_source_id(local_idx());
|
||||
stats_add_round();
|
||||
|
||||
for (auto it = stats_pending_approve_.begin(); it != stats_pending_approve_.end(); ) {
|
||||
if (it->first.first < cur_round_) {
|
||||
it = stats_pending_approve_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for (auto it = stats_pending_sign_.begin(); it != stats_pending_sign_.end(); ) {
|
||||
if (it->first.first < cur_round_) {
|
||||
it = stats_pending_sign_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur_stats_.rounds.empty()) {
|
||||
stats_add_round();
|
||||
}
|
||||
cur_stats_.rounds[0].timestamp = td::Clocks::system();
|
||||
stats_inited_ = true;
|
||||
}
|
||||
|
||||
void ValidatorSessionImpl::stats_add_round() {
|
||||
td::uint32 round = cur_stats_.first_round + cur_stats_.rounds.size();
|
||||
cur_stats_.rounds.emplace_back();
|
||||
auto& round = cur_stats_.rounds.back();
|
||||
round.timestamp = (td::uint64)td::Clocks::system();
|
||||
round.producers.resize(description().get_max_priority() + 1);
|
||||
auto& stat = cur_stats_.rounds.back();
|
||||
stat.producers.resize(description().get_max_priority() + 1);
|
||||
for (td::uint32 i = 0; i < description().get_total_nodes(); i++) {
|
||||
td::int32 priority = description().get_node_priority(i, cur_round_);
|
||||
td::int32 priority = description().get_node_priority(i, round);
|
||||
if (priority >= 0) {
|
||||
CHECK((size_t)priority < round.producers.size());
|
||||
round.producers[priority].id = description().get_source_id(i);
|
||||
CHECK((size_t)priority < stat.producers.size());
|
||||
stat.producers[priority].id = description().get_source_id(i);
|
||||
stat.producers[priority].is_ours = (local_idx() == i);
|
||||
stat.producers[priority].approvers.resize(description().get_total_nodes(), false);
|
||||
stat.producers[priority].signers.resize(description().get_total_nodes(), false);
|
||||
}
|
||||
}
|
||||
while (!round.producers.empty() && round.producers.back().id.is_zero()) {
|
||||
round.producers.pop_back();
|
||||
while (!stat.producers.empty() && stat.producers.back().id.is_zero()) {
|
||||
stat.producers.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void ValidatorSessionImpl::stats_set_candidate_status(td::uint32 round, PublicKeyHash src,
|
||||
ValidatorSessionCandidateId candidate_id, int status,
|
||||
std::string comment) {
|
||||
if (round < cur_stats_.first_round || round - cur_stats_.first_round >= cur_stats_.rounds.size()) {
|
||||
return;
|
||||
ValidatorSessionStats::Producer *ValidatorSessionImpl::stats_get_candidate_stat(
|
||||
td::uint32 round, PublicKeyHash src, ValidatorSessionCandidateId candidate_id) {
|
||||
if (round < cur_stats_.first_round || round > cur_round_ + 5) {
|
||||
return nullptr;
|
||||
}
|
||||
while (round - cur_stats_.first_round >= cur_stats_.rounds.size()) {
|
||||
stats_add_round();
|
||||
}
|
||||
auto &stats_round = cur_stats_.rounds[round - cur_stats_.first_round];
|
||||
auto it = std::find_if(stats_round.producers.begin(), stats_round.producers.end(),
|
||||
[&](const ValidatorSessionStats::Producer &p) { return p.id == src; });
|
||||
if (it == stats_round.producers.end()) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
it->candidate_id = candidate_id;
|
||||
if (it->block_status == ValidatorSessionStats::status_none) {
|
||||
it->block_timestamp = (td::uint64)td::Clocks::system();
|
||||
if (!candidate_id.is_zero()) {
|
||||
it->candidate_id = candidate_id;
|
||||
}
|
||||
it->block_status = status;
|
||||
if (!comment.empty()) {
|
||||
it->comment = std::move(comment);
|
||||
auto it2 = stats_pending_approve_.find({round, it->candidate_id});
|
||||
if (it2 != stats_pending_approve_.end()) {
|
||||
for (td::uint32 node_id : it2->second) {
|
||||
it->set_approved_by(node_id, description().get_node_weight(node_id), description().get_total_weight());
|
||||
}
|
||||
stats_pending_approve_.erase(it2);
|
||||
}
|
||||
it2 = stats_pending_sign_.find({round, it->candidate_id});
|
||||
if (it2 != stats_pending_sign_.end()) {
|
||||
for (td::uint32 node_id : it2->second) {
|
||||
it->set_signed_by(node_id, description().get_node_weight(node_id), description().get_total_weight());
|
||||
}
|
||||
stats_pending_sign_.erase(it2);
|
||||
}
|
||||
return &*it;
|
||||
}
|
||||
|
||||
ValidatorSessionStats::Producer *ValidatorSessionImpl::stats_get_candidate_stat_by_id(
|
||||
td::uint32 round, ValidatorSessionCandidateId candidate_id) {
|
||||
if (round < cur_stats_.first_round || round > cur_round_ + 5) {
|
||||
return nullptr;
|
||||
}
|
||||
while (round - cur_stats_.first_round >= cur_stats_.rounds.size()) {
|
||||
stats_add_round();
|
||||
}
|
||||
auto &stats_round = cur_stats_.rounds[round - cur_stats_.first_round];
|
||||
auto it = std::find_if(stats_round.producers.begin(), stats_round.producers.end(),
|
||||
[&](const ValidatorSessionStats::Producer &p) { return p.candidate_id == candidate_id; });
|
||||
if (it == stats_round.producers.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &*it;
|
||||
}
|
||||
|
||||
void ValidatorSessionImpl::stats_process_action(td::uint32 node_id, ton_api::validatorSession_round_Message &action) {
|
||||
ton_api::downcast_call(action, td::overloaded(
|
||||
[&](const ton_api::validatorSession_message_submittedBlock &obj) {
|
||||
auto candidate_id = description().candidate_id(
|
||||
node_id, obj.root_hash_, obj.file_hash_, obj.collated_data_file_hash_);
|
||||
auto stat = stats_get_candidate_stat(
|
||||
obj.round_, description().get_source_id(node_id), candidate_id);
|
||||
if (stat && stat->got_submit_at <= 0.0) {
|
||||
stat->got_submit_at = td::Clocks::system();
|
||||
}
|
||||
},
|
||||
[&](const ton_api::validatorSession_message_approvedBlock &obj) {
|
||||
if (obj.candidate_ == skip_round_candidate_id()) {
|
||||
return;
|
||||
}
|
||||
auto stat = stats_get_candidate_stat_by_id(obj.round_, obj.candidate_);
|
||||
if (stat) {
|
||||
stat->set_approved_by(node_id, description().get_node_weight(node_id),
|
||||
description().get_total_weight());
|
||||
} else {
|
||||
stats_pending_approve_[{obj.round_, obj.candidate_}].push_back(node_id);
|
||||
}
|
||||
},
|
||||
[&](const ton_api::validatorSession_message_commit &obj) {
|
||||
if (obj.candidate_ == skip_round_candidate_id()) {
|
||||
return;
|
||||
}
|
||||
auto stat = stats_get_candidate_stat_by_id(obj.round_, obj.candidate_);
|
||||
if (stat) {
|
||||
stat->set_signed_by(node_id, description().get_node_weight(node_id),
|
||||
description().get_total_weight());
|
||||
} else {
|
||||
stats_pending_sign_[{obj.round_, obj.candidate_}].push_back(node_id);
|
||||
}
|
||||
},
|
||||
[](const auto &) {}));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<ValidatorSession> ValidatorSession::create(
|
||||
|
|
|
@ -56,6 +56,12 @@ class ValidatorSession : public td::actor::Actor {
|
|||
td::BufferSlice proof() const {
|
||||
return proof_.clone();
|
||||
}
|
||||
bool is_cached() const {
|
||||
return is_cached_;
|
||||
}
|
||||
void set_is_cached(bool value = true) {
|
||||
is_cached_ = value;
|
||||
}
|
||||
CandidateDecision(td::uint32 ok_from) {
|
||||
ok_ = true;
|
||||
ok_from_ = ok_from;
|
||||
|
@ -69,6 +75,12 @@ class ValidatorSession : public td::actor::Actor {
|
|||
td::uint32 ok_from_ = 0;
|
||||
std::string reason_;
|
||||
td::BufferSlice proof_;
|
||||
bool is_cached_ = false;
|
||||
};
|
||||
|
||||
struct GeneratedCandidate {
|
||||
BlockCandidate candidate;
|
||||
bool is_cached = false;
|
||||
};
|
||||
|
||||
class Callback {
|
||||
|
@ -76,7 +88,7 @@ class ValidatorSession : public td::actor::Actor {
|
|||
virtual void on_candidate(td::uint32 round, PublicKey source, ValidatorSessionRootHash root_hash,
|
||||
td::BufferSlice data, td::BufferSlice collated_data,
|
||||
td::Promise<CandidateDecision> promise) = 0;
|
||||
virtual void on_generate_slot(td::uint32 round, td::Promise<BlockCandidate> promise) = 0;
|
||||
virtual void on_generate_slot(td::uint32 round, td::Promise<GeneratedCandidate> promise) = 0;
|
||||
virtual void on_block_committed(td::uint32 round, PublicKey source, ValidatorSessionRootHash root_hash,
|
||||
ValidatorSessionFileHash file_hash, td::BufferSlice data,
|
||||
std::vector<std::pair<PublicKeyHash, td::BufferSlice>> signatures,
|
||||
|
@ -96,6 +108,7 @@ class ValidatorSession : public td::actor::Actor {
|
|||
virtual void get_validator_group_info_for_litequery(
|
||||
td::uint32 cur_round,
|
||||
td::Promise<std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>>> promise) = 0;
|
||||
virtual void set_catchain_max_block_delay(double value) = 0;
|
||||
|
||||
static td::actor::ActorOwn<ValidatorSession> create(
|
||||
catchain::CatChainSessionId session_id, ValidatorSessionOptions opts, PublicKeyHash local_id,
|
||||
|
|
|
@ -90,6 +90,8 @@ class ValidatorSessionImpl : public ValidatorSession {
|
|||
td::actor::ActorOwn<catchain::CatChain> catchain_;
|
||||
std::unique_ptr<ValidatorSessionDescription> description_;
|
||||
|
||||
double catchain_max_block_delay_ = 0.5;
|
||||
|
||||
void on_new_round(td::uint32 round);
|
||||
void on_catchain_started();
|
||||
void check_vote_for_slot(td::uint32 att);
|
||||
|
@ -159,10 +161,19 @@ class ValidatorSessionImpl : public ValidatorSession {
|
|||
bool compress_block_candidates_ = false;
|
||||
|
||||
ValidatorSessionStats cur_stats_;
|
||||
bool stats_inited_ = false;
|
||||
std::map<std::pair<td::uint32, ValidatorSessionCandidateId>, std::vector<td::uint32>>
|
||||
stats_pending_approve_; // round, candidate_id -> approvers
|
||||
std::map<std::pair<td::uint32, ValidatorSessionCandidateId>, std::vector<td::uint32>>
|
||||
stats_pending_sign_; // round, candidate_id -> signers
|
||||
void stats_init();
|
||||
void stats_add_round();
|
||||
void stats_set_candidate_status(td::uint32 round, PublicKeyHash src, ValidatorSessionCandidateId candidate_id,
|
||||
int status, std::string comment = "");
|
||||
ValidatorSessionStats::Producer *stats_get_candidate_stat(
|
||||
td::uint32 round, PublicKeyHash src,
|
||||
ValidatorSessionCandidateId candidate_id = ValidatorSessionCandidateId::zero());
|
||||
ValidatorSessionStats::Producer *stats_get_candidate_stat_by_id(td::uint32 round,
|
||||
ValidatorSessionCandidateId candidate_id);
|
||||
void stats_process_action(td::uint32 node_id, ton_api::validatorSession_round_Message &action);
|
||||
|
||||
public:
|
||||
ValidatorSessionImpl(catchain::CatChainSessionId session_id, ValidatorSessionOptions opts, PublicKeyHash local_id,
|
||||
|
@ -179,6 +190,9 @@ class ValidatorSessionImpl : public ValidatorSession {
|
|||
void get_validator_group_info_for_litequery(
|
||||
td::uint32 cur_round,
|
||||
td::Promise<std::vector<tl_object_ptr<lite_api::liteServer_nonfinal_candidateInfo>>> promise) override;
|
||||
void set_catchain_max_block_delay(double value) override {
|
||||
catchain_max_block_delay_ = value;
|
||||
}
|
||||
|
||||
void process_blocks(std::vector<catchain::CatChainBlock *> blocks);
|
||||
void finished_processing();
|
||||
|
@ -190,17 +204,16 @@ class ValidatorSessionImpl : public ValidatorSession {
|
|||
void process_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
|
||||
void try_approve_block(const SentBlock *block);
|
||||
void try_sign();
|
||||
|
||||
void candidate_decision_fail(td::uint32 round, ValidatorSessionCandidateId hash, std::string result,
|
||||
td::uint32 src, td::BufferSlice proof);
|
||||
void candidate_decision_fail(td::uint32 round, ValidatorSessionCandidateId hash, std::string result, td::uint32 src,
|
||||
td::BufferSlice proof, double validation_time, bool validation_cached);
|
||||
void candidate_decision_ok(td::uint32 round, ValidatorSessionCandidateId hash, RootHash root_hash, FileHash file_hash,
|
||||
td::uint32 src, td::uint32 ok_from);
|
||||
td::uint32 src, td::uint32 ok_from, double validation_time, bool validation_cached);
|
||||
void candidate_approved_signed(td::uint32 round, ValidatorSessionCandidateId hash, td::uint32 ok_from,
|
||||
td::BufferSlice signature);
|
||||
|
||||
void generated_block(td::uint32 round, ValidatorSessionRootHash root_hash, td::BufferSlice data,
|
||||
td::BufferSlice collated);
|
||||
td::BufferSlice collated, double collation_time, bool collation_cached);
|
||||
void signed_block(td::uint32 round, ValidatorSessionCandidateId hash, td::BufferSlice signature);
|
||||
|
||||
void end_request(td::uint32 round, ValidatorSessionCandidateId block_id) {
|
||||
|
|
|
@ -25,6 +25,8 @@ set(VALIDATOR_DB_SOURCE
|
|||
db/statedb.cpp
|
||||
db/staticfilesdb.cpp
|
||||
db/staticfilesdb.hpp
|
||||
db/db-utils.cpp
|
||||
db/db-utils.h
|
||||
|
||||
db/package.hpp
|
||||
db/package.cpp
|
||||
|
|
|
@ -832,7 +832,10 @@ void ArchiveManager::start_up() {
|
|||
if (!opts_->get_disable_rocksdb_stats()) {
|
||||
statistics_.init();
|
||||
}
|
||||
index_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_root_ + "/files/globalindex", statistics_.rocksdb_statistics).move_as_ok());
|
||||
td::RocksDbOptions db_options;
|
||||
db_options.statistics = statistics_.rocksdb_statistics;
|
||||
index_ = std::make_shared<td::RocksDb>(
|
||||
td::RocksDb::open(db_root_ + "/files/globalindex", std::move(db_options)).move_as_ok());
|
||||
std::string value;
|
||||
auto v = index_->get(create_serialize_tl_object<ton_api::db_files_index_key>().as_slice(), value);
|
||||
v.ensure();
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "td/utils/port/path.h"
|
||||
#include "common/delay.h"
|
||||
#include "files-async.hpp"
|
||||
#include "db-utils.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -41,16 +42,14 @@ class PackageStatistics {
|
|||
|
||||
void record_read(double time, uint64_t bytes) {
|
||||
read_bytes.fetch_add(bytes, std::memory_order_relaxed);
|
||||
std::lock_guard<std::mutex> guard(read_mutex);
|
||||
std::lock_guard guard(read_mutex);
|
||||
read_time.insert(time);
|
||||
read_time_sum += time;
|
||||
}
|
||||
|
||||
void record_write(double time, uint64_t bytes) {
|
||||
write_bytes.fetch_add(bytes, std::memory_order_relaxed);
|
||||
std::lock_guard<std::mutex> guard(write_mutex);
|
||||
std::lock_guard guard(write_mutex);
|
||||
write_time.insert(time);
|
||||
write_time_sum += time;
|
||||
}
|
||||
|
||||
std::string to_string_and_reset() {
|
||||
|
@ -64,68 +63,35 @@ class PackageStatistics {
|
|||
ss << "ton.pack.read.bytes COUNT : " << read_bytes.exchange(0, std::memory_order_relaxed) << "\n";
|
||||
ss << "ton.pack.write.bytes COUNT : " << write_bytes.exchange(0, std::memory_order_relaxed) << "\n";
|
||||
|
||||
std::multiset<double> temp_read_time;
|
||||
double temp_read_time_sum;
|
||||
PercentileStats temp_read_time;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(read_mutex);
|
||||
std::lock_guard guard(read_mutex);
|
||||
temp_read_time = std::move(read_time);
|
||||
read_time.clear();
|
||||
temp_read_time_sum = read_time_sum;
|
||||
read_time_sum = 0;
|
||||
}
|
||||
auto read_stats = calculate_statistics(temp_read_time);
|
||||
ss << "ton.pack.read.micros P50 : " << read_stats[0] <<
|
||||
" P95 : " << read_stats[1] <<
|
||||
" P99 : " << read_stats[2] <<
|
||||
" P100 : " << read_stats[3] <<
|
||||
" COUNT : " << temp_read_time.size() <<
|
||||
" SUM : " << temp_read_time_sum << "\n";
|
||||
ss << "ton.pack.read.micros " << temp_read_time.to_string() << "\n";
|
||||
|
||||
std::multiset<double> temp_write_time;
|
||||
double temp_write_time_sum;
|
||||
PercentileStats temp_write_time;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(write_mutex);
|
||||
std::lock_guard guard(write_mutex);
|
||||
temp_write_time = std::move(write_time);
|
||||
write_time.clear();
|
||||
temp_write_time_sum = write_time_sum;
|
||||
write_time_sum = 0;
|
||||
}
|
||||
auto write_stats = calculate_statistics(temp_write_time);
|
||||
ss << "ton.pack.write.micros P50 : " << write_stats[0] <<
|
||||
" P95 : " << write_stats[1] <<
|
||||
" P99 : " << write_stats[2] <<
|
||||
" P100 : " << write_stats[3] <<
|
||||
" COUNT : " << temp_write_time.size() <<
|
||||
" SUM : " << temp_write_time_sum << "\n";
|
||||
ss << "ton.pack.write.micros " << temp_write_time.to_string() << "\n";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_uint64_t open_count;
|
||||
std::atomic_uint64_t close_count;
|
||||
std::multiset<double> read_time;
|
||||
std::atomic_uint64_t read_bytes;
|
||||
std::multiset<double> write_time;
|
||||
std::atomic_uint64_t write_bytes;
|
||||
double read_time_sum;
|
||||
double write_time_sum;
|
||||
std::atomic_uint64_t open_count{0};
|
||||
std::atomic_uint64_t close_count{0};
|
||||
PercentileStats read_time;
|
||||
std::atomic_uint64_t read_bytes{0};
|
||||
PercentileStats write_time;
|
||||
std::atomic_uint64_t write_bytes{0};
|
||||
|
||||
mutable std::mutex read_mutex;
|
||||
mutable std::mutex write_mutex;
|
||||
|
||||
std::vector<double> calculate_statistics(const std::multiset<double>& data) const {
|
||||
if (data.empty()) return {0, 0, 0, 0};
|
||||
|
||||
auto size = data.size();
|
||||
auto calc_percentile = [&](double p) -> double {
|
||||
auto it = data.begin();
|
||||
std::advance(it, static_cast<int>(std::ceil(p * double(size)) - 1));
|
||||
return *it;
|
||||
};
|
||||
|
||||
return {calc_percentile(0.5), calc_percentile(0.95), calc_percentile(0.99), *data.rbegin()};
|
||||
}
|
||||
};
|
||||
|
||||
void DbStatistics::init() {
|
||||
|
@ -588,7 +554,9 @@ void ArchiveSlice::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::
|
|||
void ArchiveSlice::before_query() {
|
||||
if (status_ == st_closed) {
|
||||
LOG(DEBUG) << "Opening archive slice " << db_path_;
|
||||
kv_ = std::make_unique<td::RocksDb>(td::RocksDb::open(db_path_, statistics_.rocksdb_statistics).move_as_ok());
|
||||
td::RocksDbOptions db_options;
|
||||
db_options.statistics = statistics_.rocksdb_statistics;
|
||||
kv_ = std::make_unique<td::RocksDb>(td::RocksDb::open(db_path_, std::move(db_options)).move_as_ok());
|
||||
std::string value;
|
||||
auto R2 = kv_->get("status", value);
|
||||
R2.ensure();
|
||||
|
|
|
@ -88,8 +88,15 @@ void CellDbIn::start_up() {
|
|||
statistics_ = td::RocksDb::create_statistics();
|
||||
statistics_flush_at_ = td::Timestamp::in(60.0);
|
||||
}
|
||||
cell_db_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_, statistics_).move_as_ok());
|
||||
|
||||
td::RocksDbOptions db_options;
|
||||
db_options.statistics = statistics_;
|
||||
if (opts_->get_celldb_cache_size()) {
|
||||
db_options.block_cache = td::RocksDb::create_cache(opts_->get_celldb_cache_size().value());
|
||||
LOG(WARNING) << "Set CellDb block cache size to " << td::format::as_size(opts_->get_celldb_cache_size().value());
|
||||
}
|
||||
db_options.use_direct_reads = opts_->get_celldb_direct_io();
|
||||
cell_db_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_, std::move(db_options)).move_as_ok());
|
||||
|
||||
|
||||
boc_ = vm::DynamicBagOfCellsDb::create();
|
||||
boc_->set_celldb_compress_depth(opts_->get_celldb_compress_depth());
|
||||
|
@ -105,6 +112,27 @@ void CellDbIn::start_up() {
|
|||
set_block(empty, std::move(e));
|
||||
cell_db_->commit_write_batch().ensure();
|
||||
}
|
||||
|
||||
if (opts_->get_celldb_preload_all()) {
|
||||
// Iterate whole DB in a separate thread
|
||||
delay_action([snapshot = cell_db_->snapshot()]() {
|
||||
LOG(WARNING) << "CellDb: pre-loading all keys";
|
||||
td::uint64 total = 0;
|
||||
td::Timer timer;
|
||||
auto S = snapshot->for_each([&](td::Slice, td::Slice) {
|
||||
++total;
|
||||
if (total % 1000000 == 0) {
|
||||
LOG(INFO) << "CellDb: iterated " << total << " keys";
|
||||
}
|
||||
return td::Status::OK();
|
||||
});
|
||||
if (S.is_error()) {
|
||||
LOG(ERROR) << "CellDb: pre-load failed: " << S.move_as_error();
|
||||
} else {
|
||||
LOG(WARNING) << "CellDb: iterated " << total << " keys in " << timer.elapsed() << "s";
|
||||
}
|
||||
}, td::Timestamp::now());
|
||||
}
|
||||
}
|
||||
|
||||
void CellDbIn::load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise) {
|
||||
|
@ -155,6 +183,9 @@ void CellDbIn::store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promi
|
|||
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
|
||||
|
||||
promise.set_result(boc_->load_cell(cell->get_hash().as_slice()));
|
||||
if (!opts_->get_disable_rocksdb_stats()) {
|
||||
cell_db_statistics_.store_cell_time_.insert(timer.elapsed() * 1e6);
|
||||
}
|
||||
}
|
||||
|
||||
void CellDbIn::get_cell_db_reader(td::Promise<std::shared_ptr<vm::CellDbReader>> promise) {
|
||||
|
@ -162,8 +193,9 @@ void CellDbIn::get_cell_db_reader(td::Promise<std::shared_ptr<vm::CellDbReader>>
|
|||
}
|
||||
|
||||
void CellDbIn::flush_db_stats() {
|
||||
auto stats = td::RocksDb::statistics_to_string(statistics_);
|
||||
auto to_file_r = td::FileFd::open(path_ + "/db_stats.txt", td::FileFd::Truncate | td::FileFd::Create | td::FileFd::Write, 0644);
|
||||
auto stats = td::RocksDb::statistics_to_string(statistics_) + cell_db_statistics_.to_string();
|
||||
auto to_file_r =
|
||||
td::FileFd::open(path_ + "/db_stats.txt", td::FileFd::Truncate | td::FileFd::Create | td::FileFd::Write, 0644);
|
||||
if (to_file_r.is_error()) {
|
||||
LOG(ERROR) << "Failed to open db_stats.txt: " << to_file_r.move_as_error();
|
||||
return;
|
||||
|
@ -176,6 +208,7 @@ void CellDbIn::flush_db_stats() {
|
|||
return;
|
||||
}
|
||||
td::RocksDb::reset_statistics(statistics_);
|
||||
cell_db_statistics_.clear();
|
||||
}
|
||||
|
||||
void CellDbIn::alarm() {
|
||||
|
@ -278,6 +311,9 @@ void CellDbIn::gc_cont2(BlockHandle handle) {
|
|||
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
|
||||
|
||||
DCHECK(get_block(key_hash).is_error());
|
||||
if (!opts_->get_disable_rocksdb_stats()) {
|
||||
cell_db_statistics_.gc_cell_time_.insert(timer.elapsed() * 1e6);
|
||||
}
|
||||
}
|
||||
|
||||
void CellDbIn::skip_gc() {
|
||||
|
@ -441,6 +477,14 @@ td::BufferSlice CellDbIn::DbEntry::release() {
|
|||
return create_serialize_tl_object<ton_api::db_celldb_value>(create_tl_block_id(block_id), prev, next, root_hash);
|
||||
}
|
||||
|
||||
std::string CellDbIn::CellDbStatistics::to_string() {
|
||||
td::StringBuilder ss;
|
||||
ss << "ton.celldb.store_cell.micros " << store_cell_time_.to_string() << "\n";
|
||||
ss << "ton.celldb.gc_cell.micros " << gc_cell_time_.to_string() << "\n";
|
||||
ss << "ton.celldb.total_time.micros : " << (td::Timestamp::now().at() - stats_start_time_.at()) * 1e6 << "\n";
|
||||
return ss.as_cslice().str();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "interfaces/block-handle.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "validator.h"
|
||||
#include "db-utils.h"
|
||||
|
||||
namespace rocksdb {
|
||||
class Statistics;
|
||||
|
@ -42,9 +43,11 @@ class CellDbAsyncExecutor;
|
|||
|
||||
class CellDbBase : public td::actor::Actor {
|
||||
public:
|
||||
virtual void start_up();
|
||||
void start_up() override;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<vm::DynamicBagOfCellsDb::AsyncExecutor> async_executor;
|
||||
|
||||
private:
|
||||
void execute_sync(std::function<void()> f);
|
||||
friend CellDbAsyncExecutor;
|
||||
|
@ -76,8 +79,7 @@ class CellDbIn : public CellDbBase {
|
|||
RootHash root_hash;
|
||||
|
||||
DbEntry(tl_object_ptr<ton_api::db_celldb_value> entry);
|
||||
DbEntry() {
|
||||
}
|
||||
DbEntry() = default;
|
||||
DbEntry(BlockIdExt block_id, KeyHash prev, KeyHash next, RootHash root_hash)
|
||||
: block_id(block_id), prev(prev), next(next), root_hash(root_hash) {
|
||||
}
|
||||
|
@ -109,8 +111,6 @@ class CellDbIn : public CellDbBase {
|
|||
|
||||
std::unique_ptr<vm::DynamicBagOfCellsDb> boc_;
|
||||
std::shared_ptr<vm::KeyValue> cell_db_;
|
||||
std::shared_ptr<rocksdb::Statistics> statistics_;
|
||||
td::Timestamp statistics_flush_at_ = td::Timestamp::never();
|
||||
|
||||
std::function<void(const vm::CellLoader::LoadResult&)> on_load_callback_;
|
||||
std::set<td::Bits256> cells_to_migrate_;
|
||||
|
@ -127,6 +127,21 @@ class CellDbIn : public CellDbBase {
|
|||
};
|
||||
std::unique_ptr<MigrationStats> migration_stats_;
|
||||
|
||||
struct CellDbStatistics {
|
||||
PercentileStats store_cell_time_;
|
||||
PercentileStats gc_cell_time_;
|
||||
td::Timestamp stats_start_time_ = td::Timestamp::now();
|
||||
|
||||
std::string to_string();
|
||||
void clear() {
|
||||
*this = CellDbStatistics{};
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<rocksdb::Statistics> statistics_;
|
||||
CellDbStatistics cell_db_statistics_;
|
||||
td::Timestamp statistics_flush_at_ = td::Timestamp::never();
|
||||
|
||||
public:
|
||||
class MigrationProxy : public td::actor::Actor {
|
||||
public:
|
||||
|
|
54
validator/db/db-utils.cpp
Normal file
54
validator/db/db-utils.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain 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.
|
||||
|
||||
TON Blockchain 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.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "db-utils.h"
|
||||
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace ton::validator {
|
||||
|
||||
void PercentileStats::insert(double value) {
|
||||
values_.insert(value);
|
||||
}
|
||||
|
||||
std::string PercentileStats::to_string() const {
|
||||
double percentiles[4] = {0.0, 0.0, 0.0, 0.0};
|
||||
double sum = 0.0;
|
||||
size_t size = values_.size();
|
||||
if (!values_.empty()) {
|
||||
size_t indices[4] = {(size_t)std::ceil(0.5 * (double)size) - 1, (size_t)std::ceil(0.95 * (double)size) - 1,
|
||||
(size_t)std::ceil(0.99 * (double)size) - 1, size - 1};
|
||||
size_t i = 0;
|
||||
for (auto it = values_.begin(); it != values_.end(); ++it, ++i) {
|
||||
for (size_t j = 0; j < 4; ++j) {
|
||||
if (indices[j] == i) {
|
||||
percentiles[j] = *it;
|
||||
}
|
||||
}
|
||||
sum += *it;
|
||||
}
|
||||
}
|
||||
return PSTRING() << "P50 : " << percentiles[0] << " P95 : " << percentiles[1] << " P99 : " << percentiles[2]
|
||||
<< " P100 : " << percentiles[3] << " COUNT : " << size << " SUM : " << sum;
|
||||
}
|
||||
|
||||
void PercentileStats::clear() {
|
||||
values_.clear();
|
||||
}
|
||||
|
||||
} // namespace ton::validator
|
33
validator/db/db-utils.h
Normal file
33
validator/db/db-utils.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain 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.
|
||||
|
||||
TON Blockchain 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.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace ton::validator {
|
||||
|
||||
class PercentileStats {
|
||||
public:
|
||||
void insert(double value);
|
||||
std::string to_string() const;
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::multiset<double> values_;
|
||||
};
|
||||
|
||||
} // namespace ton::validator
|
|
@ -57,7 +57,7 @@ class WriteFile : public td::actor::Actor {
|
|||
status = file.sync();
|
||||
}
|
||||
if (status.is_error()) {
|
||||
td::unlink(old_name);
|
||||
td::unlink(old_name).ignore();
|
||||
promise_.set_error(std::move(status));
|
||||
stop();
|
||||
return;
|
||||
|
|
|
@ -17,10 +17,14 @@
|
|||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "wait-block-data.hpp"
|
||||
|
||||
#include "block-parse.h"
|
||||
#include "block-auto.h"
|
||||
#include "fabric.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "common/delay.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -108,7 +112,7 @@ void WaitBlockData::start() {
|
|||
td::actor::send_closure(SelfId, &WaitBlockData::failed_to_get_block_data_from_net,
|
||||
R.move_as_error_prefix("net error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::got_block_data_from_net, R.move_as_ok());
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::got_data_from_net, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -133,13 +137,49 @@ void WaitBlockData::failed_to_get_block_data_from_net(td::Status reason) {
|
|||
td::Timestamp::in(0.1));
|
||||
}
|
||||
|
||||
void WaitBlockData::got_block_data_from_net(ReceivedBlock block) {
|
||||
void WaitBlockData::got_data_from_net(ReceivedBlock block) {
|
||||
auto X = create_block(std::move(block));
|
||||
if (X.is_error()) {
|
||||
failed_to_get_block_data_from_net(X.move_as_error_prefix("bad block from net: "));
|
||||
return;
|
||||
}
|
||||
data_ = X.move_as_ok();
|
||||
got_block_data_from_net(X.move_as_ok());
|
||||
}
|
||||
|
||||
void WaitBlockData::got_block_data_from_net(td::Ref<BlockData> block) {
|
||||
if (data_.not_null()) {
|
||||
return;
|
||||
}
|
||||
data_ = std::move(block);
|
||||
if (handle_->received()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
if (!handle_->id().is_masterchain() && !handle_->inited_proof_link()) {
|
||||
// This can happen if we get block from candidates cache.
|
||||
// Proof link can be derived from the block (but not for masterchain block).
|
||||
auto r_proof_link = generate_proof_link(handle_->id(), data_->root_cell());
|
||||
if (r_proof_link.is_error()) {
|
||||
abort_query(r_proof_link.move_as_error_prefix("failed to create proof link for block: "));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::validate_block_proof_link, handle_->id(),
|
||||
r_proof_link.move_as_ok(),
|
||||
[id = handle_->id().id, SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::abort_query,
|
||||
R.move_as_error_prefix("validate proof link error: "));
|
||||
return;
|
||||
}
|
||||
LOG(DEBUG) << "Created and validated proof link for " << id.to_str();
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::checked_proof_link);
|
||||
});
|
||||
return;
|
||||
}
|
||||
checked_proof_link();
|
||||
}
|
||||
|
||||
void WaitBlockData::checked_proof_link() {
|
||||
CHECK(handle_->id().is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link());
|
||||
if (!handle_->received()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
|
@ -198,6 +238,41 @@ void WaitBlockData::got_static_file(td::BufferSlice data) {
|
|||
run_hardfork_accept_block_query(handle_->id(), data_, manager_, std::move(P));
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> WaitBlockData::generate_proof_link(BlockIdExt id, td::Ref<vm::Cell> block_root) {
|
||||
// Creating proof link. Similar to accept-block.cpp
|
||||
if (id.is_masterchain()) {
|
||||
return td::Status::Error("cannot create proof link for masterchain block");
|
||||
}
|
||||
auto usage_tree = std::make_shared<vm::CellUsageTree>();
|
||||
auto usage_cell = vm::UsageCell::create(block_root, usage_tree->root_ptr());
|
||||
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::ExtBlkRef::Record mcref{}; // _ ExtBlkRef = BlkMasterInfo;
|
||||
ShardIdFull shard;
|
||||
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) &&
|
||||
block::gen::BlkPrevInfo{info.after_merge}.validate_ref(info.prev_ref) &&
|
||||
tlb::unpack_cell(std::move(blk.extra), extra) && block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
(!info.not_master || tlb::unpack_cell(info.master_ref, mcref)))) {
|
||||
return td::Status::Error("cannot unpack block header");
|
||||
}
|
||||
vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update};
|
||||
|
||||
auto proof = vm::MerkleProof::generate(block_root, usage_tree.get());
|
||||
vm::CellBuilder cb;
|
||||
td::Ref<vm::Cell> bs_cell;
|
||||
if (!(cb.store_long_bool(0xc3, 8) // block_proof#c3
|
||||
&& block::tlb::t_BlockIdExt.pack(cb, id) // proof_for:BlockIdExt
|
||||
&& cb.store_ref_bool(std::move(proof)) // proof:^Cell
|
||||
&& cb.store_bool_bool(false) // signatures:(Maybe ^BlockSignatures)
|
||||
&& cb.finalize_to(bs_cell))) {
|
||||
return td::Status::Error("cannot serialize BlockProof");
|
||||
}
|
||||
return std_boc_serialize(bs_cell, 0);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -57,11 +57,15 @@ class WaitBlockData : public td::actor::Actor {
|
|||
void set_is_hardfork(bool value);
|
||||
void start();
|
||||
void got_block_data_from_db(td::Ref<BlockData> data);
|
||||
void got_block_data_from_net(ReceivedBlock data);
|
||||
void got_data_from_net(ReceivedBlock data);
|
||||
void got_block_data_from_net(td::Ref<BlockData> block);
|
||||
void checked_proof_link();
|
||||
void failed_to_get_block_data_from_net(td::Status reason);
|
||||
|
||||
void got_static_file(td::BufferSlice data);
|
||||
|
||||
static td::Result<td::BufferSlice> generate_proof_link(BlockIdExt id, td::Ref<vm::Cell> block_root);
|
||||
|
||||
private:
|
||||
BlockHandle handle_;
|
||||
|
||||
|
|
|
@ -192,7 +192,8 @@ void WaitBlockState::got_proof_link(td::BufferSlice data) {
|
|||
td::actor::send_closure(SelfId, &WaitBlockState::after_get_proof_link);
|
||||
} else {
|
||||
LOG(INFO) << "received bad proof link: " << R.move_as_error();
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::after_get_proof_link);
|
||||
delay_action([SelfId]() { td::actor::send_closure(SelfId, &WaitBlockState::after_get_proof_link); },
|
||||
td::Timestamp::in(0.1));
|
||||
}
|
||||
});
|
||||
run_check_proof_link_query(handle_->id(), R.move_as_ok(), manager_, timeout_, std::move(P));
|
||||
|
|
|
@ -49,8 +49,8 @@ td::Result<std::vector<td::Ref<ShardTopBlockDescription>>> create_new_shard_bloc
|
|||
|
||||
td::Ref<BlockSignatureSet> create_signature_set(std::vector<BlockSignature> sig_set);
|
||||
|
||||
void run_check_external_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Ref<ExtMessage>> promise);
|
||||
void run_check_external_message(td::Ref<ExtMessage> message, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Ref<ExtMessage>> promise);
|
||||
|
||||
void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "full-node-private-overlay.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "common/delay.h"
|
||||
#include "common/checksum.h"
|
||||
#include "full-node-serializer.hpp"
|
||||
|
||||
namespace ton::validator::fullnode {
|
||||
|
@ -38,17 +39,7 @@ void FullNodePrivateBlockOverlay::process_block_broadcast(PublicKeyHash src, ton
|
|||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received block broadcast in private overlay from " << src << ": "
|
||||
<< B.ok().block_id.to_str();
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
if (R.error().code() == ErrorCode::notready) {
|
||||
LOG(DEBUG) << "dropped broadcast: " << R.move_as_error();
|
||||
} else {
|
||||
LOG(INFO) << "dropped broadcast: " << R.move_as_error();
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, B.move_as_ok(),
|
||||
std::move(P));
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query) {
|
||||
|
@ -59,7 +50,45 @@ void FullNodePrivateBlockOverlay::process_broadcast(PublicKeyHash src, ton_api::
|
|||
query.block_->cc_seqno_, std::move(query.block_->data_));
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::process_broadcast(PublicKeyHash src,
|
||||
ton_api::tonNode_newBlockCandidateBroadcast &query) {
|
||||
process_block_candidate_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::process_broadcast(PublicKeyHash src,
|
||||
ton_api::tonNode_newBlockCandidateBroadcastCompressed &query) {
|
||||
process_block_candidate_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::process_block_candidate_broadcast(PublicKeyHash src,
|
||||
ton_api::tonNode_Broadcast &query) {
|
||||
BlockIdExt block_id;
|
||||
CatchainSeqno cc_seqno;
|
||||
td::uint32 validator_set_hash;
|
||||
td::BufferSlice data;
|
||||
auto S = deserialize_block_candidate_broadcast(query, block_id, cc_seqno, validator_set_hash, data,
|
||||
overlay::Overlays::max_fec_broadcast_size());
|
||||
if (S.is_error()) {
|
||||
LOG(DEBUG) << "dropped broadcast: " << S;
|
||||
return;
|
||||
}
|
||||
if (data.size() > FullNode::max_block_size()) {
|
||||
VLOG(FULL_NODE_WARNING) << "received block candidate with too big size from " << src;
|
||||
return;
|
||||
}
|
||||
if (td::sha256_bits256(data.as_slice()) != block_id.file_hash) {
|
||||
VLOG(FULL_NODE_WARNING) << "received block candidate with incorrect file hash from " << src;
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received newBlockCandidate in private overlay from " << src << ": " << block_id.to_str();
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_candidate_broadcast, block_id, cc_seqno,
|
||||
validator_set_hash, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
|
||||
if (adnl::AdnlNodeIdShort{src} == local_id_) {
|
||||
return;
|
||||
}
|
||||
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
|
||||
if (B.is_error()) {
|
||||
return;
|
||||
|
@ -84,6 +113,22 @@ void FullNodePrivateBlockOverlay::send_shard_block_info(BlockIdExt block_id, Cat
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::BufferSlice data) {
|
||||
if (!inited_) {
|
||||
return;
|
||||
}
|
||||
auto B =
|
||||
serialize_block_candidate_broadcast(block_id, cc_seqno, validator_set_hash, data, true); // compression enabled
|
||||
if (B.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to serialize block candidate broadcast: " << B.move_as_error();
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Sending newBlockCandidate in private overlay: " << block_id.to_str();
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
|
||||
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodePrivateBlockOverlay::send_broadcast(BlockBroadcast broadcast) {
|
||||
if (!inited_) {
|
||||
return;
|
||||
|
@ -169,18 +214,86 @@ void FullNodePrivateBlockOverlay::tear_down() {
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query) {
|
||||
auto it = senders_.find(adnl::AdnlNodeIdShort{src});
|
||||
if (it == senders_.end()) {
|
||||
void FullNodeCustomOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
|
||||
process_block_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query) {
|
||||
process_block_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
|
||||
if (!block_senders_.count(adnl::AdnlNodeIdShort(src))) {
|
||||
VLOG(FULL_NODE_DEBUG) << "Dropping block broadcast in private overlay \"" << name_ << "\" from unauthorized sender "
|
||||
<< src;
|
||||
return;
|
||||
}
|
||||
LOG(FULL_NODE_DEBUG) << "Got external message in private overlay \"" << name_ << "\" from " << src
|
||||
<< " (priority=" << it->second << ")";
|
||||
auto B = deserialize_block_broadcast(query, overlay::Overlays::max_fec_broadcast_size());
|
||||
if (B.is_error()) {
|
||||
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received block broadcast in custom overlay \"" << name_ << "\" from " << src << ": "
|
||||
<< B.ok().block_id.to_str();
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query) {
|
||||
auto it = msg_senders_.find(adnl::AdnlNodeIdShort{src});
|
||||
if (it == msg_senders_.end()) {
|
||||
VLOG(FULL_NODE_DEBUG) << "Dropping external message broadcast in custom overlay \"" << name_
|
||||
<< "\" from unauthorized sender " << src;
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Got external message in custom overlay \"" << name_ << "\" from " << src
|
||||
<< " (priority=" << it->second << ")";
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_external_message,
|
||||
std::move(query.message_->data_), it->second);
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query) {
|
||||
process_block_candidate_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_broadcast(PublicKeyHash src,
|
||||
ton_api::tonNode_newBlockCandidateBroadcastCompressed &query) {
|
||||
process_block_candidate_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
|
||||
if (!block_senders_.count(adnl::AdnlNodeIdShort(src))) {
|
||||
VLOG(FULL_NODE_DEBUG) << "Dropping block candidate broadcast in private overlay \"" << name_
|
||||
<< "\" from unauthorized sender " << src;
|
||||
return;
|
||||
}
|
||||
BlockIdExt block_id;
|
||||
CatchainSeqno cc_seqno;
|
||||
td::uint32 validator_set_hash;
|
||||
td::BufferSlice data;
|
||||
auto S = deserialize_block_candidate_broadcast(query, block_id, cc_seqno, validator_set_hash, data,
|
||||
overlay::Overlays::max_fec_broadcast_size());
|
||||
if (S.is_error()) {
|
||||
LOG(DEBUG) << "dropped broadcast: " << S;
|
||||
return;
|
||||
}
|
||||
if (data.size() > FullNode::max_block_size()) {
|
||||
VLOG(FULL_NODE_WARNING) << "received block candidate with too big size from " << src;
|
||||
return;
|
||||
}
|
||||
if (td::sha256_bits256(data.as_slice()) != block_id.file_hash) {
|
||||
VLOG(FULL_NODE_WARNING) << "received block candidate with incorrect file hash from " << src;
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received newBlockCandidate in custom overlay \"" << name_ << "\" from " << src << ": "
|
||||
<< block_id.to_str();
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_candidate_broadcast, block_id, cc_seqno,
|
||||
validator_set_hash, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
|
||||
if (adnl::AdnlNodeIdShort{src} == local_id_) {
|
||||
return;
|
||||
}
|
||||
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
|
||||
if (B.is_error()) {
|
||||
return;
|
||||
|
@ -192,7 +305,7 @@ void FullNodeCustomOverlay::send_external_message(td::BufferSlice data) {
|
|||
if (!inited_ || config_.ext_messages_broadcast_disabled_) {
|
||||
return;
|
||||
}
|
||||
LOG(FULL_NODE_DEBUG) << "Sending external message to private overlay \"" << name_ << "\"";
|
||||
VLOG(FULL_NODE_DEBUG) << "Sending external message to custom overlay \"" << name_ << "\"";
|
||||
auto B = create_serialize_tl_object<ton_api::tonNode_externalMessageBroadcast>(
|
||||
create_tl_object<ton_api::tonNode_externalMessage>(std::move(data)));
|
||||
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
|
||||
|
@ -204,6 +317,37 @@ void FullNodeCustomOverlay::send_external_message(td::BufferSlice data) {
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::send_broadcast(BlockBroadcast broadcast) {
|
||||
if (!inited_) {
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Sending block broadcast to custom overlay \"" << name_
|
||||
<< "\": " << broadcast.block_id.to_str();
|
||||
auto B = serialize_block_broadcast(broadcast, true); // compression_enabled = true
|
||||
if (B.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to serialize block broadcast: " << B.move_as_error();
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
|
||||
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::BufferSlice data) {
|
||||
if (!inited_) {
|
||||
return;
|
||||
}
|
||||
auto B =
|
||||
serialize_block_candidate_broadcast(block_id, cc_seqno, validator_set_hash, data, true); // compression enabled
|
||||
if (B.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to serialize block candidate broadcast: " << B.move_as_error();
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Sending newBlockCandidate in custom overlay \"" << name_ << "\": " << block_id.to_str();
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
|
||||
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodeCustomOverlay::start_up() {
|
||||
std::sort(nodes_.begin(), nodes_.end());
|
||||
nodes_.erase(std::unique(nodes_.begin(), nodes_.end()), nodes_.end());
|
||||
|
@ -234,7 +378,8 @@ void FullNodeCustomOverlay::try_init() {
|
|||
|
||||
void FullNodeCustomOverlay::init() {
|
||||
LOG(FULL_NODE_WARNING) << "Creating custom overlay \"" << name_ << "\" for adnl id " << local_id_ << " : "
|
||||
<< nodes_.size() << " nodes, overlay_id=" << overlay_id_;
|
||||
<< nodes_.size() << " nodes, " << msg_senders_.size() << " msg senders, "
|
||||
<< block_senders_.size() << " block senders, overlay_id=" << overlay_id_;
|
||||
class Callback : public overlay::Overlays::Callback {
|
||||
public:
|
||||
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
|
||||
|
@ -256,9 +401,12 @@ void FullNodeCustomOverlay::init() {
|
|||
};
|
||||
|
||||
std::map<PublicKeyHash, td::uint32> authorized_keys;
|
||||
for (const auto &sender : senders_) {
|
||||
for (const auto &sender : msg_senders_) {
|
||||
authorized_keys[sender.first.pubkey_hash()] = overlay::Overlays::max_fec_broadcast_size();
|
||||
}
|
||||
for (const auto &sender : block_senders_) {
|
||||
authorized_keys[sender.pubkey_hash()] = overlay::Overlays::max_fec_broadcast_size();
|
||||
}
|
||||
overlay::OverlayPrivacyRules rules{overlay::Overlays::max_fec_broadcast_size(), 0, std::move(authorized_keys)};
|
||||
td::actor::send_closure(
|
||||
overlays_, &overlay::Overlays::create_private_overlay, local_id_, overlay_id_full_.clone(), nodes_,
|
||||
|
|
|
@ -27,6 +27,11 @@ class FullNodePrivateBlockOverlay : public td::actor::Actor {
|
|||
void process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcastCompressed &query);
|
||||
void process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
|
||||
|
||||
template <class T>
|
||||
void process_broadcast(PublicKeyHash, T &) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping unknown broadcast";
|
||||
|
@ -34,36 +39,35 @@ class FullNodePrivateBlockOverlay : public td::actor::Actor {
|
|||
void receive_broadcast(PublicKeyHash src, td::BufferSlice query);
|
||||
|
||||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data);
|
||||
void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data);
|
||||
void send_broadcast(BlockBroadcast broadcast);
|
||||
|
||||
void set_config(FullNodeConfig config) {
|
||||
config_ = std::move(config);
|
||||
}
|
||||
|
||||
void set_enable_compression(bool value) {
|
||||
enable_compression_ = value;
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
void tear_down() override;
|
||||
|
||||
FullNodePrivateBlockOverlay(adnl::AdnlNodeIdShort local_id, std::vector<adnl::AdnlNodeIdShort> nodes,
|
||||
FileHash zero_state_file_hash, FullNodeConfig config, bool enable_compression,
|
||||
FileHash zero_state_file_hash, FullNodeConfig config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager)
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<FullNode> full_node)
|
||||
: local_id_(local_id)
|
||||
, nodes_(std::move(nodes))
|
||||
, zero_state_file_hash_(zero_state_file_hash)
|
||||
, config_(config)
|
||||
, enable_compression_(enable_compression)
|
||||
, keyring_(keyring)
|
||||
, adnl_(adnl)
|
||||
, rldp_(rldp)
|
||||
, rldp2_(rldp2)
|
||||
, overlays_(overlays)
|
||||
, validator_manager_(validator_manager) {
|
||||
, validator_manager_(validator_manager)
|
||||
, full_node_(full_node) {
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -71,7 +75,7 @@ class FullNodePrivateBlockOverlay : public td::actor::Actor {
|
|||
std::vector<adnl::AdnlNodeIdShort> nodes_;
|
||||
FileHash zero_state_file_hash_;
|
||||
FullNodeConfig config_;
|
||||
bool enable_compression_;
|
||||
bool enable_compression_ = true;
|
||||
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
td::actor::ActorId<adnl::Adnl> adnl_;
|
||||
|
@ -79,6 +83,7 @@ class FullNodePrivateBlockOverlay : public td::actor::Actor {
|
|||
td::actor::ActorId<rldp2::Rldp> rldp2_;
|
||||
td::actor::ActorId<overlay::Overlays> overlays_;
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager_;
|
||||
td::actor::ActorId<FullNode> full_node_;
|
||||
|
||||
bool inited_ = false;
|
||||
overlay::OverlayIdFull overlay_id_full_;
|
||||
|
@ -90,7 +95,16 @@ class FullNodePrivateBlockOverlay : public td::actor::Actor {
|
|||
|
||||
class FullNodeCustomOverlay : public td::actor::Actor {
|
||||
public:
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query);
|
||||
void process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcastCompressed &query);
|
||||
void process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
|
||||
|
||||
template <class T>
|
||||
void process_broadcast(PublicKeyHash, T &) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping unknown broadcast";
|
||||
|
@ -98,6 +112,9 @@ class FullNodeCustomOverlay : public td::actor::Actor {
|
|||
void receive_broadcast(PublicKeyHash src, td::BufferSlice query);
|
||||
|
||||
void send_external_message(td::BufferSlice data);
|
||||
void send_broadcast(BlockBroadcast broadcast);
|
||||
void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data);
|
||||
|
||||
void set_config(FullNodeConfig config) {
|
||||
config_ = std::move(config);
|
||||
|
@ -106,16 +123,17 @@ class FullNodeCustomOverlay : public td::actor::Actor {
|
|||
void start_up() override;
|
||||
void tear_down() override;
|
||||
|
||||
FullNodeCustomOverlay(adnl::AdnlNodeIdShort local_id, std::vector<adnl::AdnlNodeIdShort> nodes,
|
||||
std::map<adnl::AdnlNodeIdShort, int> senders, std::string name, FileHash zero_state_file_hash,
|
||||
FullNodeCustomOverlay(adnl::AdnlNodeIdShort local_id, CustomOverlayParams params, FileHash zero_state_file_hash,
|
||||
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager)
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<FullNode> full_node)
|
||||
: local_id_(local_id)
|
||||
, nodes_(std::move(nodes))
|
||||
, senders_(std::move(senders))
|
||||
, name_(std::move(name))
|
||||
, name_(std::move(params.name_))
|
||||
, nodes_(std::move(params.nodes_))
|
||||
, msg_senders_(std::move(params.msg_senders_))
|
||||
, block_senders_(std::move(params.block_senders_))
|
||||
, zero_state_file_hash_(zero_state_file_hash)
|
||||
, config_(config)
|
||||
, keyring_(keyring)
|
||||
|
@ -123,14 +141,16 @@ class FullNodeCustomOverlay : public td::actor::Actor {
|
|||
, rldp_(rldp)
|
||||
, rldp2_(rldp2)
|
||||
, overlays_(overlays)
|
||||
, validator_manager_(validator_manager) {
|
||||
, validator_manager_(validator_manager)
|
||||
, full_node_(full_node) {
|
||||
}
|
||||
|
||||
private:
|
||||
adnl::AdnlNodeIdShort local_id_;
|
||||
std::vector<adnl::AdnlNodeIdShort> nodes_;
|
||||
std::map<adnl::AdnlNodeIdShort, int> senders_;
|
||||
std::string name_;
|
||||
std::vector<adnl::AdnlNodeIdShort> nodes_;
|
||||
std::map<adnl::AdnlNodeIdShort, int> msg_senders_;
|
||||
std::set<adnl::AdnlNodeIdShort> block_senders_;
|
||||
FileHash zero_state_file_hash_;
|
||||
FullNodeConfig config_;
|
||||
|
||||
|
@ -140,6 +160,7 @@ class FullNodeCustomOverlay : public td::actor::Actor {
|
|||
td::actor::ActorId<rldp2::Rldp> rldp2_;
|
||||
td::actor::ActorId<overlay::Overlays> overlays_;
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager_;
|
||||
td::actor::ActorId<FullNode> full_node_;
|
||||
|
||||
bool inited_ = false;
|
||||
overlay::OverlayIdFull overlay_id_full_;
|
||||
|
|
|
@ -152,4 +152,63 @@ td::Status deserialize_block_full(ton_api::tonNode_DataFull& obj, BlockIdExt& id
|
|||
return S;
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> serialize_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Slice data,
|
||||
bool compression_enabled) {
|
||||
if (!compression_enabled) {
|
||||
return create_serialize_tl_object<ton_api::tonNode_newBlockCandidateBroadcast>(
|
||||
create_tl_block_id(block_id), cc_seqno, validator_set_hash,
|
||||
create_tl_object<ton_api::tonNode_blockSignature>(Bits256::zero(), td::BufferSlice()), td::BufferSlice(data));
|
||||
}
|
||||
TRY_RESULT(root, vm::std_boc_deserialize(data));
|
||||
TRY_RESULT(data_new, vm::std_boc_serialize(root, 2));
|
||||
td::BufferSlice compressed = td::lz4_compress(data_new);
|
||||
VLOG(FULL_NODE_DEBUG) << "Compressing block candidate broadcast: " << data.size() << " -> " << compressed.size();
|
||||
return create_serialize_tl_object<ton_api::tonNode_newBlockCandidateBroadcastCompressed>(
|
||||
create_tl_block_id(block_id), cc_seqno, validator_set_hash,
|
||||
create_tl_object<ton_api::tonNode_blockSignature>(Bits256::zero(), td::BufferSlice()), 0, std::move(compressed));
|
||||
}
|
||||
|
||||
static td::Status deserialize_block_candidate_broadcast(ton_api::tonNode_newBlockCandidateBroadcast& obj,
|
||||
BlockIdExt& block_id, CatchainSeqno& cc_seqno,
|
||||
td::uint32& validator_set_hash, td::BufferSlice& data) {
|
||||
block_id = create_block_id(obj.id_);
|
||||
cc_seqno = obj.catchain_seqno_;
|
||||
validator_set_hash = obj.validator_set_hash_;
|
||||
data = std::move(obj.data_);
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
static td::Status deserialize_block_candidate_broadcast(ton_api::tonNode_newBlockCandidateBroadcastCompressed& obj,
|
||||
BlockIdExt& block_id, CatchainSeqno& cc_seqno,
|
||||
td::uint32& validator_set_hash, td::BufferSlice& data,
|
||||
int max_decompressed_data_size) {
|
||||
block_id = create_block_id(obj.id_);
|
||||
cc_seqno = obj.catchain_seqno_;
|
||||
validator_set_hash = obj.validator_set_hash_;
|
||||
TRY_RESULT(decompressed, td::lz4_decompress(obj.compressed_, max_decompressed_data_size));
|
||||
TRY_RESULT(root, vm::std_boc_deserialize(decompressed));
|
||||
TRY_RESULT_ASSIGN(data, vm::std_boc_serialize(root, 31));
|
||||
VLOG(FULL_NODE_DEBUG) << "Decompressing block candidate broadcast: " << obj.compressed_.size() << " -> "
|
||||
<< data.size();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status deserialize_block_candidate_broadcast(ton_api::tonNode_Broadcast& obj, BlockIdExt& block_id,
|
||||
CatchainSeqno& cc_seqno, td::uint32& validator_set_hash,
|
||||
td::BufferSlice& data, int max_decompressed_data_size) {
|
||||
td::Status S;
|
||||
ton_api::downcast_call(obj, td::overloaded(
|
||||
[&](ton_api::tonNode_newBlockCandidateBroadcast& f) {
|
||||
S = deserialize_block_candidate_broadcast(f, block_id, cc_seqno, validator_set_hash,
|
||||
data);
|
||||
},
|
||||
[&](ton_api::tonNode_newBlockCandidateBroadcastCompressed& f) {
|
||||
S = deserialize_block_candidate_broadcast(f, block_id, cc_seqno, validator_set_hash,
|
||||
data, max_decompressed_data_size);
|
||||
},
|
||||
[&](auto&) { S = td::Status::Error("unknown data type"); }));
|
||||
return S;
|
||||
}
|
||||
|
||||
} // namespace ton::validator::fullnode
|
||||
|
|
|
@ -28,4 +28,11 @@ td::Result<td::BufferSlice> serialize_block_full(const BlockIdExt& id, td::Slice
|
|||
td::Status deserialize_block_full(ton_api::tonNode_DataFull& obj, BlockIdExt& id, td::BufferSlice& proof,
|
||||
td::BufferSlice& data, bool& is_proof_link, int max_decompressed_data_size);
|
||||
|
||||
td::Result<td::BufferSlice> serialize_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Slice data,
|
||||
bool compression_enabled);
|
||||
td::Status deserialize_block_candidate_broadcast(ton_api::tonNode_Broadcast& obj, BlockIdExt& block_id,
|
||||
CatchainSeqno& cc_seqno, td::uint32& validator_set_hash,
|
||||
td::BufferSlice& data, int max_decompressed_data_size);
|
||||
|
||||
} // namespace ton::validator::fullnode
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "checksum.h"
|
||||
#include "overlays.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "full-node-shard.hpp"
|
||||
#include "full-node-shard-queries.hpp"
|
||||
#include "full-node-serializer.hpp"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
@ -646,6 +648,35 @@ void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_ne
|
|||
query.block_->cc_seqno_, std::move(query.block_->data_));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query) {
|
||||
process_block_candidate_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src,
|
||||
ton_api::tonNode_newBlockCandidateBroadcastCompressed &query) {
|
||||
process_block_candidate_broadcast(src, query);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
|
||||
BlockIdExt block_id;
|
||||
CatchainSeqno cc_seqno;
|
||||
td::uint32 validator_set_hash;
|
||||
td::BufferSlice data;
|
||||
auto S = deserialize_block_candidate_broadcast(query, block_id, cc_seqno, validator_set_hash, data,
|
||||
overlay::Overlays::max_fec_broadcast_size());
|
||||
if (data.size() > FullNode::max_block_size()) {
|
||||
VLOG(FULL_NODE_WARNING) << "received block candidate with too big size from " << src;
|
||||
return;
|
||||
}
|
||||
if (td::sha256_bits256(data.as_slice()) != block_id.file_hash) {
|
||||
VLOG(FULL_NODE_WARNING) << "received block candidate with incorrect file hash from " << src;
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received newBlockCandidate from " << src << ": " << block_id.to_str();
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_candidate_broadcast, block_id, cc_seqno,
|
||||
validator_set_hash, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
|
||||
process_block_broadcast(src, query);
|
||||
}
|
||||
|
@ -661,17 +692,7 @@ void FullNodeShardImpl::process_block_broadcast(PublicKeyHash src, ton_api::tonN
|
|||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received block broadcast from " << src << ": " << B.ok().block_id.to_str();
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
if (R.error().code() == ErrorCode::notready) {
|
||||
LOG(DEBUG) << "dropped broadcast: " << R.move_as_error();
|
||||
} else {
|
||||
LOG(INFO) << "dropped broadcast: " << R.move_as_error();
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, B.move_as_ok(),
|
||||
std::move(P));
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
|
||||
|
@ -748,6 +769,23 @@ void FullNodeShardImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) {
|
||||
if (!client_.empty()) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
auto B =
|
||||
serialize_block_candidate_broadcast(block_id, cc_seqno, validator_set_hash, data, true); // compression enabled
|
||||
if (B.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to serialize block candidate broadcast: " << B.move_as_error();
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Sending newBlockCandidate: " << block_id.to_str();
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_,
|
||||
overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) {
|
||||
if (!client_.empty()) {
|
||||
UNREACHABLE();
|
||||
|
@ -1137,7 +1175,8 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id,
|
|||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client)
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client,
|
||||
td::actor::ActorId<FullNode> full_node)
|
||||
: shard_(shard)
|
||||
, local_id_(local_id)
|
||||
, adnl_id_(adnl_id)
|
||||
|
@ -1149,6 +1188,7 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id,
|
|||
, overlays_(overlays)
|
||||
, validator_manager_(validator_manager)
|
||||
, client_(client)
|
||||
, full_node_(full_node)
|
||||
, config_(config) {
|
||||
}
|
||||
|
||||
|
@ -1157,9 +1197,10 @@ td::actor::ActorOwn<FullNodeShard> FullNodeShard::create(
|
|||
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client) {
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node) {
|
||||
return td::actor::create_actor<FullNodeShardImpl>("tonnode", shard, local_id, adnl_id, zero_state_file_hash, config,
|
||||
keyring, adnl, rldp, rldp2, overlays, validator_manager, client);
|
||||
keyring, adnl, rldp, rldp2, overlays, validator_manager, client,
|
||||
full_node);
|
||||
}
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -41,6 +41,8 @@ class FullNodeShard : public td::actor::Actor {
|
|||
virtual void send_ihr_message(td::BufferSlice data) = 0;
|
||||
virtual void send_external_message(td::BufferSlice data) = 0;
|
||||
virtual void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) = 0;
|
||||
virtual void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) = 0;
|
||||
virtual void send_broadcast(BlockBroadcast broadcast) = 0;
|
||||
|
||||
virtual void sign_overlay_certificate(PublicKeyHash signed_key, td::uint32 expiry_at, td::uint32 max_size, td::Promise<td::BufferSlice> promise) = 0;
|
||||
|
@ -72,7 +74,7 @@ class FullNodeShard : public td::actor::Actor {
|
|||
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client);
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node);
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "full-node-shard.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/utils/port/Poll.h"
|
||||
|
@ -152,12 +153,19 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_ihrMessageBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcastCompressed &query);
|
||||
void process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
|
||||
|
||||
void receive_broadcast(PublicKeyHash src, td::BufferSlice query);
|
||||
void check_broadcast(PublicKeyHash src, td::BufferSlice query, td::Promise<td::Unit> promise);
|
||||
|
||||
void send_ihr_message(td::BufferSlice data) override;
|
||||
void send_external_message(td::BufferSlice data) override;
|
||||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override;
|
||||
void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) override;
|
||||
void send_broadcast(BlockBroadcast broadcast) override;
|
||||
|
||||
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
|
@ -214,7 +222,7 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client);
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node);
|
||||
|
||||
private:
|
||||
bool use_new_download() const {
|
||||
|
@ -236,6 +244,7 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::actor::ActorId<overlay::Overlays> overlays_;
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager_;
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client_;
|
||||
td::actor::ActorId<FullNode> full_node_;
|
||||
|
||||
td::uint32 attempt_ = 0;
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> pr
|
|||
|
||||
local_keys_.insert(key);
|
||||
create_private_block_overlay(key);
|
||||
for (auto &p : private_custom_overlays_) {
|
||||
update_ext_msg_overlay(p.first, p.second);
|
||||
for (auto &p : custom_overlays_) {
|
||||
update_custom_overlay(p.second);
|
||||
}
|
||||
|
||||
if (!sign_cert_by_.is_zero()) {
|
||||
|
@ -64,8 +64,8 @@ void FullNodeImpl::del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> pr
|
|||
}
|
||||
local_keys_.erase(key);
|
||||
private_block_overlays_.erase(key);
|
||||
for (auto &p : private_custom_overlays_) {
|
||||
update_ext_msg_overlay(p.first, p.second);
|
||||
for (auto &p : custom_overlays_) {
|
||||
update_custom_overlay(p.second);
|
||||
}
|
||||
|
||||
if (sign_cert_by_ != key) {
|
||||
|
@ -119,8 +119,8 @@ void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td:
|
|||
}
|
||||
local_id_ = adnl_id_.pubkey_hash();
|
||||
|
||||
for (auto &p : private_custom_overlays_) {
|
||||
update_ext_msg_overlay(p.first, p.second);
|
||||
for (auto &p : custom_overlays_) {
|
||||
update_custom_overlay(p.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,40 +132,37 @@ void FullNodeImpl::set_config(FullNodeConfig config) {
|
|||
for (auto& overlay : private_block_overlays_) {
|
||||
td::actor::send_closure(overlay.second, &FullNodePrivateBlockOverlay::set_config, config);
|
||||
}
|
||||
for (auto& overlay : private_custom_overlays_) {
|
||||
for (auto& overlay : custom_overlays_) {
|
||||
for (auto &actor : overlay.second.actors_) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::set_config, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::add_ext_msg_overlay(std::vector<adnl::AdnlNodeIdShort> nodes,
|
||||
std::map<adnl::AdnlNodeIdShort, int> senders, std::string name,
|
||||
td::Promise<td::Unit> promise) {
|
||||
if (nodes.empty()) {
|
||||
void FullNodeImpl::add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) {
|
||||
if (params.nodes_.empty()) {
|
||||
promise.set_error(td::Status::Error("list of nodes is empty"));
|
||||
return;
|
||||
}
|
||||
if (private_custom_overlays_.count(name)) {
|
||||
promise.set_error(td::Status::Error(PSTRING() << "duplicate overlay name \"" << name << "\""));
|
||||
std::string name = params.name_;
|
||||
if (custom_overlays_.count(name)) {
|
||||
promise.set_error(td::Status::Error(PSTRING() << "duplicate custom overlay name \"" << name << "\""));
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_WARNING) << "Adding private overlay for external messages \"" << name << "\", " << nodes.size()
|
||||
<< " nodes";
|
||||
auto &p = private_custom_overlays_[name];
|
||||
p.nodes_ = nodes;
|
||||
p.senders_ = senders;
|
||||
update_ext_msg_overlay(name, p);
|
||||
VLOG(FULL_NODE_WARNING) << "Adding custom overlay \"" << name << "\", " << params.nodes_.size() << " nodes";
|
||||
auto &p = custom_overlays_[name];
|
||||
p.params_ = std::move(params);
|
||||
update_custom_overlay(p);
|
||||
promise.set_result(td::Unit());
|
||||
}
|
||||
|
||||
void FullNodeImpl::del_ext_msg_overlay(std::string name, td::Promise<td::Unit> promise) {
|
||||
auto it = private_custom_overlays_.find(name);
|
||||
if (it == private_custom_overlays_.end()) {
|
||||
void FullNodeImpl::del_custom_overlay(std::string name, td::Promise<td::Unit> promise) {
|
||||
auto it = custom_overlays_.find(name);
|
||||
if (it == custom_overlays_.end()) {
|
||||
promise.set_error(td::Status::Error(PSTRING() << "no such overlay \"" << name << "\""));
|
||||
return;
|
||||
}
|
||||
private_custom_overlays_.erase(it);
|
||||
custom_overlays_.erase(it);
|
||||
promise.set_result(td::Unit());
|
||||
}
|
||||
|
||||
|
@ -182,8 +179,9 @@ void FullNodeImpl::initial_read_complete(BlockHandle top_handle) {
|
|||
void FullNodeImpl::add_shard(ShardIdFull shard) {
|
||||
while (true) {
|
||||
if (shards_.count(shard) == 0) {
|
||||
shards_.emplace(shard, FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, config_, keyring_,
|
||||
adnl_, rldp_, rldp2_, overlays_, validator_manager_, client_));
|
||||
shards_.emplace(shard,
|
||||
FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, config_, keyring_, adnl_,
|
||||
rldp_, rldp2_, overlays_, validator_manager_, client_, actor_id(this)));
|
||||
if (all_validators_.size() > 0) {
|
||||
td::actor::send_closure(shards_[shard], &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
|
@ -221,10 +219,10 @@ void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice dat
|
|||
VLOG(FULL_NODE_WARNING) << "dropping OUT ext message to unknown shard";
|
||||
return;
|
||||
}
|
||||
for (auto &private_overlay : private_custom_overlays_) {
|
||||
for (auto &private_overlay : custom_overlays_) {
|
||||
for (auto &actor : private_overlay.second.actors_) {
|
||||
auto local_id = actor.first;
|
||||
if (private_overlay.second.senders_.count(local_id)) {
|
||||
if (private_overlay.second.params_.msg_senders_.count(local_id)) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_external_message, data.clone());
|
||||
}
|
||||
}
|
||||
|
@ -245,13 +243,35 @@ void FullNodeImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_s
|
|||
td::actor::send_closure(shard, &FullNodeShard::send_shard_block_info, block_id, cc_seqno, std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_broadcast(BlockBroadcast broadcast) {
|
||||
void FullNodeImpl::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) {
|
||||
send_block_candidate_broadcast_to_custom_overlays(block_id, cc_seqno, validator_set_hash, data);
|
||||
auto shard = get_shard(ShardIdFull{masterchainId, shardIdAll});
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT shard block info message to unknown shard";
|
||||
return;
|
||||
}
|
||||
if (!private_block_overlays_.empty()) {
|
||||
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_block_candidate,
|
||||
block_id, cc_seqno, validator_set_hash, data.clone());
|
||||
}
|
||||
if (broadcast_block_candidates_in_public_overlay_) {
|
||||
td::actor::send_closure(shard, &FullNodeShard::send_block_candidate, block_id, cc_seqno, validator_set_hash,
|
||||
std::move(data));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) {
|
||||
send_block_broadcast_to_custom_overlays(broadcast);
|
||||
if (custom_overlays_only) {
|
||||
return;
|
||||
}
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT broadcast to unknown shard";
|
||||
return;
|
||||
}
|
||||
if (!private_block_overlays_.empty()) {
|
||||
if (broadcast.block_id.is_masterchain() && !private_block_overlays_.empty()) {
|
||||
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
|
||||
broadcast.clone());
|
||||
}
|
||||
|
@ -349,14 +369,12 @@ td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(AccountIdPrefixFull ds
|
|||
return get_shard(shard_prefix(dst, 60));
|
||||
}
|
||||
|
||||
void FullNodeImpl::got_key_block_state(td::Ref<ShardState> state) {
|
||||
auto m = td::Ref<MasterchainState>{std::move(state)};
|
||||
|
||||
void FullNodeImpl::got_key_block_config(td::Ref<ConfigHolder> config) {
|
||||
PublicKeyHash l = PublicKeyHash::zero();
|
||||
std::vector<PublicKeyHash> keys;
|
||||
std::map<PublicKeyHash, adnl::AdnlNodeIdShort> current_validators;
|
||||
for (td::int32 i = -1; i <= 1; i++) {
|
||||
auto r = m->get_total_validator_set(i < 0 ? i : 1 - i);
|
||||
auto r = config->get_total_validator_set(i < 0 ? i : 1 - i);
|
||||
if (r.not_null()) {
|
||||
auto vec = r->export_vector();
|
||||
for (auto &el : vec) {
|
||||
|
@ -372,16 +390,15 @@ void FullNodeImpl::got_key_block_state(td::Ref<ShardState> state) {
|
|||
}
|
||||
}
|
||||
|
||||
set_private_block_overlays_enable_compression(m->get_consensus_config().proto_version >= 3);
|
||||
|
||||
if (current_validators != current_validators_) {
|
||||
current_validators_ = std::move(current_validators);
|
||||
update_private_overlays();
|
||||
}
|
||||
|
||||
if (keys == all_validators_) {
|
||||
return;
|
||||
}
|
||||
// Let's turn off this optimization, since keyblocks are rare enough to update on each keyblock
|
||||
// if (keys == all_validators_) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
all_validators_ = keys;
|
||||
sign_cert_by_ = l;
|
||||
|
@ -393,18 +410,57 @@ void FullNodeImpl::got_key_block_state(td::Ref<ShardState> state) {
|
|||
}
|
||||
|
||||
void FullNodeImpl::new_key_block(BlockHandle handle) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to get key block state: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FullNodeImpl::got_key_block_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_shard_state_from_db, handle,
|
||||
std::move(P));
|
||||
if (handle->id().seqno() == 0) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to get zero state: " << R.move_as_error();
|
||||
} else {
|
||||
auto s = td::Ref<MasterchainState>{R.move_as_ok()};
|
||||
CHECK(s.not_null());
|
||||
td::actor::send_closure(SelfId, &FullNodeImpl::got_key_block_config, s->get_config_holder().move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_shard_state_from_db, handle,
|
||||
std::move(P));
|
||||
} else {
|
||||
CHECK(handle->is_key_block());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ProofLink>> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(FULL_NODE_WARNING) << "failed to get key block proof: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &FullNodeImpl::got_key_block_config,
|
||||
R.ok()->get_key_block_config().move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_proof_link_from_db, handle,
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::process_block_broadcast(BlockBroadcast broadcast) {
|
||||
send_block_broadcast_to_custom_overlays(broadcast);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, std::move(broadcast),
|
||||
[](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
if (R.error().code() == ErrorCode::notready) {
|
||||
LOG(DEBUG) << "dropped broadcast: " << R.move_as_error();
|
||||
} else {
|
||||
LOG(INFO) << "dropped broadcast: " << R.move_as_error();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FullNodeImpl::process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::BufferSlice data) {
|
||||
send_block_candidate_broadcast_to_custom_overlays(block_id, cc_seqno, validator_set_hash, data);
|
||||
// ignore cc_seqno and validator_hash for now
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_block_candidate, block_id,
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
void FullNodeImpl::start_up() {
|
||||
add_shard(ShardIdFull{masterchainId});
|
||||
if (local_id_.is_zero()) {
|
||||
if(adnl_id_.is_zero()) {
|
||||
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
||||
|
@ -435,8 +491,13 @@ void FullNodeImpl::start_up() {
|
|||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_shard_block_info, block_id, cc_seqno, std::move(data));
|
||||
}
|
||||
void send_broadcast(BlockBroadcast broadcast) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_broadcast, std::move(broadcast));
|
||||
void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_block_candidate, block_id, cc_seqno, validator_set_hash,
|
||||
std::move(data));
|
||||
}
|
||||
void send_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_broadcast, std::move(broadcast), custom_overlays_only);
|
||||
}
|
||||
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) override {
|
||||
|
@ -488,8 +549,8 @@ void FullNodeImpl::start_up() {
|
|||
}
|
||||
|
||||
void FullNodeImpl::update_private_overlays() {
|
||||
for (auto &p : private_custom_overlays_) {
|
||||
update_ext_msg_overlay(p.first, p.second);
|
||||
for (auto &p : custom_overlays_) {
|
||||
update_custom_overlay(p.second);
|
||||
}
|
||||
|
||||
private_block_overlays_.clear();
|
||||
|
@ -501,16 +562,6 @@ void FullNodeImpl::update_private_overlays() {
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::set_private_block_overlays_enable_compression(bool value) {
|
||||
if (private_block_overlays_enable_compression_ == value) {
|
||||
return;
|
||||
}
|
||||
private_block_overlays_enable_compression_ = true;
|
||||
for (auto &p : private_block_overlays_) {
|
||||
td::actor::send_closure(p.second, &FullNodePrivateBlockOverlay::set_enable_compression, value);
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::create_private_block_overlay(PublicKeyHash key) {
|
||||
CHECK(local_keys_.count(key));
|
||||
if (current_validators_.count(key)) {
|
||||
|
@ -519,29 +570,30 @@ void FullNodeImpl::create_private_block_overlay(PublicKeyHash key) {
|
|||
nodes.push_back(p.second);
|
||||
}
|
||||
private_block_overlays_[key] = td::actor::create_actor<FullNodePrivateBlockOverlay>(
|
||||
"BlocksPrivateOverlay", current_validators_[key], std::move(nodes), zero_state_file_hash_, config_,
|
||||
private_block_overlays_enable_compression_, keyring_, adnl_, rldp_, rldp2_, overlays_, validator_manager_);
|
||||
"BlocksPrivateOverlay", current_validators_[key], std::move(nodes), zero_state_file_hash_, config_, keyring_,
|
||||
adnl_, rldp_, rldp2_, overlays_, validator_manager_, actor_id(this));
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::update_ext_msg_overlay(const std::string &name, ExtMsgOverlayInfo &overlay) {
|
||||
void FullNodeImpl::update_custom_overlay(CustomOverlayInfo &overlay) {
|
||||
auto old_actors = std::move(overlay.actors_);
|
||||
overlay.actors_.clear();
|
||||
CustomOverlayParams ¶ms = overlay.params_;
|
||||
auto try_local_id = [&](const adnl::AdnlNodeIdShort &local_id) {
|
||||
if (std::find(overlay.nodes_.begin(), overlay.nodes_.end(), local_id) != overlay.nodes_.end()) {
|
||||
if (std::find(params.nodes_.begin(), params.nodes_.end(), local_id) != params.nodes_.end()) {
|
||||
auto it = old_actors.find(local_id);
|
||||
if (it != old_actors.end()) {
|
||||
overlay.actors_[local_id] = std::move(it->second);
|
||||
old_actors.erase(it);
|
||||
} else {
|
||||
overlay.actors_[local_id] = td::actor::create_actor<FullNodeCustomOverlay>(
|
||||
"CustomOverlay", local_id, overlay.nodes_, overlay.senders_, name, zero_state_file_hash_, config_,
|
||||
keyring_, adnl_, rldp_, rldp2_, overlays_, validator_manager_);
|
||||
"CustomOverlay", local_id, params, zero_state_file_hash_, config_, keyring_, adnl_, rldp_, rldp2_,
|
||||
overlays_, validator_manager_, actor_id(this));
|
||||
}
|
||||
}
|
||||
};
|
||||
try_local_id(adnl_id_);
|
||||
for (const PublicKeyHash &local_key: local_keys_) {
|
||||
for (const PublicKeyHash &local_key : local_keys_) {
|
||||
auto it = current_validators_.find(local_key);
|
||||
if (it != current_validators_.end()) {
|
||||
try_local_id(it->second);
|
||||
|
@ -549,6 +601,48 @@ void FullNodeImpl::update_ext_msg_overlay(const std::string &name, ExtMsgOverlay
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast& broadcast) {
|
||||
if (!custom_overlays_sent_broadcasts_.insert(broadcast.block_id).second) {
|
||||
return;
|
||||
}
|
||||
custom_overlays_sent_broadcasts_lru_.push(broadcast.block_id);
|
||||
if (custom_overlays_sent_broadcasts_lru_.size() > 256) {
|
||||
custom_overlays_sent_broadcasts_.erase(custom_overlays_sent_broadcasts_lru_.front());
|
||||
custom_overlays_sent_broadcasts_lru_.pop();
|
||||
}
|
||||
for (auto &private_overlay : custom_overlays_) {
|
||||
for (auto &actor : private_overlay.second.actors_) {
|
||||
auto local_id = actor.first;
|
||||
if (private_overlay.second.params_.block_senders_.count(local_id)) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_broadcast, broadcast.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_block_candidate_broadcast_to_custom_overlays(const BlockIdExt &block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash,
|
||||
const td::BufferSlice &data) {
|
||||
// Same cache of sent broadcasts as in send_block_broadcast_to_custom_overlays
|
||||
if (!custom_overlays_sent_broadcasts_.insert(block_id).second) {
|
||||
return;
|
||||
}
|
||||
custom_overlays_sent_broadcasts_lru_.push(block_id);
|
||||
if (custom_overlays_sent_broadcasts_lru_.size() > 256) {
|
||||
custom_overlays_sent_broadcasts_.erase(custom_overlays_sent_broadcasts_lru_.front());
|
||||
custom_overlays_sent_broadcasts_lru_.pop();
|
||||
}
|
||||
for (auto &private_overlay : custom_overlays_) {
|
||||
for (auto &actor : private_overlay.second.actors_) {
|
||||
auto local_id = actor.first;
|
||||
if (private_overlay.second.params_.block_senders_.count(local_id)) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_block_candidate, block_id, cc_seqno,
|
||||
validator_set_hash, data.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
|
||||
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
|
@ -569,7 +663,6 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id
|
|||
, client_(client)
|
||||
, db_root_(db_root)
|
||||
, config_(config) {
|
||||
add_shard(ShardIdFull{masterchainId});
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<FullNode> FullNode::create(ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
|
@ -598,6 +691,21 @@ bool FullNodeConfig::operator!=(const FullNodeConfig &rhs) const {
|
|||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
CustomOverlayParams CustomOverlayParams::fetch(const ton_api::engine_validator_customOverlay& f) {
|
||||
CustomOverlayParams c;
|
||||
c.name_ = f.name_;
|
||||
for (const auto &node : f.nodes_) {
|
||||
c.nodes_.emplace_back(node->adnl_id_);
|
||||
if (node->msg_sender_) {
|
||||
c.msg_senders_[ton::adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
|
||||
}
|
||||
if (node->block_sender_) {
|
||||
c.block_senders_.emplace(node->adnl_id_);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
} // namespace fullnode
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -55,6 +55,15 @@ struct FullNodeConfig {
|
|||
bool ext_messages_broadcast_disabled_ = false;
|
||||
};
|
||||
|
||||
struct CustomOverlayParams {
|
||||
std::string name_;
|
||||
std::vector<adnl::AdnlNodeIdShort> nodes_;
|
||||
std::map<adnl::AdnlNodeIdShort, int> msg_senders_;
|
||||
std::set<adnl::AdnlNodeIdShort> block_senders_;
|
||||
|
||||
static CustomOverlayParams fetch(const ton_api::engine_validator_customOverlay& f);
|
||||
};
|
||||
|
||||
class FullNode : public td::actor::Actor {
|
||||
public:
|
||||
virtual ~FullNode() = default;
|
||||
|
@ -74,10 +83,12 @@ class FullNode : public td::actor::Actor {
|
|||
virtual void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void set_config(FullNodeConfig config) = 0;
|
||||
|
||||
virtual void add_ext_msg_overlay(std::vector<adnl::AdnlNodeIdShort> nodes,
|
||||
std::map<adnl::AdnlNodeIdShort, int> senders, std::string name,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void del_ext_msg_overlay(std::string name, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void del_custom_overlay(std::string name, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void process_block_broadcast(BlockBroadcast broadcast) = 0;
|
||||
virtual void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::BufferSlice data) = 0;
|
||||
|
||||
static constexpr td::uint32 max_block_size() {
|
||||
return 4 << 20;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <queue>
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -53,9 +54,8 @@ class FullNodeImpl : public FullNode {
|
|||
void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) override;
|
||||
void set_config(FullNodeConfig config) override;
|
||||
|
||||
void add_ext_msg_overlay(std::vector<adnl::AdnlNodeIdShort> nodes, std::map<adnl::AdnlNodeIdShort, int> senders,
|
||||
std::string name, td::Promise<td::Unit> promise) override;
|
||||
void del_ext_msg_overlay(std::string name, td::Promise<td::Unit> promise) override;
|
||||
void add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) override;
|
||||
void del_custom_overlay(std::string name, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void add_shard(ShardIdFull shard);
|
||||
void del_shard(ShardIdFull shard);
|
||||
|
@ -66,7 +66,9 @@ class FullNodeImpl : public FullNode {
|
|||
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data);
|
||||
void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data);
|
||||
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqnp, td::BufferSlice data);
|
||||
void send_broadcast(BlockBroadcast broadcast);
|
||||
void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data);
|
||||
void send_broadcast(BlockBroadcast broadcast, bool custom_overlays_only);
|
||||
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout, td::Promise<ReceivedBlock> promise);
|
||||
void download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
|
@ -80,9 +82,13 @@ class FullNodeImpl : public FullNode {
|
|||
void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise);
|
||||
|
||||
void got_key_block_state(td::Ref<ShardState> state);
|
||||
void got_key_block_config(td::Ref<ConfigHolder> config);
|
||||
void new_key_block(BlockHandle handle);
|
||||
|
||||
void process_block_broadcast(BlockBroadcast broadcast) override;
|
||||
void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) override;
|
||||
|
||||
void start_up() override;
|
||||
|
||||
FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
|
||||
|
@ -121,20 +127,22 @@ class FullNodeImpl : public FullNode {
|
|||
FullNodeConfig config_;
|
||||
|
||||
std::map<PublicKeyHash, td::actor::ActorOwn<FullNodePrivateBlockOverlay>> private_block_overlays_;
|
||||
bool private_block_overlays_enable_compression_ = false;
|
||||
bool broadcast_block_candidates_in_public_overlay_ = false;
|
||||
|
||||
struct ExtMsgOverlayInfo {
|
||||
std::vector<adnl::AdnlNodeIdShort> nodes_;
|
||||
std::map<adnl::AdnlNodeIdShort, int> senders_;
|
||||
std::map<adnl::AdnlNodeIdShort, td::actor::ActorOwn<FullNodeCustomOverlay>>
|
||||
actors_; // our local id -> actor
|
||||
struct CustomOverlayInfo {
|
||||
CustomOverlayParams params_;
|
||||
std::map<adnl::AdnlNodeIdShort, td::actor::ActorOwn<FullNodeCustomOverlay>> actors_; // our local id -> actor
|
||||
};
|
||||
std::map<std::string, ExtMsgOverlayInfo> private_custom_overlays_;
|
||||
std::map<std::string, CustomOverlayInfo> custom_overlays_;
|
||||
std::set<BlockIdExt> custom_overlays_sent_broadcasts_;
|
||||
std::queue<BlockIdExt> custom_overlays_sent_broadcasts_lru_;
|
||||
|
||||
void update_private_overlays();
|
||||
void set_private_block_overlays_enable_compression(bool value);
|
||||
void create_private_block_overlay(PublicKeyHash key);
|
||||
void update_ext_msg_overlay(const std::string& name, ExtMsgOverlayInfo& overlay);
|
||||
void update_custom_overlay(CustomOverlayInfo& overlay);
|
||||
void send_block_broadcast_to_custom_overlays(const BlockBroadcast& broadcast);
|
||||
void send_block_candidate_broadcast_to_custom_overlays(const BlockIdExt& block_id, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, const td::BufferSlice& data);
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -899,11 +899,6 @@ void AcceptBlockQuery::written_block_info_2() {
|
|||
}
|
||||
|
||||
void AcceptBlockQuery::applied() {
|
||||
if (!send_broadcast_) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
|
||||
BlockBroadcast b;
|
||||
b.data = data_->data();
|
||||
b.block_id = id_;
|
||||
|
@ -923,7 +918,8 @@ void AcceptBlockQuery::applied() {
|
|||
}
|
||||
|
||||
// do not wait for answer
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::send_block_broadcast, std::move(b));
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::send_block_broadcast, std::move(b),
|
||||
/* custom_overlays_only = */ !send_broadcast_);
|
||||
|
||||
finish_query();
|
||||
}
|
||||
|
|
|
@ -5012,12 +5012,13 @@ bool Collator::create_block_candidate() {
|
|||
}
|
||||
// 4. save block candidate
|
||||
LOG(INFO) << "saving new BlockCandidate";
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::set_block_candidate, block_candidate->id,
|
||||
block_candidate->clone(), [self = get_self()](td::Result<td::Unit> saved) -> void {
|
||||
LOG(DEBUG) << "got answer to set_block_candidate";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::return_block_candidate,
|
||||
std::move(saved));
|
||||
});
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::set_block_candidate, block_candidate->id, block_candidate->clone(),
|
||||
validator_set_->get_catchain_seqno(), validator_set_->get_validator_set_hash(),
|
||||
[self = get_self()](td::Result<td::Unit> saved) -> void {
|
||||
LOG(DEBUG) << "got answer to set_block_candidate";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::return_block_candidate, std::move(saved));
|
||||
});
|
||||
// 5. communicate about bad and delayed external messages
|
||||
if (!bad_ext_msgs_.empty() || !delay_ext_msgs_.empty()) {
|
||||
LOG(INFO) << "sending complete_external_messages() to Manager";
|
||||
|
|
|
@ -86,24 +86,18 @@ td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice dat
|
|||
return Ref<ExtMessageQ>{true, std::move(data), std::move(ext_msg), dest_prefix, wc, addr};
|
||||
}
|
||||
|
||||
void ExtMessageQ::run_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
|
||||
td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
void ExtMessageQ::run_message(td::Ref<ExtMessage> message, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
td::Promise<td::Ref<ExtMessage>> promise) {
|
||||
auto R = create_ext_message(std::move(data), limits);
|
||||
if (R.is_error()) {
|
||||
return promise.set_error(R.move_as_error_prefix("failed to parse external message "));
|
||||
}
|
||||
auto M = R.move_as_ok();
|
||||
auto root = M->root_cell();
|
||||
auto root = message->root_cell();
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
tlb::unpack_cell_inexact(root, info); // checked in create message
|
||||
ton::StdSmcAddress addr = M->addr();
|
||||
ton::WorkchainId wc = M->wc();
|
||||
ton::StdSmcAddress addr = message->addr();
|
||||
ton::WorkchainId wc = message->wc();
|
||||
|
||||
run_fetch_account_state(
|
||||
wc, addr, manager,
|
||||
[promise = std::move(promise), msg_root = root, wc, addr,
|
||||
M](td::Result<std::tuple<td::Ref<vm::CellSlice>, UnixTime, LogicalTime, std::unique_ptr<block::ConfigInfo>>>
|
||||
[promise = std::move(promise), msg_root = root, wc, addr, message](
|
||||
td::Result<std::tuple<td::Ref<vm::CellSlice>, UnixTime, LogicalTime, std::unique_ptr<block::ConfigInfo>>>
|
||||
res) mutable {
|
||||
if (res.is_error()) {
|
||||
promise.set_error(td::Status::Error(PSLICE() << "Failed to get account state"));
|
||||
|
@ -120,7 +114,7 @@ void ExtMessageQ::run_message(td::BufferSlice data, block::SizeLimitsConfig::Ext
|
|||
} else {
|
||||
auto status = run_message_on_account(wc, &acc, utime, lt + 1, msg_root, std::move(config));
|
||||
if (status.is_ok()) {
|
||||
promise.set_value(std::move(M));
|
||||
promise.set_value(std::move(message));
|
||||
} else {
|
||||
promise.set_error(td::Status::Error(PSLICE() << "External message was not accepted\n"
|
||||
<< status.message()));
|
||||
|
|
|
@ -61,8 +61,7 @@ class ExtMessageQ : public ExtMessage {
|
|||
ton::StdSmcAddress addr);
|
||||
static td::Result<td::Ref<ExtMessageQ>> create_ext_message(td::BufferSlice data,
|
||||
block::SizeLimitsConfig::ExtMsgLimits limits);
|
||||
static void run_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
|
||||
td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
static void run_message(td::Ref<ExtMessage> message, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
td::Promise<td::Ref<ExtMessage>> promise);
|
||||
static td::Status run_message_on_account(ton::WorkchainId wc,
|
||||
block::Account* acc,
|
||||
|
|
|
@ -119,10 +119,9 @@ td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data,
|
|||
return std::move(res);
|
||||
}
|
||||
|
||||
void run_check_external_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
|
||||
td::actor::ActorId<ValidatorManager> manager,
|
||||
void run_check_external_message(Ref<ExtMessage> message, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<td::Ref<ExtMessage>> promise) {
|
||||
ExtMessageQ::run_message(std::move(data), limits, std::move(manager), std::move(promise));
|
||||
ExtMessageQ::run_message(std::move(message), std::move(manager), std::move(promise));
|
||||
}
|
||||
|
||||
td::Result<td::Ref<IhrMessage>> create_ihr_message(td::BufferSlice data) {
|
||||
|
|
|
@ -6330,7 +6330,8 @@ bool ValidateQuery::save_candidate() {
|
|||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager, &ValidatorManager::set_block_candidate, id_, block_candidate.clone(), std::move(P));
|
||||
td::actor::send_closure(manager, &ValidatorManager::set_block_candidate, id_, block_candidate.clone(),
|
||||
validator_set_->get_catchain_seqno(), validator_set_->get_validator_set_hash(), std::move(P));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,8 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
virtual void wait_block_signatures_short(BlockIdExt id, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<BlockSignatureSet>> promise) = 0;
|
||||
|
||||
virtual void set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void set_block_candidate(BlockIdExt id, BlockCandidate candidate, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void wait_block_state_merge(BlockIdExt left_id, BlockIdExt right_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
|
@ -133,7 +134,7 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
virtual void send_external_message(td::Ref<ExtMessage> message) = 0;
|
||||
virtual void send_ihr_message(td::Ref<IhrMessage> message) = 0;
|
||||
virtual void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) = 0;
|
||||
virtual void send_block_broadcast(BlockBroadcast broadcast) = 0;
|
||||
virtual void send_block_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) = 0;
|
||||
|
||||
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) = 0;
|
||||
|
@ -171,6 +172,7 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
virtual void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void log_validator_session_stats(BlockIdExt block_id, validatorsession::ValidatorSessionStats stats) = 0;
|
||||
virtual void log_new_validator_group_stats(validatorsession::NewValidatorGroupStats stats) = 0;
|
||||
|
||||
virtual void get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) = 0;
|
||||
virtual void get_block_data_for_litequery(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) = 0;
|
||||
|
|
|
@ -775,7 +775,8 @@ void ValidatorManagerImpl::set_next_block(BlockIdExt block_id, BlockIdExt next,
|
|||
get_block_handle(block_id, true, std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) {
|
||||
void ValidatorManagerImpl::set_block_candidate(BlockIdExt id, BlockCandidate candidate, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(db_, &Db::store_block_candidate, std::move(candidate), std::move(promise));
|
||||
}
|
||||
|
||||
|
|
|
@ -130,6 +130,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
void new_ihr_message(td::BufferSlice data) override;
|
||||
void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override;
|
||||
void new_block_candidate(BlockIdExt block_id, td::BufferSlice data) override {
|
||||
}
|
||||
|
||||
void add_ext_server_id(adnl::AdnlNodeIdShort id) override {
|
||||
UNREACHABLE();
|
||||
|
@ -177,7 +179,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void wait_block_signatures_short(BlockIdExt id, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<BlockSignatureSet>> promise) override;
|
||||
|
||||
void set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) override;
|
||||
void set_block_candidate(BlockIdExt id, BlockCandidate candidate, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void wait_block_state_merge(BlockIdExt left_id, BlockIdExt right_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) override;
|
||||
|
@ -251,7 +254,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
new_ihr_message(message->serialize());
|
||||
}
|
||||
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override;
|
||||
void send_block_broadcast(BlockBroadcast broadcast) override {
|
||||
void send_block_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) override {
|
||||
}
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||
|
@ -378,6 +381,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void log_validator_session_stats(BlockIdExt block_id, validatorsession::ValidatorSessionStats stats) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void log_new_validator_group_stats(validatorsession::NewValidatorGroupStats stats) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint32> promise) override {
|
||||
if (queue_size_counter_.empty()) {
|
||||
queue_size_counter_ =
|
||||
|
@ -416,6 +422,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
promise.set_result(td::Status::Error("not implemented"));
|
||||
}
|
||||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
|
||||
opts_ = std::move(opts);
|
||||
}
|
||||
|
||||
private:
|
||||
PublicKeyHash local_id_;
|
||||
|
||||
|
|
|
@ -152,6 +152,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void new_block_candidate(BlockIdExt block_id, td::BufferSlice data) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void add_ext_server_id(adnl::AdnlNodeIdShort id) override {
|
||||
UNREACHABLE();
|
||||
|
@ -215,7 +218,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void wait_block_signatures_short(BlockIdExt id, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<BlockSignatureSet>> promise) override;
|
||||
|
||||
void set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) override {
|
||||
void set_block_candidate(BlockIdExt id, BlockCandidate candidate, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Promise<td::Unit> promise) override {
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
|
@ -317,7 +321,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void send_block_broadcast(BlockBroadcast broadcast) override {
|
||||
void send_block_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) override {
|
||||
}
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override {
|
||||
|
@ -439,6 +443,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void log_validator_session_stats(BlockIdExt block_id, validatorsession::ValidatorSessionStats stats) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void log_new_validator_group_stats(validatorsession::NewValidatorGroupStats stats) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint32> promise) override {
|
||||
if (queue_size_counter_.empty()) {
|
||||
queue_size_counter_ =
|
||||
|
@ -476,6 +483,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) override {
|
||||
promise.set_result(td::Status::Error("not implemented"));
|
||||
}
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
|
||||
opts_ = std::move(opts);
|
||||
}
|
||||
|
||||
private:
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "manager.hpp"
|
||||
#include "checksum.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "validator-group.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "downloaders/wait-block-state.hpp"
|
||||
|
@ -410,14 +412,42 @@ void ValidatorManagerImpl::add_external_message(td::Ref<ExtMessage> msg, int pri
|
|||
ext_messages_hashes_[id.hash] = {priority, id};
|
||||
}
|
||||
void ValidatorManagerImpl::check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) {
|
||||
++ls_stats_check_ext_messages_;
|
||||
auto state = do_get_last_liteserver_state();
|
||||
if (state.is_null()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
|
||||
return;
|
||||
}
|
||||
run_check_external_message(std::move(data), state->get_ext_msg_limits(), actor_id(this),
|
||||
std::move(promise));
|
||||
auto R = create_ext_message(std::move(data), state->get_ext_msg_limits());
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix("failed to parse external message: "));
|
||||
return;
|
||||
}
|
||||
auto message = R.move_as_ok();
|
||||
WorkchainId wc = message->wc();
|
||||
StdSmcAddress addr = message->addr();
|
||||
if (checked_ext_msg_counter_.get_msg_count(wc, addr) >= max_ext_msg_per_addr()) {
|
||||
promise.set_error(
|
||||
td::Status::Error(PSTRING() << "too many external messages to address " << wc << ":" << addr.to_hex()));
|
||||
return;
|
||||
}
|
||||
|
||||
promise = [self = this, wc, addr, promise = std::move(promise),
|
||||
SelfId = actor_id(this)](td::Result<td::Ref<ExtMessage>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
td::actor::send_lambda(SelfId, [=, promise = std::move(promise), message = R.move_as_ok()]() mutable {
|
||||
if (self->checked_ext_msg_counter_.inc_msg_count(wc, addr) > max_ext_msg_per_addr()) {
|
||||
promise.set_error(
|
||||
td::Status::Error(PSTRING() << "too many external messages to address " << wc << ":" << addr.to_hex()));
|
||||
return;
|
||||
}
|
||||
promise.set_result(std::move(message));
|
||||
});
|
||||
};
|
||||
++ls_stats_check_ext_messages_;
|
||||
run_check_external_message(std::move(message), actor_id(this), std::move(promise));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::new_ihr_message(td::BufferSlice data) {
|
||||
|
@ -464,6 +494,17 @@ void ValidatorManagerImpl::new_shard_block(BlockIdExt block_id, CatchainSeqno cc
|
|||
actor_id(this), td::Timestamp::in(2.0), std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::new_block_candidate(BlockIdExt block_id, td::BufferSlice data) {
|
||||
if (!last_masterchain_block_handle_) {
|
||||
VLOG(VALIDATOR_DEBUG) << "dropping top shard block broadcast: not inited";
|
||||
return;
|
||||
}
|
||||
if (!started_) {
|
||||
return;
|
||||
}
|
||||
add_cached_block_candidate(ReceivedBlock{block_id, std::move(data)});
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_shard_block_description(td::Ref<ShardTopBlockDescription> desc) {
|
||||
if (desc->may_be_valid(last_masterchain_block_handle_, last_masterchain_state_)) {
|
||||
auto it = shard_blocks_.find(ShardTopBlockDescriptionId{desc->shard(), desc->catchain_seqno()});
|
||||
|
@ -495,6 +536,36 @@ void ValidatorManagerImpl::add_shard_block_description(td::Ref<ShardTopBlockDesc
|
|||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_cached_block_candidate(ReceivedBlock block) {
|
||||
BlockIdExt id = block.id;
|
||||
if (block.id.is_masterchain()) {
|
||||
return;
|
||||
}
|
||||
if (cached_block_candidates_.emplace(id, std::move(block)).second) {
|
||||
cached_block_candidates_lru_.push_back(id);
|
||||
{
|
||||
auto it = wait_block_data_.find(id);
|
||||
if (it != wait_block_data_.end()) {
|
||||
auto r_block = create_block(cached_block_candidates_[id].clone());
|
||||
if (r_block.is_ok()) {
|
||||
td::actor::send_closure(it->second.actor_, &WaitBlockData::got_block_data_from_net, r_block.move_as_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
auto it = wait_state_.find(id);
|
||||
if (it != wait_state_.end()) {
|
||||
// Proof link is not ready at this point, but this will force WaitBlockState to redo send_get_proof_link_request
|
||||
td::actor::send_closure(it->second.actor_, &WaitBlockState::after_get_proof_link);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cached_block_candidates_lru_.size() > max_cached_candidates()) {
|
||||
CHECK(cached_block_candidates_.erase(cached_block_candidates_lru_.front()));
|
||||
cached_block_candidates_lru_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_ext_server_id(adnl::AdnlNodeIdShort id) {
|
||||
class Cb : public adnl::Adnl::Callback {
|
||||
private:
|
||||
|
@ -1189,11 +1260,16 @@ void ValidatorManagerImpl::set_next_block(BlockIdExt block_id, BlockIdExt next,
|
|||
get_block_handle(block_id, true, std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) {
|
||||
void ValidatorManagerImpl::set_block_candidate(BlockIdExt id, BlockCandidate candidate, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Promise<td::Unit> promise) {
|
||||
if (!candidates_buffer_.empty()) {
|
||||
td::actor::send_closure(candidates_buffer_, &CandidatesBuffer::add_new_candidate, id,
|
||||
PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}, candidate.collated_file_hash);
|
||||
}
|
||||
if (!id.is_masterchain()) {
|
||||
add_cached_block_candidate(ReceivedBlock{id, candidate.data.clone()});
|
||||
callback_->send_block_candidate(id, cc_seqno, validator_set_hash, candidate.data.clone());
|
||||
}
|
||||
td::actor::send_closure(db_, &Db::store_block_candidate, std::move(candidate), std::move(promise));
|
||||
}
|
||||
|
||||
|
@ -1450,6 +1526,13 @@ void ValidatorManagerImpl::get_last_liteserver_state_block(
|
|||
|
||||
void ValidatorManagerImpl::send_get_block_request(BlockIdExt id, td::uint32 priority,
|
||||
td::Promise<ReceivedBlock> promise) {
|
||||
{
|
||||
auto it = cached_block_candidates_.find(id);
|
||||
if (it != cached_block_candidates_.end()) {
|
||||
LOG(DEBUG) << "send_get_block_request: got result from candidates cache for " << id.to_str();
|
||||
return promise.set_value(it->second.clone());
|
||||
}
|
||||
}
|
||||
callback_->download_block(id, priority, td::Timestamp::in(10.0), std::move(promise));
|
||||
}
|
||||
|
||||
|
@ -1472,6 +1555,20 @@ void ValidatorManagerImpl::send_get_block_proof_request(BlockIdExt block_id, td:
|
|||
|
||||
void ValidatorManagerImpl::send_get_block_proof_link_request(BlockIdExt block_id, td::uint32 priority,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (!block_id.is_masterchain()) {
|
||||
auto it = cached_block_candidates_.find(block_id);
|
||||
if (it != cached_block_candidates_.end()) {
|
||||
// Proof link can be created from the cached block candidate
|
||||
LOG(DEBUG) << "send_get_block_proof_link_request: creating proof link from cached caniddate for "
|
||||
<< block_id.to_str();
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, block_root, vm::std_boc_deserialize(it->second.data),
|
||||
"failed to create proof link: ");
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, proof_link, WaitBlockData::generate_proof_link(it->second.id, block_root),
|
||||
"failed to create proof link: ");
|
||||
promise.set_result(std::move(proof_link));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback_->download_block_proof_link(block_id, priority, td::Timestamp::in(10.0), std::move(promise));
|
||||
}
|
||||
|
||||
|
@ -1503,8 +1600,8 @@ void ValidatorManagerImpl::send_top_shard_block_description(td::Ref<ShardTopBloc
|
|||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::send_block_broadcast(BlockBroadcast broadcast) {
|
||||
callback_->send_broadcast(std::move(broadcast));
|
||||
void ValidatorManagerImpl::send_block_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) {
|
||||
callback_->send_broadcast(std::move(broadcast), custom_overlays_only);
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::start_up() {
|
||||
|
@ -2135,7 +2232,7 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
|
|||
auto G = td::actor::create_actor<ValidatorGroup>(
|
||||
"validatorgroup", shard, validator_id, session_id, validator_set, opts, keyring_, adnl_, rldp_, overlays_,
|
||||
db_root_, actor_id(this), init_session,
|
||||
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()));
|
||||
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), opts_);
|
||||
return G;
|
||||
}
|
||||
}
|
||||
|
@ -2418,9 +2515,9 @@ void ValidatorManagerImpl::state_serializer_update(BlockSeqno seqno) {
|
|||
void ValidatorManagerImpl::alarm() {
|
||||
try_advance_gc_masterchain_block();
|
||||
alarm_timestamp() = td::Timestamp::in(1.0);
|
||||
if (last_masterchain_block_handle_ && gc_masterchain_handle_) {
|
||||
td::actor::send_closure(db_, &Db::run_gc, last_masterchain_block_handle_->unix_time(),
|
||||
gc_masterchain_handle_->unix_time(), static_cast<UnixTime>(opts_->archive_ttl()));
|
||||
if (shard_client_handle_ && gc_masterchain_handle_) {
|
||||
td::actor::send_closure(db_, &Db::run_gc, shard_client_handle_->unix_time(), gc_masterchain_handle_->unix_time(),
|
||||
static_cast<UnixTime>(opts_->archive_ttl()));
|
||||
}
|
||||
if (log_status_at_.is_in_past()) {
|
||||
if (last_masterchain_block_handle_) {
|
||||
|
@ -2523,6 +2620,16 @@ void ValidatorManagerImpl::alarm() {
|
|||
log_ls_stats_at_ = td::Timestamp::in(60.0);
|
||||
}
|
||||
alarm_timestamp().relax(log_ls_stats_at_);
|
||||
if (cleanup_mempool_at_.is_in_past()) {
|
||||
if (is_validator()) {
|
||||
get_external_messages(ShardIdFull{masterchainId, shardIdAll},
|
||||
[](td::Result<std::vector<std::pair<td::Ref<ExtMessage>, int>>>) {});
|
||||
get_external_messages(ShardIdFull{basechainId, shardIdAll},
|
||||
[](td::Result<std::vector<std::pair<td::Ref<ExtMessage>, int>>>) {});
|
||||
}
|
||||
cleanup_mempool_at_ = td::Timestamp::in(250.0);
|
||||
}
|
||||
alarm_timestamp().relax(cleanup_mempool_at_);
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) {
|
||||
|
@ -2714,8 +2821,12 @@ void ValidatorManagerImpl::log_validator_session_stats(BlockIdExt block_id,
|
|||
std::vector<tl_object_ptr<ton_api::validatorSession_statsProducer>> producers;
|
||||
for (const auto &producer : round.producers) {
|
||||
producers.push_back(create_tl_object<ton_api::validatorSession_statsProducer>(
|
||||
producer.id.bits256_value(), producer.candidate_id, producer.block_status, producer.block_timestamp,
|
||||
producer.comment));
|
||||
producer.id.bits256_value(), producer.candidate_id, producer.block_status, producer.comment,
|
||||
producer.block_timestamp, producer.is_accepted, producer.is_ours, producer.got_submit_at,
|
||||
producer.collation_time, producer.collated_at, producer.collation_cached, producer.validation_time,
|
||||
producer.validated_at, producer.validation_cached, producer.gen_utime, producer.approved_weight,
|
||||
producer.approved_33pct_at, producer.approved_66pct_at, producer.signed_weight, producer.signed_33pct_at,
|
||||
producer.signed_66pct_at, producer.serialize_time, producer.deserialize_time, producer.serialized_size));
|
||||
}
|
||||
rounds.push_back(create_tl_object<ton_api::validatorSession_statsRound>(round.timestamp, std::move(producers)));
|
||||
}
|
||||
|
@ -2725,7 +2836,7 @@ void ValidatorManagerImpl::log_validator_session_stats(BlockIdExt block_id,
|
|||
stats.cc_seqno, stats.creator.bits256_value(), stats.total_validators, stats.total_weight, stats.signatures,
|
||||
stats.signatures_weight, stats.approve_signatures, stats.approve_signatures_weight, stats.first_round,
|
||||
std::move(rounds));
|
||||
std::string s = td::json_encode<std::string>(td::ToJson(*obj.get()), false);
|
||||
auto s = td::json_encode<std::string>(td::ToJson(*obj.get()), false);
|
||||
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return c == '\n' || c == '\r'; }), s.end());
|
||||
|
||||
std::ofstream file;
|
||||
|
@ -2733,7 +2844,31 @@ void ValidatorManagerImpl::log_validator_session_stats(BlockIdExt block_id,
|
|||
file << s << "\n";
|
||||
file.close();
|
||||
|
||||
LOG(INFO) << "Writing validator session stats for " << block_id.id;
|
||||
LOG(INFO) << "Writing validator session stats for " << block_id.id.to_str();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::log_new_validator_group_stats(validatorsession::NewValidatorGroupStats stats) {
|
||||
std::string fname = opts_->get_session_logs_file();
|
||||
if (fname.empty()) {
|
||||
return;
|
||||
}
|
||||
std::vector<tl_object_ptr<ton_api::validatorSession_newValidatorGroupStats_node>> nodes;
|
||||
for (const auto &node : stats.nodes) {
|
||||
nodes.push_back(
|
||||
create_tl_object<ton_api::validatorSession_newValidatorGroupStats_node>(node.id.bits256_value(), node.weight));
|
||||
}
|
||||
auto obj = create_tl_object<ton_api::validatorSession_newValidatorGroupStats>(
|
||||
stats.session_id, stats.shard.workchain, stats.shard.shard, stats.cc_seqno, stats.timestamp, stats.self_idx,
|
||||
std::move(nodes));
|
||||
auto s = td::json_encode<std::string>(td::ToJson(*obj.get()), false);
|
||||
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return c == '\n' || c == '\r'; }), s.end());
|
||||
|
||||
std::ofstream file;
|
||||
file.open(fname, std::ios_base::app);
|
||||
file << s << "\n";
|
||||
file.close();
|
||||
|
||||
LOG(INFO) << "Writing new validator group stats for " << stats.shard.to_str();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::get_block_handle_for_litequery(BlockIdExt block_id, td::Promise<ConstBlockHandle> promise) {
|
||||
|
@ -2997,6 +3132,14 @@ void ValidatorManagerImpl::get_validator_groups_info_for_litequery(
|
|||
td::actor::create_actor<Actor>("get-validator-groups-info", std::move(groups), std::move(promise)).release();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::update_options(td::Ref<ValidatorManagerOptions> opts) {
|
||||
// Currently options can be updated only to change state_serializer_enabled flag
|
||||
if (!serializer_.empty()) {
|
||||
td::actor::send_closure(serializer_, &AsyncStateSerializer::update_options, opts);
|
||||
}
|
||||
opts_ = std::move(opts);
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
|
||||
td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
|
@ -3005,6 +3148,29 @@ td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
|
|||
rldp, overlays);
|
||||
}
|
||||
|
||||
size_t ValidatorManagerImpl::CheckedExtMsgCounter::get_msg_count(WorkchainId wc, StdSmcAddress addr) {
|
||||
before_query();
|
||||
auto it1 = counter_cur_.find({wc, addr});
|
||||
auto it2 = counter_prev_.find({wc, addr});
|
||||
return (it1 == counter_cur_.end() ? 0 : it1->second) + (it2 == counter_prev_.end() ? 0 : it2->second);
|
||||
}
|
||||
size_t ValidatorManagerImpl::CheckedExtMsgCounter::inc_msg_count(WorkchainId wc, StdSmcAddress addr) {
|
||||
before_query();
|
||||
auto it2 = counter_prev_.find({wc, addr});
|
||||
return (it2 == counter_prev_.end() ? 0 : it2->second) + ++counter_cur_[{wc, addr}];
|
||||
}
|
||||
void ValidatorManagerImpl::CheckedExtMsgCounter::before_query() {
|
||||
while (cleanup_at_.is_in_past()) {
|
||||
counter_prev_ = std::move(counter_cur_);
|
||||
counter_cur_.clear();
|
||||
if (counter_prev_.empty()) {
|
||||
cleanup_at_ = td::Timestamp::in(max_ext_msg_per_addr_time_window() / 2.0);
|
||||
break;
|
||||
}
|
||||
cleanup_at_ += max_ext_msg_per_addr_time_window() / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -18,10 +18,14 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/refcnt.hpp"
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "interfaces/db.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/port/Poll.h"
|
||||
#include "td/utils/port/StdStreams.h"
|
||||
#include "validator-group.hpp"
|
||||
#include "shard-client.hpp"
|
||||
#include "manager-init.h"
|
||||
|
@ -220,6 +224,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
};
|
||||
// DATA FOR COLLATOR
|
||||
std::map<ShardTopBlockDescriptionId, td::Ref<ShardTopBlockDescription>> shard_blocks_;
|
||||
|
||||
std::map<BlockIdExt, ReceivedBlock> cached_block_candidates_;
|
||||
std::list<BlockIdExt> cached_block_candidates_lru_;
|
||||
|
||||
struct ExtMessages {
|
||||
std::map<MessageId<ExtMessage>, std::unique_ptr<MessageExt<ExtMessage>>> ext_messages_;
|
||||
std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, std::map<ExtMessage::Hash, MessageId<ExtMessage>>>
|
||||
|
@ -233,10 +241,20 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
};
|
||||
std::map<int, ExtMessages> ext_msgs_; // priority -> messages
|
||||
std::map<ExtMessage::Hash, std::pair<int, MessageId<ExtMessage>>> ext_messages_hashes_; // hash -> priority
|
||||
td::Timestamp cleanup_mempool_at_;
|
||||
// IHR ?
|
||||
std::map<MessageId<IhrMessage>, std::unique_ptr<MessageExt<IhrMessage>>> ihr_messages_;
|
||||
std::map<IhrMessage::Hash, MessageId<IhrMessage>> ihr_messages_hashes_;
|
||||
|
||||
struct CheckedExtMsgCounter {
|
||||
std::map<std::pair<WorkchainId, StdSmcAddress>, size_t> counter_cur_, counter_prev_;
|
||||
td::Timestamp cleanup_at_ = td::Timestamp::now();
|
||||
|
||||
size_t get_msg_count(WorkchainId wc, StdSmcAddress addr);
|
||||
size_t inc_msg_count(WorkchainId wc, StdSmcAddress addr);
|
||||
void before_query();
|
||||
} checked_ext_msg_counter_;
|
||||
|
||||
private:
|
||||
// VALIDATOR GROUPS
|
||||
ValidatorSessionId get_validator_set_id(ShardIdFull shard, td::Ref<ValidatorSet> val_set, td::Bits256 opts_hash,
|
||||
|
@ -365,6 +383,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
|
||||
void new_ihr_message(td::BufferSlice data) override;
|
||||
void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override;
|
||||
void new_block_candidate(BlockIdExt block_id, td::BufferSlice data) override;
|
||||
|
||||
void add_ext_server_id(adnl::AdnlNodeIdShort id) override;
|
||||
void add_ext_server_port(td::uint16 port) override;
|
||||
|
@ -409,7 +428,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void wait_block_signatures_short(BlockIdExt id, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<BlockSignatureSet>> promise) override;
|
||||
|
||||
void set_block_candidate(BlockIdExt id, BlockCandidate candidate, td::Promise<td::Unit> promise) override;
|
||||
void set_block_candidate(BlockIdExt id, BlockCandidate candidate, CatchainSeqno cc_seqno,
|
||||
td::uint32 validator_set_hash, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void wait_block_state_merge(BlockIdExt left_id, BlockIdExt right_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) override;
|
||||
|
@ -473,7 +493,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void send_external_message(td::Ref<ExtMessage> message) override;
|
||||
void send_ihr_message(td::Ref<IhrMessage> message) override;
|
||||
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override;
|
||||
void send_block_broadcast(BlockBroadcast broadcast) override;
|
||||
void send_block_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) override;
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
|
||||
|
@ -503,6 +523,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
|
||||
void add_shard_block_description(td::Ref<ShardTopBlockDescription> desc);
|
||||
void add_cached_block_candidate(ReceivedBlock block);
|
||||
|
||||
void register_block_handle(BlockHandle handle);
|
||||
|
||||
|
@ -565,6 +586,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void log_validator_session_stats(BlockIdExt block_id, validatorsession::ValidatorSessionStats stats) override;
|
||||
void log_new_validator_group_stats(validatorsession::NewValidatorGroupStats stats) override;
|
||||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts) override;
|
||||
|
||||
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint32> promise) override {
|
||||
if (queue_size_counter_.empty()) {
|
||||
|
@ -663,6 +687,15 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
double max_mempool_num() const {
|
||||
return opts_->max_mempool_num();
|
||||
}
|
||||
size_t max_cached_candidates() const {
|
||||
return 128;
|
||||
}
|
||||
static double max_ext_msg_per_addr_time_window() {
|
||||
return 10.0;
|
||||
}
|
||||
static size_t max_ext_msg_per_addr() {
|
||||
return 3 * 10;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<BlockSeqno, WaitList<td::actor::Actor, td::Unit>> shard_client_waiters_;
|
||||
|
|
|
@ -27,6 +27,9 @@ namespace ton {
|
|||
namespace validator {
|
||||
|
||||
void AsyncStateSerializer::start_up() {
|
||||
if (!opts_->get_state_serializer_enabled()) {
|
||||
LOG(ERROR) << "Persistent state serializer is disabled";
|
||||
}
|
||||
alarm_timestamp() = td::Timestamp::in(1.0 + td::Random::fast(0, 10) * 1.0);
|
||||
running_ = true;
|
||||
|
||||
|
@ -130,29 +133,35 @@ void AsyncStateSerializer::next_iteration() {
|
|||
}
|
||||
CHECK(masterchain_handle_->id() == last_block_id_);
|
||||
if (attempt_ < max_attempt() && last_key_block_id_.id.seqno < last_block_id_.id.seqno &&
|
||||
need_serialize(masterchain_handle_)) {
|
||||
need_serialize(masterchain_handle_) && opts_->get_state_serializer_enabled()) {
|
||||
if (!have_masterchain_state_) {
|
||||
LOG(INFO) << "started serializing persistent state for " << masterchain_handle_->id().id;
|
||||
LOG(ERROR) << "started serializing persistent state for " << masterchain_handle_->id().id.to_str();
|
||||
// block next attempts immediately, but send actual request later
|
||||
running_ = true;
|
||||
double delay = td::Random::fast(0, 3600);
|
||||
LOG(WARNING) << "serializer delay = " << delay << "s";
|
||||
delay_action([SelfId = actor_id(
|
||||
this)]() { td::actor::send_closure(SelfId, &AsyncStateSerializer::request_masterchain_state); },
|
||||
td::Timestamp::in(td::Random::fast(0, 3600)));
|
||||
td::Timestamp::in(delay));
|
||||
return;
|
||||
}
|
||||
while (next_idx_ < shards_.size()) {
|
||||
if (!need_monitor(shards_[next_idx_].shard_full())) {
|
||||
next_idx_++;
|
||||
} else {
|
||||
// block next attempts immediately, but send actual request later
|
||||
running_ = true;
|
||||
delay_action(
|
||||
[SelfId = actor_id(this), shard = shards_[next_idx_]]() { td::actor::send_closure(SelfId, &AsyncStateSerializer::request_shard_state, shard); },
|
||||
td::Timestamp::in(td::Random::fast(0, 1800)));
|
||||
// block next attempts immediately, but send actual request later
|
||||
running_ = true;
|
||||
double delay = td::Random::fast(0, 1800);
|
||||
LOG(WARNING) << "serializer delay = " << delay << "s";
|
||||
delay_action(
|
||||
[SelfId = actor_id(this), shard = shards_[next_idx_]]() {
|
||||
td::actor::send_closure(SelfId, &AsyncStateSerializer::request_shard_state, shard);
|
||||
},
|
||||
td::Timestamp::in(delay));
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "finished serializing persistent state for " << masterchain_handle_->id().id;
|
||||
LOG(ERROR) << "finished serializing persistent state for " << masterchain_handle_->id().id.to_str();
|
||||
last_key_block_ts_ = masterchain_handle_->unix_time();
|
||||
last_key_block_id_ = masterchain_handle_->id();
|
||||
}
|
||||
|
@ -168,6 +177,9 @@ void AsyncStateSerializer::next_iteration() {
|
|||
return;
|
||||
}
|
||||
if (masterchain_handle_->inited_next_left()) {
|
||||
if (need_serialize(masterchain_handle_) && !opts_->get_state_serializer_enabled()) {
|
||||
LOG(ERROR) << "skipping serializing persistent state for " << masterchain_handle_->id().id.to_str();
|
||||
}
|
||||
last_block_id_ = masterchain_handle_->one_next(true);
|
||||
have_masterchain_state_ = false;
|
||||
masterchain_handle_ = nullptr;
|
||||
|
@ -194,7 +206,11 @@ void AsyncStateSerializer::got_masterchain_handle(BlockHandle handle) {
|
|||
|
||||
void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state,
|
||||
std::shared_ptr<vm::CellDbReader> cell_db_reader) {
|
||||
LOG(INFO) << "serializing masterchain state " << masterchain_handle_->id().id;
|
||||
if (!opts_->get_state_serializer_enabled()) {
|
||||
stored_masterchain_state();
|
||||
return;
|
||||
}
|
||||
LOG(ERROR) << "serializing masterchain state " << masterchain_handle_->id().id.to_str();
|
||||
have_masterchain_state_ = true;
|
||||
CHECK(next_idx_ == 0);
|
||||
CHECK(shards_.size() == 0);
|
||||
|
@ -204,11 +220,16 @@ void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state
|
|||
shards_.push_back(v->top_block_id());
|
||||
}
|
||||
|
||||
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader](td::FileFd& fd) {
|
||||
return vm::std_boc_serialize_to_file_large(cell_db_reader, hash, fd, 31);
|
||||
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader,
|
||||
cancellation_token = cancellation_token_source_.get_cancellation_token()](td::FileFd& fd) mutable {
|
||||
return vm::std_boc_serialize_to_file_large(cell_db_reader, hash, fd, 31, std::move(cancellation_token));
|
||||
};
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
if (R.is_error() && R.error().code() == cancelled) {
|
||||
LOG(ERROR) << "Persistent state serialization cancelled";
|
||||
} else {
|
||||
R.ensure();
|
||||
}
|
||||
td::actor::send_closure(SelfId, &AsyncStateSerializer::stored_masterchain_state);
|
||||
});
|
||||
|
||||
|
@ -217,7 +238,7 @@ void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state
|
|||
}
|
||||
|
||||
void AsyncStateSerializer::stored_masterchain_state() {
|
||||
LOG(INFO) << "finished serializing masterchain state " << masterchain_handle_->id().id;
|
||||
LOG(ERROR) << "finished serializing masterchain state " << masterchain_handle_->id().id.to_str();
|
||||
running_ = false;
|
||||
next_iteration();
|
||||
}
|
||||
|
@ -247,13 +268,22 @@ void AsyncStateSerializer::got_shard_handle(BlockHandle handle) {
|
|||
|
||||
void AsyncStateSerializer::got_shard_state(BlockHandle handle, td::Ref<ShardState> state,
|
||||
std::shared_ptr<vm::CellDbReader> cell_db_reader) {
|
||||
LOG(INFO) << "serializing shard state " << handle->id().id;
|
||||
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader](td::FileFd& fd) {
|
||||
return vm::std_boc_serialize_to_file_large(cell_db_reader, hash, fd, 31);
|
||||
if (!opts_->get_state_serializer_enabled()) {
|
||||
success_handler();
|
||||
return;
|
||||
}
|
||||
LOG(ERROR) << "serializing shard state " << handle->id().id.to_str();
|
||||
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader,
|
||||
cancellation_token = cancellation_token_source_.get_cancellation_token()](td::FileFd& fd) mutable {
|
||||
return vm::std_boc_serialize_to_file_large(cell_db_reader, hash, fd, 31, std::move(cancellation_token));
|
||||
};
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
LOG(INFO) << "finished serializing shard state " << handle->id().id;
|
||||
if (R.is_error() && R.error().code() == cancelled) {
|
||||
LOG(ERROR) << "Persistent state serialization cancelled";
|
||||
} else {
|
||||
R.ensure();
|
||||
LOG(ERROR) << "finished serializing shard state " << handle->id().id.to_str();
|
||||
}
|
||||
td::actor::send_closure(SelfId, &AsyncStateSerializer::success_handler);
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::store_persistent_state_file_gen, handle->id(),
|
||||
|
@ -279,6 +309,14 @@ void AsyncStateSerializer::success_handler() {
|
|||
next_iteration();
|
||||
}
|
||||
|
||||
void AsyncStateSerializer::update_options(td::Ref<ValidatorManagerOptions> opts) {
|
||||
opts_ = std::move(opts);
|
||||
if (!opts_->get_state_serializer_enabled()) {
|
||||
cancellation_token_source_.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AsyncStateSerializer::need_monitor(ShardIdFull shard) {
|
||||
return opts_->need_monitor(shard);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class AsyncStateSerializer : public td::actor::Actor {
|
|||
bool saved_to_db_ = true;
|
||||
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
td::CancellationTokenSource cancellation_token_source_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
|
||||
|
@ -89,6 +90,8 @@ class AsyncStateSerializer : public td::actor::Actor {
|
|||
void fail_handler(td::Status reason);
|
||||
void fail_handler_cont();
|
||||
void success_handler();
|
||||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -27,7 +27,8 @@ namespace ton {
|
|||
|
||||
namespace validator {
|
||||
|
||||
void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<BlockCandidate> promise) {
|
||||
void ValidatorGroup::generate_block_candidate(
|
||||
td::uint32 round_id, td::Promise<validatorsession::ValidatorSession::GeneratedCandidate> promise) {
|
||||
if (round_id > last_known_round_id_) {
|
||||
last_known_round_id_ = round_id;
|
||||
}
|
||||
|
@ -37,14 +38,18 @@ void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<B
|
|||
}
|
||||
if (cached_collated_block_) {
|
||||
if (cached_collated_block_->result) {
|
||||
promise.set_result(cached_collated_block_->result.value().clone());
|
||||
promise.set_value({cached_collated_block_->result.value().clone(), true});
|
||||
} else {
|
||||
cached_collated_block_->promises.push_back(std::move(promise));
|
||||
cached_collated_block_->promises.push_back(promise.wrap([](BlockCandidate &&res) {
|
||||
return validatorsession::ValidatorSession::GeneratedCandidate{std::move(res), true};
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
cached_collated_block_ = std::make_shared<CachedCollatedBlock>();
|
||||
cached_collated_block_->promises.push_back(std::move(promise));
|
||||
cached_collated_block_->promises.push_back(promise.wrap([](BlockCandidate &&res) {
|
||||
return validatorsession::ValidatorSession::GeneratedCandidate{std::move(res), false};
|
||||
}));
|
||||
run_collate_query(
|
||||
shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_,
|
||||
Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_, manager_, td::Timestamp::in(10.0),
|
||||
|
@ -73,7 +78,7 @@ void ValidatorGroup::generated_block_candidate(std::shared_ptr<CachedCollatedBlo
|
|||
}
|
||||
|
||||
void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidate block,
|
||||
td::Promise<UnixTime> promise) {
|
||||
td::Promise<std::pair<UnixTime, bool>> promise) {
|
||||
if (round_id > last_known_round_id_) {
|
||||
last_known_round_id_ = round_id;
|
||||
}
|
||||
|
@ -88,7 +93,7 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
|
|||
CacheKey cache_key = block_to_cache_key(block);
|
||||
auto it = approved_candidates_cache_.find(cache_key);
|
||||
if (it != approved_candidates_cache_.end()) {
|
||||
promise.set_result(it->second);
|
||||
promise.set_value({it->second, true});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -113,7 +118,7 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
|
|||
ts);
|
||||
td::actor::send_closure(SelfId, &ValidatorGroup::add_available_block_candidate, block.pubkey.as_bits256(),
|
||||
block.id, block.collated_file_hash);
|
||||
promise.set_result(ts);
|
||||
promise.set_value({ts, false});
|
||||
},
|
||||
[&](CandidateReject reject) {
|
||||
promise.set_error(
|
||||
|
@ -247,15 +252,18 @@ std::unique_ptr<validatorsession::ValidatorSession::Callback> ValidatorGroup::ma
|
|||
void on_candidate(td::uint32 round, PublicKey source, validatorsession::ValidatorSessionRootHash root_hash,
|
||||
td::BufferSlice data, td::BufferSlice collated_data,
|
||||
td::Promise<validatorsession::ValidatorSession::CandidateDecision> promise) override {
|
||||
auto P = td::PromiseCreator::lambda([id = id_, promise = std::move(promise)](td::Result<td::uint32> R) mutable {
|
||||
if (R.is_ok()) {
|
||||
promise.set_value(validatorsession::ValidatorSession::CandidateDecision{R.move_as_ok()});
|
||||
} else {
|
||||
auto S = R.move_as_error();
|
||||
promise.set_value(
|
||||
validatorsession::ValidatorSession::CandidateDecision{S.message().c_str(), td::BufferSlice()});
|
||||
}
|
||||
});
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<std::pair<td::uint32, bool>> R) mutable {
|
||||
if (R.is_ok()) {
|
||||
validatorsession::ValidatorSession::CandidateDecision decision(R.ok().first);
|
||||
decision.set_is_cached(R.ok().second);
|
||||
promise.set_value(std::move(decision));
|
||||
} else {
|
||||
auto S = R.move_as_error();
|
||||
promise.set_value(
|
||||
validatorsession::ValidatorSession::CandidateDecision{S.message().c_str(), td::BufferSlice()});
|
||||
}
|
||||
});
|
||||
|
||||
BlockCandidate candidate{Ed25519_PublicKey{source.ed25519_value().raw()},
|
||||
BlockIdExt{0, 0, 0, root_hash, sha256_bits256(data.as_slice())},
|
||||
|
@ -264,7 +272,8 @@ std::unique_ptr<validatorsession::ValidatorSession::Callback> ValidatorGroup::ma
|
|||
td::actor::send_closure(id_, &ValidatorGroup::validate_block_candidate, round, std::move(candidate),
|
||||
std::move(P));
|
||||
}
|
||||
void on_generate_slot(td::uint32 round, td::Promise<BlockCandidate> promise) override {
|
||||
void on_generate_slot(td::uint32 round,
|
||||
td::Promise<validatorsession::ValidatorSession::GeneratedCandidate> promise) override {
|
||||
td::actor::send_closure(id_, &ValidatorGroup::generate_block_candidate, round, std::move(promise));
|
||||
}
|
||||
void on_block_committed(td::uint32 round, PublicKey source, validatorsession::ValidatorSessionRootHash root_hash,
|
||||
|
@ -339,6 +348,10 @@ void ValidatorGroup::create_session() {
|
|||
<< ".",
|
||||
allow_unsafe_self_blocks_resync_);
|
||||
}
|
||||
if (opts_->get_catchain_max_block_delay()) {
|
||||
td::actor::send_closure(session_, &validatorsession::ValidatorSession::set_catchain_max_block_delay,
|
||||
opts_->get_catchain_max_block_delay().value());
|
||||
}
|
||||
if (started_) {
|
||||
td::actor::send_closure(session_, &validatorsession::ValidatorSession::start);
|
||||
}
|
||||
|
@ -368,6 +381,22 @@ void ValidatorGroup::start(std::vector<BlockIdExt> prev, BlockIdExt min_masterch
|
|||
prev_block_ids_ = std::vector<BlockIdExt>{next_block_id};
|
||||
}
|
||||
postponed_accept_.clear();
|
||||
|
||||
validatorsession::NewValidatorGroupStats stats;
|
||||
stats.session_id = session_id_;
|
||||
stats.shard = shard_;
|
||||
stats.cc_seqno = validator_set_->get_catchain_seqno();
|
||||
stats.timestamp = td::Clocks::system();
|
||||
td::uint32 idx = 0;
|
||||
for (const auto& node : validator_set_->export_vector()) {
|
||||
PublicKeyHash id = ValidatorFullId{node.key}.compute_short_id();
|
||||
if (id == local_id_) {
|
||||
stats.self_idx = idx;
|
||||
}
|
||||
stats.nodes.push_back(validatorsession::NewValidatorGroupStats::Node{id, node.weight});
|
||||
++idx;
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::log_new_validator_group_stats, std::move(stats));
|
||||
}
|
||||
|
||||
void ValidatorGroup::destroy() {
|
||||
|
@ -381,6 +410,9 @@ void ValidatorGroup::destroy() {
|
|||
return;
|
||||
}
|
||||
auto stats = R.move_as_ok();
|
||||
if (stats.rounds.empty()) {
|
||||
return;
|
||||
}
|
||||
stats.cc_seqno = cc_seqno;
|
||||
td::actor::send_closure(manager, &ValidatorManager::log_validator_session_stats, block_id,
|
||||
std::move(stats));
|
||||
|
|
|
@ -34,8 +34,10 @@ class ValidatorManager;
|
|||
|
||||
class ValidatorGroup : public td::actor::Actor {
|
||||
public:
|
||||
void generate_block_candidate(td::uint32 round_id, td::Promise<BlockCandidate> promise);
|
||||
void validate_block_candidate(td::uint32 round_id, BlockCandidate block, td::Promise<td::uint32> promise);
|
||||
void generate_block_candidate(td::uint32 round_id,
|
||||
td::Promise<validatorsession::ValidatorSession::GeneratedCandidate> promise);
|
||||
void validate_block_candidate(td::uint32 round_id, BlockCandidate block,
|
||||
td::Promise<std::pair<UnixTime, bool>> promise);
|
||||
void accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block, RootHash root_hash,
|
||||
FileHash file_hash, std::vector<BlockSignature> signatures,
|
||||
std::vector<BlockSignature> approve_signatures,
|
||||
|
@ -67,7 +69,7 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
std::string db_root, td::actor::ActorId<ValidatorManager> validator_manager, bool create_session,
|
||||
bool allow_unsafe_self_blocks_resync)
|
||||
bool allow_unsafe_self_blocks_resync, td::Ref<ValidatorManagerOptions> opts)
|
||||
: shard_(shard)
|
||||
, local_id_(std::move(local_id))
|
||||
, session_id_(session_id)
|
||||
|
@ -80,7 +82,8 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
, db_root_(std::move(db_root))
|
||||
, manager_(validator_manager)
|
||||
, init_(create_session)
|
||||
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync) {
|
||||
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync)
|
||||
, opts_(std::move(opts)) {
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -121,6 +124,7 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
bool init_ = false;
|
||||
bool started_ = false;
|
||||
bool allow_unsafe_self_blocks_resync_;
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
td::uint32 last_known_round_id_ = 0;
|
||||
|
||||
struct CachedCollatedBlock {
|
||||
|
|
|
@ -129,6 +129,21 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
bool nonfinal_ls_queries_enabled() const override {
|
||||
return nonfinal_ls_queries_enabled_;
|
||||
}
|
||||
td::optional<td::uint64> get_celldb_cache_size() const override {
|
||||
return celldb_cache_size_;
|
||||
}
|
||||
bool get_celldb_direct_io() const override {
|
||||
return celldb_direct_io_;
|
||||
}
|
||||
bool get_celldb_preload_all() const override {
|
||||
return celldb_preload_all_;
|
||||
}
|
||||
td::optional<double> get_catchain_max_block_delay() const override {
|
||||
return catchain_max_block_delay_;
|
||||
}
|
||||
bool get_state_serializer_enabled() const override {
|
||||
return state_serializer_enabled_;
|
||||
}
|
||||
|
||||
void set_zero_block_id(BlockIdExt block_id) override {
|
||||
zero_block_id_ = block_id;
|
||||
|
@ -197,6 +212,21 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
void set_nonfinal_ls_queries_enabled(bool value) override {
|
||||
nonfinal_ls_queries_enabled_ = value;
|
||||
}
|
||||
void set_celldb_cache_size(td::uint64 value) override {
|
||||
celldb_cache_size_ = value;
|
||||
}
|
||||
void set_celldb_direct_io(bool value) override {
|
||||
celldb_direct_io_ = value;
|
||||
}
|
||||
void set_celldb_preload_all(bool value) override {
|
||||
celldb_preload_all_ = value;
|
||||
}
|
||||
void set_catchain_max_block_delay(double value) override {
|
||||
catchain_max_block_delay_ = value;
|
||||
}
|
||||
void set_state_serializer_enabled(bool value) override {
|
||||
state_serializer_enabled_ = value;
|
||||
}
|
||||
|
||||
ValidatorManagerOptionsImpl *make_copy() const override {
|
||||
return new ValidatorManagerOptionsImpl(*this);
|
||||
|
@ -244,6 +274,11 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
double archive_preload_period_ = 0.0;
|
||||
bool disable_rocksdb_stats_;
|
||||
bool nonfinal_ls_queries_enabled_ = false;
|
||||
td::optional<td::uint64> celldb_cache_size_;
|
||||
bool celldb_direct_io_ = false;
|
||||
bool celldb_preload_all_ = false;
|
||||
td::optional<double> catchain_max_block_delay_;
|
||||
bool state_serializer_enabled_ = true;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -86,6 +86,11 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
virtual double get_archive_preload_period() const = 0;
|
||||
virtual bool get_disable_rocksdb_stats() const = 0;
|
||||
virtual bool nonfinal_ls_queries_enabled() const = 0;
|
||||
virtual td::optional<td::uint64> get_celldb_cache_size() const = 0;
|
||||
virtual bool get_celldb_direct_io() const = 0;
|
||||
virtual bool get_celldb_preload_all() const = 0;
|
||||
virtual td::optional<double> get_catchain_max_block_delay() const = 0;
|
||||
virtual bool get_state_serializer_enabled() const = 0;
|
||||
|
||||
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
|
||||
virtual void set_init_block_id(BlockIdExt block_id) = 0;
|
||||
|
@ -110,13 +115,18 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
virtual void set_archive_preload_period(double value) = 0;
|
||||
virtual void set_disable_rocksdb_stats(bool value) = 0;
|
||||
virtual void set_nonfinal_ls_queries_enabled(bool value) = 0;
|
||||
virtual void set_celldb_cache_size(td::uint64 value) = 0;
|
||||
virtual void set_celldb_direct_io(bool value) = 0;
|
||||
virtual void set_celldb_preload_all(bool value) = 0;
|
||||
virtual void set_catchain_max_block_delay(double value) = 0;
|
||||
virtual void set_state_serializer_enabled(bool value) = 0;
|
||||
|
||||
static td::Ref<ValidatorManagerOptions> create(
|
||||
BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard = [](ShardIdFull, CatchainSeqno,
|
||||
ShardCheckMode) { return true; },
|
||||
bool allow_blockchain_init = false, double sync_blocks_before = 86400, double block_ttl = 86400 * 7,
|
||||
double state_ttl = 3600, double archive_ttl = 86400 * 365, double key_proof_ttl = 86400 * 3650,
|
||||
bool allow_blockchain_init = false, double sync_blocks_before = 3600, double block_ttl = 86400,
|
||||
double state_ttl = 3600, double archive_ttl = 86400 * 7, double key_proof_ttl = 86400 * 3650,
|
||||
double max_mempool_num = 999999,
|
||||
bool initial_sync_disabled = false);
|
||||
};
|
||||
|
@ -134,7 +144,9 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
virtual void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
|
||||
virtual void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
|
||||
virtual void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) = 0;
|
||||
virtual void send_broadcast(BlockBroadcast broadcast) = 0;
|
||||
virtual void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||
td::BufferSlice data) = 0;
|
||||
virtual void send_broadcast(BlockBroadcast broadcast, bool custom_overlays_only = false) = 0;
|
||||
virtual void download_block(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) = 0;
|
||||
virtual void download_zero_state(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
|
@ -202,6 +214,7 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
virtual void check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) = 0;
|
||||
virtual void new_ihr_message(td::BufferSlice data) = 0;
|
||||
virtual void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) = 0;
|
||||
virtual void new_block_candidate(BlockIdExt block_id, td::BufferSlice data) = 0;
|
||||
|
||||
virtual void add_ext_server_id(adnl::AdnlNodeIdShort id) = 0;
|
||||
virtual void add_ext_server_port(td::uint16 port) = 0;
|
||||
|
@ -238,6 +251,7 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
virtual void add_perf_timer_stat(std::string name, double duration) = 0;
|
||||
virtual void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint32> promise) = 0;
|
||||
|
||||
virtual void update_options(td::Ref<ValidatorManagerOptions> opts) = 0;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
Loading…
Reference in a new issue