1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 19:22:37 +00:00

Merge pull request #877 from ton-blockchain/testnet

Merge developer branch
This commit is contained in:
EmelyanenkoK 2024-01-25 13:54:08 +03:00 committed by GitHub
commit 8a9ff33992
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 211 additions and 85 deletions

View file

@ -24,7 +24,7 @@ jobs:
run: | run: |
cp assembly/nix/build-linux-x86-64-nix.sh . cp assembly/nix/build-linux-x86-64-nix.sh .
chmod +x build-linux-x86-64-nix.sh chmod +x build-linux-x86-64-nix.sh
./build-linux-x86-64-nix.sh ./build-linux-x86-64-nix.sh -t
- name: Simple binaries test - name: Simple binaries test
run: | run: |
@ -38,4 +38,4 @@ jobs:
uses: actions/upload-artifact@master uses: actions/upload-artifact@master
with: with:
name: ton-x86_64-linux-binaries name: ton-x86_64-linux-binaries
path: artifacts path: artifacts

View file

@ -20,7 +20,7 @@ jobs:
run: | run: |
cp assembly/nix/build-macos-nix.sh . cp assembly/nix/build-macos-nix.sh .
chmod +x build-macos-nix.sh chmod +x build-macos-nix.sh
./build-macos-nix.sh ./build-macos-nix.sh -t
- name: Simple binaries test - name: Simple binaries test
run: | run: |
@ -34,4 +34,4 @@ jobs:
uses: actions/upload-artifact@master uses: actions/upload-artifact@master
with: with:
name: ton-x86_64-macos-binaries name: ton-x86_64-macos-binaries
path: artifacts path: artifacts

View file

@ -1,14 +1,20 @@
## 2024.01 Update ## 2024.01 Update
1. Fixes in how gas in transactions on special accounts is accounted in block limit. Previously, gas was counted as usual, so to conduct elections that costs >30m gas block limit in masterchain was set to 37m gas. To lower the limit for safety reasons it is proposed to not count gas on special accounts. Besides `gas_max` is set to `special_gas_limit` for all types of transactions on special accounts. New behavior is activated through setting `gas_prices_v3` in `ConfigParam 20;`. 1. Fixes in how gas in transactions on special accounts is accounted in block limit. Previously, gas was counted as usual, so to conduct elections that costs >30m gas block limit in masterchain was set to 37m gas. To lower the limit for safety reasons it is proposed to caunt gas on special accounts separately. Besides `gas_max` is set to `special_gas_limit` for all types of transactions on special accounts. New behavior is activated through setting `version >= 5` in `ConfigParam 8;`.
* Besides update of config temporally increases gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` to `special_gas_limit`, see [details](https://t.me/tonstatus/88). * Besides update of config temporally increases gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` to `special_gas_limit`, see [details](https://t.me/tonstatus/88).
2. Improvements in LS behavior 2. Improvements in LS behavior
* Improved detection of the state with all shards applied to decrease rate of `Block is not applied` error * Improved detection of the state with all shards applied to decrease rate of `Block is not applied` error
* Better error logs: `block not in db` and `block is not applied` separation * Better error logs: `block not in db` and `block is not applied` separation
* Fix error in proof generation for blocks after merge * Fix error in proof generation for blocks after merge
* Fix most of `block is not applied` issues related to sending too recent block in Proofs
* LS now check external messages till `accept_message` (`set_gas`).
3. Improvements in DHT work and storage, CellDb, config.json ammendment, peer misbehavior detection, validator session stats collection, emulator. 3. Improvements in DHT work and storage, CellDb, config.json ammendment, peer misbehavior detection, validator session stats collection, emulator.
4. Change in CTOS and XLOAD behavior activated through setting `version >= 5` in `ConfigParam 8;`:
* Loading "nested libraries" (i.e. a library cell that points to another library cell) throws an exception.
* Loading a library consumes gas for cell load only once (for the library cell), not twice (both for the library cell and the cell in the library).
* `XLOAD` now works differently. When it takes a library cell, it returns the cell that it points to. This allows loading "nested libraries", if needed.
Besides the work of the core team, this update is based on the efforts of @XaBbl4 (peer misbehavior detection). Besides the work of the Core team, this update is based on the efforts of @XaBbl4 (peer misbehavior detection) and @akifoq (CTOS behavior and gas limit scheme for special accounts).
## 2023.12 Update ## 2023.12 Update

View file

@ -31,7 +31,7 @@ pipeline {
sh ''' sh '''
cp assembly/nix/build-linux-x86-64-nix.sh . cp assembly/nix/build-linux-x86-64-nix.sh .
chmod +x build-linux-x86-64-nix.sh chmod +x build-linux-x86-64-nix.sh
./build-linux-x86-64-nix.sh ./build-linux-x86-64-nix.sh -t
''' '''
sh ''' sh '''
cd artifacts cd artifacts
@ -69,7 +69,7 @@ pipeline {
sh ''' sh '''
cp assembly/nix/build-linux-arm64-nix.sh . cp assembly/nix/build-linux-arm64-nix.sh .
chmod +x build-linux-arm64-nix.sh chmod +x build-linux-arm64-nix.sh
./build-linux-arm64-nix.sh ./build-linux-arm64-nix.sh -t
''' '''
sh ''' sh '''
cd artifacts cd artifacts
@ -107,7 +107,7 @@ pipeline {
sh ''' sh '''
cp assembly/nix/build-macos-nix.sh . cp assembly/nix/build-macos-nix.sh .
chmod +x build-macos-nix.sh chmod +x build-macos-nix.sh
./build-macos-nix.sh ./build-macos-nix.sh -t
''' '''
sh ''' sh '''
cd artifacts cd artifacts
@ -145,7 +145,7 @@ pipeline {
sh ''' sh '''
cp assembly/nix/build-macos-nix.sh . cp assembly/nix/build-macos-nix.sh .
chmod +x build-macos-nix.sh chmod +x build-macos-nix.sh
./build-macos-nix.sh ./build-macos-nix.sh -t
''' '''
sh ''' sh '''
cd artifacts cd artifacts
@ -233,4 +233,4 @@ pipeline {
} }
} }
} }
} }

View file

@ -3,12 +3,27 @@
nix-build --version nix-build --version
test $? -eq 0 || { echo "Nix is not installed!"; exit 1; } test $? -eq 0 || { echo "Nix is not installed!"; exit 1; }
with_tests=false
while getopts 't' flag; do
case "${flag}" in
t) with_tests=true ;;
*) break
;;
esac
done
cp assembly/nix/linux-arm64* . cp assembly/nix/linux-arm64* .
cp assembly/nix/microhttpd.nix . cp assembly/nix/microhttpd.nix .
cp assembly/nix/openssl.nix . cp assembly/nix/openssl.nix .
export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz
nix-build linux-arm64-static.nix if [ "$with_tests" = true ]; then
nix-build linux-arm64-static.nix --arg testing true
else
nix-build linux-arm64-static.nix
fi
mkdir artifacts mkdir artifacts
cp ./result/bin/* artifacts/ cp ./result/bin/* artifacts/
chmod +x artifacts/* chmod +x artifacts/*
@ -17,4 +32,4 @@ nix-build linux-arm64-tonlib.nix
cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
cp ./result/lib/libemulator.so artifacts/ cp ./result/lib/libemulator.so artifacts/
cp -r crypto/fift/lib artifacts/ cp -r crypto/fift/lib artifacts/
cp -r crypto/smartcont artifacts/ cp -r crypto/smartcont artifacts/

View file

@ -3,12 +3,28 @@
nix-build --version nix-build --version
test $? -eq 0 || { echo "Nix is not installed!"; exit 1; } test $? -eq 0 || { echo "Nix is not installed!"; exit 1; }
with_tests=false
while getopts 't' flag; do
case "${flag}" in
t) with_tests=true ;;
*) break
;;
esac
done
cp assembly/nix/linux-x86-64* . cp assembly/nix/linux-x86-64* .
cp assembly/nix/microhttpd.nix . cp assembly/nix/microhttpd.nix .
cp assembly/nix/openssl.nix . cp assembly/nix/openssl.nix .
export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz
nix-build linux-x86-64-static.nix if [ "$with_tests" = true ]; then
nix-build linux-x86-64-static.nix --arg testing true
else
nix-build linux-x86-64-static.nix
fi
mkdir artifacts mkdir artifacts
cp ./result/bin/* artifacts/ cp ./result/bin/* artifacts/
chmod +x artifacts/* chmod +x artifacts/*
@ -17,4 +33,4 @@ nix-build linux-x86-64-tonlib.nix
cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
cp ./result/lib/libemulator.so artifacts/ cp ./result/lib/libemulator.so artifacts/
cp -r crypto/fift/lib artifacts/ cp -r crypto/fift/lib artifacts/
cp -r crypto/smartcont artifacts/ cp -r crypto/smartcont artifacts/

View file

@ -3,9 +3,25 @@
nix-build --version nix-build --version
test $? -eq 0 || { echo "Nix is not installed!"; exit 1; } test $? -eq 0 || { echo "Nix is not installed!"; exit 1; }
with_tests=false
while getopts 't' flag; do
case "${flag}" in
t) with_tests=true ;;
*) break
;;
esac
done
cp assembly/nix/macos-* . cp assembly/nix/macos-* .
export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz export NIX_PATH=nixpkgs=https://github.com/nixOS/nixpkgs/archive/23.05.tar.gz
nix-build macos-static.nix
if [ "$with_tests" = true ]; then
nix-build macos-static.nix --arg testing true
else
nix-build macos-static.nix
fi
mkdir artifacts mkdir artifacts
cp ./result-bin/bin/* artifacts/ cp ./result-bin/bin/* artifacts/
chmod +x artifacts/* chmod +x artifacts/*
@ -14,4 +30,4 @@ nix-build macos-tonlib.nix
cp ./result/lib/libtonlibjson.dylib artifacts/ cp ./result/lib/libtonlibjson.dylib artifacts/
cp ./result/lib/libemulator.dylib artifacts/ cp ./result/lib/libemulator.dylib artifacts/
cp -r crypto/fift/lib artifacts/ cp -r crypto/fift/lib artifacts/
cp -r crypto/smartcont artifacts/ cp -r crypto/smartcont artifacts/

View file

@ -3,6 +3,7 @@
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; } { pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
, lib ? pkgs.lib , lib ? pkgs.lib
, stdenv ? pkgs.stdenv , stdenv ? pkgs.stdenv
, testing ? false
}: }:
let let
microhttpdmy = (import ./microhttpd.nix) {}; microhttpdmy = (import ./microhttpd.nix) {};
@ -25,7 +26,7 @@ stdenv.mkDerivation {
]; ];
makeStatic = true; makeStatic = true;
doCheck = true; doCheck = testing;
cmakeFlags = [ cmakeFlags = [
"-DTON_USE_ABSEIL=OFF" "-DTON_USE_ABSEIL=OFF"

View file

@ -3,6 +3,7 @@
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; } { pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
, lib ? pkgs.lib , lib ? pkgs.lib
, stdenv ? pkgs.stdenv , stdenv ? pkgs.stdenv
, testing ? false
}: }:
let let
microhttpdmy = (import ./microhttpd.nix) {}; microhttpdmy = (import ./microhttpd.nix) {};
@ -25,7 +26,7 @@ stdenv.mkDerivation {
]; ];
makeStatic = true; makeStatic = true;
doCheck = true; doCheck = testing;
cmakeFlags = [ cmakeFlags = [
"-DTON_USE_ABSEIL=OFF" "-DTON_USE_ABSEIL=OFF"

View file

@ -3,6 +3,7 @@
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; } { pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
, lib ? pkgs.lib , lib ? pkgs.lib
, stdenv ? pkgs.stdenv , stdenv ? pkgs.stdenv
, testing ? false
}: }:
pkgs.llvmPackages_14.stdenv.mkDerivation { pkgs.llvmPackages_14.stdenv.mkDerivation {
@ -29,7 +30,7 @@ pkgs.llvmPackages_14.stdenv.mkDerivation {
dontAddStaticConfigureFlags = true; dontAddStaticConfigureFlags = true;
makeStatic = true; makeStatic = true;
doCheck = true; doCheck = testing;
configureFlags = []; configureFlags = [];
@ -62,4 +63,4 @@ pkgs.llvmPackages_14.stdenv.mkDerivation {
done done
''; '';
outputs = [ "bin" "out" ]; outputs = [ "bin" "out" ];
} }

View file

@ -19,6 +19,6 @@
namespace ton { namespace ton {
// See doc/GlobalVersions.md // See doc/GlobalVersions.md
const int SUPPORTED_VERSION = 4; const int SUPPORTED_VERSION = 5;
} }

View file

@ -696,11 +696,6 @@ gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas
block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64 block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
= GasLimitsPrices; = GasLimitsPrices;
// same fields as gas_prices_ext; behavior differs
gas_prices_v3#df gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas_credit:uint64
block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
= GasLimitsPrices;
gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices
= GasLimitsPrices; = GasLimitsPrices;

View file

@ -654,13 +654,9 @@ td::Result<GasLimitsPrices> Config::do_get_gas_limits_prices(td::Ref<vm::Cell> c
res.delete_due_limit = r.delete_due_limit; res.delete_due_limit = r.delete_due_limit;
}; };
block::gen::GasLimitsPrices::Record_gas_prices_ext rec; block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
block::gen::GasLimitsPrices::Record_gas_prices_v3 rec_v3;
vm::CellSlice cs0 = cs; vm::CellSlice cs0 = cs;
if (tlb::unpack(cs, rec)) { if (tlb::unpack(cs, rec)) {
f(rec, rec.special_gas_limit); f(rec, rec.special_gas_limit);
} else if (tlb::unpack(cs = cs0, rec_v3)) {
f(rec_v3, rec_v3.special_gas_limit);
res.special_full_limit = true;
} else { } else {
block::gen::GasLimitsPrices::Record_gas_prices rec0; block::gen::GasLimitsPrices::Record_gas_prices rec0;
if (tlb::unpack(cs = cs0, rec0)) { if (tlb::unpack(cs = cs0, rec0)) {

View file

@ -349,7 +349,6 @@ struct GasLimitsPrices {
td::uint64 block_gas_limit{0}; td::uint64 block_gas_limit{0};
td::uint64 freeze_due_limit{0}; td::uint64 freeze_due_limit{0};
td::uint64 delete_due_limit{0}; td::uint64 delete_due_limit{0};
bool special_full_limit{false};
td::RefInt256 compute_gas_price(td::uint64 gas_used) const; td::RefInt256 compute_gas_price(td::uint64 gas_used) const;
}; };

View file

@ -1039,12 +1039,8 @@ bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, t
delete_due_limit = td::make_refint(r.delete_due_limit); delete_due_limit = td::make_refint(r.delete_due_limit);
}; };
block::gen::GasLimitsPrices::Record_gas_prices_ext rec; block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
block::gen::GasLimitsPrices::Record_gas_prices_v3 rec_v3;
if (tlb::csr_unpack(cs, rec)) { if (tlb::csr_unpack(cs, rec)) {
f(rec, rec.special_gas_limit); f(rec, rec.special_gas_limit);
} else if (tlb::csr_unpack(cs, rec_v3)) {
f(rec_v3, rec_v3.special_gas_limit);
special_gas_full = true;
} else { } else {
block::gen::GasLimitsPrices::Record_gas_prices rec0; block::gen::GasLimitsPrices::Record_gas_prices rec0;
if (tlb::csr_unpack(std::move(cs), rec0)) { if (tlb::csr_unpack(std::move(cs), rec0)) {
@ -1153,8 +1149,8 @@ namespace transaction {
* not enough to clean up old queires, thus locking funds inside. * not enough to clean up old queires, thus locking funds inside.
* See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened. * See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened.
* Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu * Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu
* It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-16). * It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-29).
* It is activated by setting gas_prices_v3 in ConfigParam 20 (config_mc_gas_prices). * It is activated by setting global version to 5 in ConfigParam 8.
* This config change also activates new behavior for special accounts in masterchain. * This config change also activates new behavior for special accounts in masterchain.
* *
* @param cfg The compute phase configuration. * @param cfg The compute phase configuration.
@ -1164,10 +1160,10 @@ namespace transaction {
* @returns True if gas_limit override is required, false otherwise * @returns True if gas_limit override is required, false otherwise
*/ */
static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) { static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) {
if (!cfg.mc_gas_prices.special_full_limit) { if (!cfg.special_gas_full) {
return false; return false;
} }
ton::UnixTime until = 1708041600; // 2024-02-16 00:00:00 UTC ton::UnixTime until = 1709164800; // 2024-02-29 00:00:00 UTC
ton::WorkchainId wc = 0; ton::WorkchainId wc = 0;
const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD"; const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD";
return now < until && account.workchain == wc && account.addr.to_hex() == addr_hex; return now < until && account.workchain == wc && account.addr.to_hex() == addr_hex;
@ -1563,6 +1559,7 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
vm.set_global_version(cfg.global_version); vm.set_global_version(cfg.global_version);
vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
vm.set_chksig_always_succeed(cfg.ignore_chksig); vm.set_chksig_always_succeed(cfg.ignore_chksig);
vm.set_stop_on_accept_message(cfg.stop_on_accept_message);
// vm.incr_stack_trace(1); // enable stack dump after each step // vm.incr_stack_trace(1); // enable stack dump after each step
LOG(DEBUG) << "starting VM"; LOG(DEBUG) << "starting VM";
@ -3533,6 +3530,7 @@ td::Status FetchConfigParams::fetch_config_params(
TRY_RESULT_PREFIX(mc_gas_prices, config.get_gas_limits_prices(true), TRY_RESULT_PREFIX(mc_gas_prices, config.get_gas_limits_prices(true),
"cannot unpack masterchain gas prices and limits: "); "cannot unpack masterchain gas prices and limits: ");
compute_phase_cfg->mc_gas_prices = std::move(mc_gas_prices); compute_phase_cfg->mc_gas_prices = std::move(mc_gas_prices);
compute_phase_cfg->special_gas_full = config.get_global_version() >= 5;
storage_phase_cfg->enable_due_payment = config.get_global_version() >= 4; storage_phase_cfg->enable_due_payment = config.get_global_version() >= 4;
compute_phase_cfg->block_rand_seed = *rand_seed; compute_phase_cfg->block_rand_seed = *rand_seed;
compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth; compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth;

View file

@ -120,6 +120,7 @@ struct ComputePhaseConfig {
std::unique_ptr<vm::Dictionary> suspended_addresses; std::unique_ptr<vm::Dictionary> suspended_addresses;
SizeLimitsConfig size_limits; SizeLimitsConfig size_limits;
int vm_log_verbosity = 0; int vm_log_verbosity = 0;
bool stop_on_accept_message = false;
ComputePhaseConfig() : gas_price(0), gas_limit(0), special_gas_limit(0), gas_credit(0) { ComputePhaseConfig() : gas_price(0), gas_limit(0), special_gas_limit(0), gas_credit(0) {
compute_threshold(); compute_threshold();

View file

@ -892,6 +892,40 @@ int exec_load_special_cell(VmState* st, bool quiet) {
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
VM_LOG(st) << "execute XLOAD" << (quiet ? "Q" : ""); VM_LOG(st) << "execute XLOAD" << (quiet ? "Q" : "");
auto cell = stack.pop_cell(); auto cell = stack.pop_cell();
if (st->get_global_version() >= 5) {
st->register_cell_load(cell->get_hash());
auto r_loaded_cell = cell->load_cell();
if (r_loaded_cell.is_error()) {
if (quiet) {
stack.push_bool(false);
return 0;
} else {
throw VmError{Excno::cell_und, "failed to load cell"};
}
}
auto loaded_cell = r_loaded_cell.move_as_ok();
if (loaded_cell.data_cell->is_special()) {
if (loaded_cell.data_cell->special_type() != CellTraits::SpecialType::Library) {
if (quiet) {
stack.push_bool(false);
return 0;
} else {
throw VmError{Excno::cell_und, "unexpected special cell"};
}
}
CellSlice cs(std::move(loaded_cell));
DCHECK(cs.size() == Cell::hash_bits + 8);
cell = st->load_library(cs.data_bits() + 8);
if (cell.is_null()) {
if (quiet) {
stack.push_bool(false);
return 0;
} else {
throw VmError{Excno::cell_und, "failed to load library cell"};
}
}
}
}
stack.push_cell(cell); stack.push_cell(cell);
if (quiet) { if (quiet) {
stack.push_bool(true); stack.push_bool(true);

View file

@ -1056,9 +1056,10 @@ std::ostream& operator<<(std::ostream& os, Ref<CellSlice> cs_ref) {
// If can_be_special is not null, then it is allowed to load special cell // If can_be_special is not null, then it is allowed to load special cell
// Flag whether loaded cell is actually special will be stored into can_be_special // Flag whether loaded cell is actually special will be stored into can_be_special
VirtualCell::LoadedCell load_cell_slice_impl(Ref<Cell> cell, bool* can_be_special) { VirtualCell::LoadedCell load_cell_slice_impl(Ref<Cell> cell, bool* can_be_special) {
auto* vm_state_interface = VmStateInterface::get();
bool library_loaded = false;
while (true) { while (true) {
auto* vm_state_interface = VmStateInterface::get(); if (vm_state_interface && !library_loaded) {
if (vm_state_interface) {
vm_state_interface->register_cell_load(cell->get_hash()); vm_state_interface->register_cell_load(cell->get_hash());
} }
auto r_loaded_cell = cell->load_cell(); auto r_loaded_cell = cell->load_cell();
@ -1077,6 +1078,12 @@ VirtualCell::LoadedCell load_cell_slice_impl(Ref<Cell> cell, bool* can_be_specia
} else if (loaded_cell.data_cell->is_special()) { } else if (loaded_cell.data_cell->is_special()) {
if (loaded_cell.data_cell->special_type() == DataCell::SpecialType::Library) { if (loaded_cell.data_cell->special_type() == DataCell::SpecialType::Library) {
if (vm_state_interface) { if (vm_state_interface) {
if (vm_state_interface->get_global_version() >= 5) {
if (library_loaded) {
throw VmError{Excno::cell_und, "failed to load library cell: recursive library cells are not allowed"};
}
library_loaded = true;
}
CellSlice cs(std::move(loaded_cell)); CellSlice cs(std::move(loaded_cell));
DCHECK(cs.size() == Cell::hash_bits + 8); DCHECK(cs.size() == Cell::hash_bits + 8);
auto library_cell = vm_state_interface->load_library(cs.data_bits() + 8); auto library_cell = vm_state_interface->load_library(cs.data_bits() + 8);

View file

@ -67,6 +67,10 @@ int exec_set_gas_generic(VmState* st, long long new_gas_limit) {
throw VmNoGas{}; throw VmNoGas{};
} }
st->change_gas_limit(new_gas_limit); st->change_gas_limit(new_gas_limit);
if (st->get_stop_on_accept_message()) {
VM_LOG(st) << "External message is accepted, stopping TVM";
return st->jump(td::Ref<QuitCont>{true, 0});
}
return 0; return 0;
} }

View file

@ -98,6 +98,7 @@ class VmState final : public VmStateInterface {
td::HashSet<CellHash> loaded_cells; td::HashSet<CellHash> loaded_cells;
int stack_trace{0}, debug_off{0}; int stack_trace{0}, debug_off{0};
bool chksig_always_succeed{false}; bool chksig_always_succeed{false};
bool stop_on_accept_message{false};
td::optional<td::Bits256> missing_library; td::optional<td::Bits256> missing_library;
td::uint16 max_data_depth = 512; // Default value td::uint16 max_data_depth = 512; // Default value
int global_version{0}; int global_version{0};
@ -339,7 +340,7 @@ class VmState final : public VmStateInterface {
void preclear_cr(const ControlRegs& save) { void preclear_cr(const ControlRegs& save) {
cr &= save; cr &= save;
} }
int get_global_version() const { int get_global_version() const override {
return global_version; return global_version;
} }
void set_global_version(int version) { void set_global_version(int version) {
@ -381,6 +382,12 @@ class VmState final : public VmStateInterface {
bool get_chksig_always_succeed() const { bool get_chksig_always_succeed() const {
return chksig_always_succeed; return chksig_always_succeed;
} }
void set_stop_on_accept_message(bool flag) {
stop_on_accept_message = flag;
}
bool get_stop_on_accept_message() const {
return stop_on_accept_message;
}
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const { Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp()); return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
} }

View file

@ -19,6 +19,7 @@
#pragma once #pragma once
#include "common/refcnt.hpp" #include "common/refcnt.hpp"
#include "vm/cells.h" #include "vm/cells.h"
#include "common/global-version.h"
#include "td/utils/Context.h" #include "td/utils/Context.h"
@ -38,6 +39,9 @@ class VmStateInterface : public td::Context<VmStateInterface> {
virtual bool register_op(int op_units = 1) { virtual bool register_op(int op_units = 1) {
return true; return true;
}; };
virtual int get_global_version() const {
return ton::SUPPORTED_VERSION;
}
}; };
} // namespace vm } // namespace vm

View file

@ -36,4 +36,21 @@ intermediate value before division (e.g. `(xy+w)/z`).
* Flag +16 in actions "Send message", "Reserve", "Change library" causes bounce if action fails. * Flag +16 in actions "Send message", "Reserve", "Change library" causes bounce if action fails.
### Storage phase ### Storage phase
* Unpaid storage fee is now saved to `due_payment` * Unpaid storage fee is now saved to `due_payment`
## Version 5
### Gas limits
Version 5 enables higher gas limits for special contracts.
* Gas limit for all transactions on special contracts is set to `special_gas_limit` from `ConfigParam 20` (which is 35M at the moment of writing).
Previously only ticktock transactions had this limit, while ordinary transactions had a default limit of `gas_limit` gas (1M).
* Gas usage of special contracts is not taken into account when checking block limits. This allows keeping masterchain block limits low
while having high gas limits for elector.
* Gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` is increased to `special_gas_limit * 2` until 2024-02-29.
See [this post](https://t.me/tonstatus/88) for details.
### Loading libraries
* Loading "nested libraries" (i.e. a library cell that points to another library cell) throws an exception.
* Loading a library consumes gas for cell load only once (for the library cell), not twice (both for the library cell and the cell in the library).
* `XLOAD` now works differently. When it takes a library cell, it returns the cell that it points to. This allows loading "nested libraries", if needed.

View file

@ -1,11 +1,17 @@
## 2024.01 Update ## 2024.01 Update
1. Fixes in how gas in transactions on special accounts is accounted in block limit. Previously, gas was counted as usual, so to conduct elections that costs >30m gas block limit in masterchain was set to 37m gas. To lower the limit for safety reasons it is proposed to not count gas on special accounts. Besides `gas_max` is set to `special_gas_limit` for all types of transactions on special accounts. New behavior is activated through setting `gas_prices_v3` in `ConfigParam 20;`. 1. Fixes in how gas in transactions on special accounts is accounted in block limit. Previously, gas was counted as usual, so to conduct elections that costs >30m gas block limit in masterchain was set to 37m gas. To lower the limit for safety reasons it is proposed to caunt gas on special accounts separately. Besides `gas_max` is set to `special_gas_limit` for all types of transactions on special accounts. New behavior is activated through setting `version >= 5` in `ConfigParam 8;`.
* Besides update of config temporally increases gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` to `special_gas_limit`, see [details](https://t.me/tonstatus/88). * Besides update of config temporally increases gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` to `special_gas_limit`, see [details](https://t.me/tonstatus/88).
2. Improvements in LS behavior 2. Improvements in LS behavior
* Improved detection of the state with all shards applied to decrease rate of `Block is not applied` error * Improved detection of the state with all shards applied to decrease rate of `Block is not applied` error
* Better error logs: `block not in db` and `block is not applied` separation * Better error logs: `block not in db` and `block is not applied` separation
* Fix error in proof generation for blocks after merge * Fix error in proof generation for blocks after merge
* Fix most of `block is not applied` issues related to sending too recent block in Proofs
* LS now check external messages till `accept_message` (`set_gas`).
3. Improvements in DHT work and storage, CellDb, config.json ammendment, peer misbehavior detection, validator session stats collection, emulator. 3. Improvements in DHT work and storage, CellDb, config.json ammendment, peer misbehavior detection, validator session stats collection, emulator.
4. Change in CTOS and XLOAD behavior activated through setting `version >= 5` in `ConfigParam 8;`:
* Loading "nested libraries" (i.e. a library cell that points to another library cell) throws an exception.
* Loading a library consumes gas for cell load only once (for the library cell), not twice (both for the library cell and the cell in the library).
* `XLOAD` now works differently. When it takes a library cell, it returns the cell that it points to. This allows loading "nested libraries", if needed.
Besides the work of the core team, this update is based on the efforts of @XaBbl4 (peer misbehavior detection). Besides the work of the Core team, this update is based on the efforts of @XaBbl4 (peer misbehavior detection) and @akifoq (CTOS behavior and gas limit scheme for special accounts).

View file

@ -34,6 +34,7 @@
#include "validator-session/validator-session-description.h" #include "validator-session/validator-session-description.h"
#include "validator-session/validator-session-state.h" #include "validator-session/validator-session-state.h"
#include "validator-session/validator-session-description.hpp"
#include <limits> #include <limits>
#include <memory> #include <memory>
@ -48,17 +49,13 @@ class Description : public ton::validatorsession::ValidatorSessionDescription {
return 0; return 0;
} }
void *alloc(size_t size, size_t align, bool temp) override { void *alloc(size_t size, size_t align, bool temp) override {
size = (size + 15) / 16 * 16; return (temp ? mem_temp_ : mem_perm_).alloc(size, align);
td::uint32 idx = temp ? 1 : 0;
auto s = pdata_cur_[idx].fetch_add(size);
CHECK(s + size <= pdata_size_[idx]);
return static_cast<void *>(pdata_[idx] + s);
} }
bool is_persistent(const void *ptr) const override { bool is_persistent(const void *ptr) const override {
return ptr == nullptr || (ptr >= pdata_[0] && ptr < pdata_[0] + pdata_size_[0]); return mem_perm_.contains(ptr);
} }
void clear_temp_memory() override { void clear_temp_memory() override {
pdata_cur_[1] = 0; mem_temp_.clear();
} }
ton::PublicKeyHash get_source_id(td::uint32 idx) const override { ton::PublicKeyHash get_source_id(td::uint32 idx) const override {
@ -189,21 +186,8 @@ class Description : public ton::validatorsession::ValidatorSessionDescription {
return opts_; return opts_;
} }
~Description() {
delete[] pdata_[0];
delete[] pdata_[1];
}
Description(ton::validatorsession::ValidatorSessionOptions opts, td::uint32 total_nodes) Description(ton::validatorsession::ValidatorSessionOptions opts, td::uint32 total_nodes)
: opts_(opts), total_nodes_(total_nodes) { : opts_(opts), total_nodes_(total_nodes), mem_perm_(1 << 30), mem_temp_(1 << 22) {
pdata_size_[0] =
static_cast<std::size_t>(std::numeric_limits<std::size_t>::max() < (1ull << 32) ? 1ull << 30 : 1ull << 33);
pdata_size_[1] = 1 << 22;
pdata_[0] = new td::uint8[pdata_size_[0]];
pdata_[1] = new td::uint8[pdata_size_[1]];
pdata_cur_[0] = 0;
pdata_cur_[1] = 0;
for (auto &el : cache_) { for (auto &el : cache_) {
Cached v{nullptr}; Cached v{nullptr};
el.store(v, std::memory_order_relaxed); el.store(v, std::memory_order_relaxed);
@ -224,9 +208,7 @@ class Description : public ton::validatorsession::ValidatorSessionDescription {
}; };
std::array<std::atomic<Cached>, cache_size> cache_; std::array<std::atomic<Cached>, cache_size> cache_;
td::uint8 *pdata_[2]; ton::validatorsession::ValidatorSessionDescriptionImpl::MemPool mem_perm_, mem_temp_;
std::atomic<size_t> pdata_cur_[2];
size_t pdata_size_[2];
}; };
double myrand() { double myrand() {

View file

@ -58,6 +58,7 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
}; };
std::array<std::atomic<Cached>, cache_size> cache_; std::array<std::atomic<Cached>, cache_size> cache_;
public:
class MemPool { class MemPool {
public: public:
explicit MemPool(size_t chunk_size); explicit MemPool(size_t chunk_size);
@ -71,6 +72,8 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
std::vector<td::uint8 *> data_; std::vector<td::uint8 *> data_;
size_t ptr_ = 0; size_t ptr_ = 0;
}; };
private:
MemPool mem_perm_ = MemPool(mem_chunk_size_perm); MemPool mem_perm_ = MemPool(mem_chunk_size_perm);
MemPool mem_temp_ = MemPool(mem_chunk_size_temp); MemPool mem_temp_ = MemPool(mem_chunk_size_temp);

View file

@ -244,7 +244,7 @@ class Collator final : public td::actor::Actor {
Ref<vm::Cell>& in_msg); Ref<vm::Cell>& in_msg);
bool create_ticktock_transactions(int mask); bool create_ticktock_transactions(int mask);
bool create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, ton::LogicalTime req_start_lt, int mask); bool create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, ton::LogicalTime req_start_lt, int mask);
Ref<vm::Cell> create_ordinary_transaction(Ref<vm::Cell> msg_root); Ref<vm::Cell> create_ordinary_transaction(Ref<vm::Cell> msg_root, bool is_special_tx = false);
bool check_cur_validator_set(); bool check_cur_validator_set();
bool unpack_last_mc_state(); bool unpack_last_mc_state();
bool unpack_last_state(); bool unpack_last_state();

View file

@ -2667,8 +2667,7 @@ bool Collator::create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, t
return fatal_error(td::Status::Error( return fatal_error(td::Status::Error(
-666, std::string{"cannot serialize new transaction for smart contract "} + smc_addr.to_hex())); -666, std::string{"cannot serialize new transaction for smart contract "} + smc_addr.to_hex()));
} }
if (!trans->update_limits(*block_limit_status_, if (!trans->update_limits(*block_limit_status_, /* with_gas = */ false)) {
/* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) {
return fatal_error(-666, "cannot update block limit status to include the new transaction"); return fatal_error(-666, "cannot update block limit status to include the new transaction");
} }
if (trans->commit(*acc).is_null()) { if (trans->commit(*acc).is_null()) {
@ -2684,10 +2683,11 @@ bool Collator::create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, t
* Creates an ordinary transaction using a given message. * Creates an ordinary transaction using a given message.
* *
* @param msg_root The root of the message to be processed serialized using Message TLB-scheme. * @param msg_root The root of the message to be processed serialized using Message TLB-scheme.
* @param is_special_tx True if creating a special transaction (mint/recover), false otherwise.
* *
* @returns The root of the serialized transaction, or an empty reference if the transaction creation fails. * @returns The root of the serialized transaction, or an empty reference if the transaction creation fails.
*/ */
Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) { Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root, bool is_special_tx) {
ton::StdSmcAddress addr; ton::StdSmcAddress addr;
auto cs = vm::load_cell_slice(msg_root); auto cs = vm::load_cell_slice(msg_root);
bool external; bool external;
@ -2746,7 +2746,7 @@ Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) {
std::unique_ptr<block::transaction::Transaction> trans = res.move_as_ok(); std::unique_ptr<block::transaction::Transaction> trans = res.move_as_ok();
if (!trans->update_limits(*block_limit_status_, if (!trans->update_limits(*block_limit_status_,
/* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) { /* with_gas = */ !(is_special_tx && compute_phase_cfg_.special_gas_full))) {
fatal_error("cannot update block limit status to include the new transaction"); fatal_error("cannot update block limit status to include the new transaction");
return {}; return {};
} }
@ -3019,7 +3019,7 @@ int Collator::process_one_new_message(block::NewOutMsg msg, bool enqueue_only, R
return -1; return -1;
} }
// 1. create a Transaction processing this Message // 1. create a Transaction processing this Message
auto trans_root = create_ordinary_transaction(msg.msg); auto trans_root = create_ordinary_transaction(msg.msg, is_special != nullptr);
if (trans_root.is_null()) { if (trans_root.is_null()) {
fatal_error("cannot create transaction for re-processing output message"); fatal_error("cannot create transaction for re-processing output message");
return -1; return -1;

View file

@ -156,6 +156,7 @@ td::Status ExtMessageQ::run_message_on_account(ton::WorkchainId wc,
} }
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config->get_libraries_root(), 256); compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config->get_libraries_root(), 256);
compute_phase_cfg_.with_vm_log = true; compute_phase_cfg_.with_vm_log = true;
compute_phase_cfg_.stop_on_accept_message = true;
auto res = Collator::impl_create_ordinary_transaction(msg_root, acc, utime, lt, auto res = Collator::impl_create_ordinary_transaction(msg_root, acc, utime, lt,
&storage_phase_cfg_, &compute_phase_cfg_, &storage_phase_cfg_, &compute_phase_cfg_,

View file

@ -945,6 +945,7 @@ bool ValidateQuery::fetch_config_params() {
return fatal_error(mc_gas_prices.move_as_error_prefix("cannot unpack masterchain gas prices and limits: ")); return fatal_error(mc_gas_prices.move_as_error_prefix("cannot unpack masterchain gas prices and limits: "));
} }
compute_phase_cfg_.mc_gas_prices = mc_gas_prices.move_as_ok(); compute_phase_cfg_.mc_gas_prices = mc_gas_prices.move_as_ok();
compute_phase_cfg_.special_gas_full = config_->get_global_version() >= 5;
storage_phase_cfg_.enable_due_payment = config_->get_global_version() >= 4; storage_phase_cfg_.enable_due_payment = config_->get_global_version() >= 4;
compute_phase_cfg_.block_rand_seed = rand_seed_; compute_phase_cfg_.block_rand_seed = rand_seed_;
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256); compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
@ -4684,6 +4685,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
bool external{false}, ihr_delivered{false}, need_credit_phase{false}; bool external{false}, ihr_delivered{false}, need_credit_phase{false};
// check input message // check input message
block::CurrencyCollection money_imported(0), money_exported(0); block::CurrencyCollection money_imported(0), money_exported(0);
bool is_special_tx = false; // recover/mint transaction
if (in_msg_root.not_null()) { if (in_msg_root.not_null()) {
auto in_descr_cs = in_msg_dict_->lookup(in_msg_root->get_hash().as_bitslice()); auto in_descr_cs = in_msg_dict_->lookup(in_msg_root->get_hash().as_bitslice());
if (in_descr_cs.is_null()) { if (in_descr_cs.is_null()) {
@ -4699,6 +4701,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
<< " has an invalid InMsg record (not one of msg_import_ext, msg_import_fin, " << " has an invalid InMsg record (not one of msg_import_ext, msg_import_fin, "
"msg_import_imm or msg_import_ihr)"); "msg_import_imm or msg_import_ihr)");
} }
is_special_tx = is_special_in_msg(*in_descr_cs);
// once we know there is a InMsg with correct hash, we already know that it contains a message with this hash (by the verification of InMsg), so it is our message // once we know there is a InMsg with correct hash, we already know that it contains a message with this hash (by the verification of InMsg), so it is our message
// have still to check its destination address and imported value // have still to check its destination address and imported value
// and that it refers to this transaction // and that it refers to this transaction
@ -4716,7 +4719,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
<< " processed inbound message created later at logical time " << " processed inbound message created later at logical time "
<< info.created_lt); << info.created_lt);
} }
if (info.created_lt != start_lt_ || !is_special_in_msg(*in_descr_cs)) { if (info.created_lt != start_lt_ || !is_special_tx) {
msg_proc_lt_.emplace_back(addr, lt, info.created_lt); msg_proc_lt_.emplace_back(addr, lt, info.created_lt);
} }
dest = std::move(info.dest); dest = std::move(info.dest);
@ -5056,19 +5059,31 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
return reject_query(PSTRING() << "cannot re-create the serialization of transaction " << lt return reject_query(PSTRING() << "cannot re-create the serialization of transaction " << lt
<< " for smart contract " << addr.to_hex()); << " for smart contract " << addr.to_hex());
} }
if (!trs->update_limits(*block_limit_status_, if (!trs->update_limits(*block_limit_status_, /* with_gas = */ false, /* with_size = */ false)) {
/* with_gas = */ !account.is_special && !trs->gas_limit_overridden,
/* with_size = */ false)) {
return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account " return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account "
<< addr.to_hex()); << addr.to_hex());
} }
if (block_limit_status_->gas_used > block_limits_->gas.hard() + compute_phase_cfg_.gas_limit) {
// Note that block_limit_status_->gas_used does not include transactions in special accounts // Collator should stop if total gas usage exceeds limits, including transactions on special accounts, but without
// ticktocks and mint/recover.
// Here Validator checks a weaker condition
if (!is_special_tx && !trs->gas_limit_overridden && trans_type == block::transaction::Transaction::tr_ord) {
(account.is_special ? total_special_gas_used_ : total_gas_used_) += trs->gas_used();
}
if (total_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.gas_limit) {
return reject_query(PSTRING() << "gas block limits are exceeded: total_gas_used > gas_limit_hard + trx_gas_limit (" return reject_query(PSTRING() << "gas block limits are exceeded: total_gas_used > gas_limit_hard + trx_gas_limit ("
<< "total_gas_used=" << block_limit_status_->gas_used << "total_gas_used=" << total_gas_used_
<< ", gas_limit_hard=" << block_limits_->gas.hard() << ", gas_limit_hard=" << block_limits_->gas.hard()
<< ", trx_gas_limit=" << compute_phase_cfg_.gas_limit << ")"); << ", trx_gas_limit=" << compute_phase_cfg_.gas_limit << ")");
} }
if (total_special_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.special_gas_limit) {
return reject_query(
PSTRING() << "gas block limits are exceeded: total_special_gas_used > gas_limit_hard + special_gas_limit ("
<< "total_special_gas_used=" << total_special_gas_used_
<< ", gas_limit_hard=" << block_limits_->gas.hard()
<< ", special_gas_limit=" << compute_phase_cfg_.special_gas_limit << ")");
}
auto trans_root2 = trs->commit(account); auto trans_root2 = trs->commit(account);
if (trans_root2.is_null()) { if (trans_root2.is_null()) {
return reject_query(PSTRING() << "the re-created transaction " << lt << " for smart contract " << addr.to_hex() return reject_query(PSTRING() << "the re-created transaction " << lt << " for smart contract " << addr.to_hex()

View file

@ -195,6 +195,7 @@ class ValidateQuery : public td::actor::Actor {
ton::LogicalTime prev_key_block_lt_; ton::LogicalTime prev_key_block_lt_;
std::unique_ptr<block::BlockLimits> block_limits_; std::unique_ptr<block::BlockLimits> block_limits_;
std::unique_ptr<block::BlockLimitStatus> block_limit_status_; std::unique_ptr<block::BlockLimitStatus> block_limit_status_;
td::uint64 total_gas_used_{0}, total_special_gas_used_{0};
LogicalTime start_lt_, end_lt_; LogicalTime start_lt_, end_lt_;
UnixTime prev_now_{~0u}, now_{~0u}; UnixTime prev_now_{~0u}, now_{~0u};

View file

@ -2460,8 +2460,8 @@ void ValidatorManagerImpl::update_shard_client_state(BlockIdExt masterchain_bloc
} }
void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) { void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) {
if (!shard_client_.empty() && !from_db) { if (shard_client_handle_ && !from_db) {
td::actor::send_closure(shard_client_, &ShardClient::get_processed_masterchain_block_id, std::move(promise)); promise.set_result(shard_client_handle_->id());
} else { } else {
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise)); td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
} }