1
0
Fork 0
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:
EmelyanenkoK 2024-06-09 20:42:35 +03:00 committed by GitHub
commit 5c392e0f2d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 2313 additions and 706 deletions

View 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

View file

@ -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
View 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

View file

@ -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

View file

@ -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/

View file

@ -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/

View file

@ -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/

View file

@ -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"
];
}

View file

@ -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 = [

View file

@ -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"
];
}

View file

@ -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;

View file

@ -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 = [

View file

@ -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
'';
}

View file

@ -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
'';
}

View file

@ -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)

View file

@ -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 {

View file

@ -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 {

View file

@ -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}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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()) {

View file

@ -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.

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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)) {
}

View file

@ -87,4 +87,8 @@ void PerfWarningTimer::reset() {
start_at_ = 0;
}
double PerfWarningTimer::elapsed() const {
return Time::now() - start_at_;
}
} // namespace td

View file

@ -53,6 +53,7 @@ class PerfWarningTimer {
PerfWarningTimer &operator=(PerfWarningTimer &&) = delete;
~PerfWarningTimer();
void reset();
double elapsed() const;
private:
string name_;

View file

@ -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 {

View file

@ -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.

View file

@ -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.

View file

@ -344,6 +344,10 @@ struct BlockSignature {
struct ReceivedBlock {
BlockIdExt id;
td::BufferSlice data;
ReceivedBlock clone() const {
return ReceivedBlock{id, data.clone()};
}
};
struct BlockBroadcast {

View file

@ -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;

View file

@ -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();

View file

@ -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();
}

View file

@ -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_;
};

View file

@ -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) {

View file

@ -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();

View file

@ -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) {

View file

@ -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"

View file

@ -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

View file

@ -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(

View file

@ -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,

View file

@ -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) {

View file

@ -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

View file

@ -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();

View file

@ -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();

View file

@ -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

View file

@ -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
View 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
View 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

View file

@ -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;

View file

@ -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

View file

@ -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_;

View file

@ -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));

View file

@ -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,

View file

@ -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_,

View file

@ -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_;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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 &params = 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

View file

@ -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;

View file

@ -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

View file

@ -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();
}

View file

@ -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";

View file

@ -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()));

View file

@ -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,

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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));
}

View file

@ -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_;

View file

@ -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_;

View file

@ -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

View file

@ -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_;

View file

@ -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);
}

View file

@ -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

View file

@ -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));

View file

@ -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 {

View file

@ -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

View file

@ -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