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:
commit
8a9ff33992
31 changed files with 211 additions and 85 deletions
4
.github/workflows/ton-x86-64-linux.yml
vendored
4
.github/workflows/ton-x86-64-linux.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
|||
run: |
|
||||
cp assembly/nix/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
|
||||
run: |
|
||||
|
@ -38,4 +38,4 @@ jobs:
|
|||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-x86_64-linux-binaries
|
||||
path: artifacts
|
||||
path: artifacts
|
||||
|
|
4
.github/workflows/ton-x86-64-macos.yml
vendored
4
.github/workflows/ton-x86-64-macos.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
run: |
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh
|
||||
./build-macos-nix.sh -t
|
||||
|
||||
- name: Simple binaries test
|
||||
run: |
|
||||
|
@ -34,4 +34,4 @@ jobs:
|
|||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ton-x86_64-macos-binaries
|
||||
path: artifacts
|
||||
path: artifacts
|
||||
|
|
10
Changelog.md
10
Changelog.md
|
@ -1,14 +1,20 @@
|
|||
## 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).
|
||||
2. Improvements in LS behavior
|
||||
* 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
|
||||
* 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.
|
||||
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
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ pipeline {
|
|||
sh '''
|
||||
cp assembly/nix/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 '''
|
||||
cd artifacts
|
||||
|
@ -69,7 +69,7 @@ pipeline {
|
|||
sh '''
|
||||
cp assembly/nix/build-linux-arm64-nix.sh .
|
||||
chmod +x build-linux-arm64-nix.sh
|
||||
./build-linux-arm64-nix.sh
|
||||
./build-linux-arm64-nix.sh -t
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
|
@ -107,7 +107,7 @@ pipeline {
|
|||
sh '''
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh
|
||||
./build-macos-nix.sh -t
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
|
@ -145,7 +145,7 @@ pipeline {
|
|||
sh '''
|
||||
cp assembly/nix/build-macos-nix.sh .
|
||||
chmod +x build-macos-nix.sh
|
||||
./build-macos-nix.sh
|
||||
./build-macos-nix.sh -t
|
||||
'''
|
||||
sh '''
|
||||
cd artifacts
|
||||
|
@ -233,4 +233,4 @@ pipeline {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,27 @@
|
|||
nix-build --version
|
||||
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/microhttpd.nix .
|
||||
cp assembly/nix/openssl.nix .
|
||||
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
|
||||
cp ./result/bin/* 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/libemulator.so artifacts/
|
||||
cp -r crypto/fift/lib artifacts/
|
||||
cp -r crypto/smartcont artifacts/
|
||||
cp -r crypto/smartcont artifacts/
|
||||
|
|
|
@ -3,12 +3,28 @@
|
|||
nix-build --version
|
||||
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/microhttpd.nix .
|
||||
cp assembly/nix/openssl.nix .
|
||||
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
|
||||
cp ./result/bin/* 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/libemulator.so artifacts/
|
||||
cp -r crypto/fift/lib artifacts/
|
||||
cp -r crypto/smartcont artifacts/
|
||||
cp -r crypto/smartcont artifacts/
|
||||
|
|
|
@ -3,9 +3,25 @@
|
|||
nix-build --version
|
||||
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-* .
|
||||
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
|
||||
cp ./result-bin/bin/* artifacts/
|
||||
chmod +x artifacts/*
|
||||
|
@ -14,4 +30,4 @@ nix-build macos-tonlib.nix
|
|||
cp ./result/lib/libtonlibjson.dylib artifacts/
|
||||
cp ./result/lib/libemulator.dylib artifacts/
|
||||
cp -r crypto/fift/lib artifacts/
|
||||
cp -r crypto/smartcont artifacts/
|
||||
cp -r crypto/smartcont artifacts/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
|
||||
, lib ? pkgs.lib
|
||||
, stdenv ? pkgs.stdenv
|
||||
, testing ? false
|
||||
}:
|
||||
let
|
||||
microhttpdmy = (import ./microhttpd.nix) {};
|
||||
|
@ -25,7 +26,7 @@ stdenv.mkDerivation {
|
|||
];
|
||||
|
||||
makeStatic = true;
|
||||
doCheck = true;
|
||||
doCheck = testing;
|
||||
|
||||
cmakeFlags = [
|
||||
"-DTON_USE_ABSEIL=OFF"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
|
||||
, lib ? pkgs.lib
|
||||
, stdenv ? pkgs.stdenv
|
||||
, testing ? false
|
||||
}:
|
||||
let
|
||||
microhttpdmy = (import ./microhttpd.nix) {};
|
||||
|
@ -25,7 +26,7 @@ stdenv.mkDerivation {
|
|||
];
|
||||
|
||||
makeStatic = true;
|
||||
doCheck = true;
|
||||
doCheck = testing;
|
||||
|
||||
cmakeFlags = [
|
||||
"-DTON_USE_ABSEIL=OFF"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
|
||||
, lib ? pkgs.lib
|
||||
, stdenv ? pkgs.stdenv
|
||||
, testing ? false
|
||||
}:
|
||||
|
||||
pkgs.llvmPackages_14.stdenv.mkDerivation {
|
||||
|
@ -29,7 +30,7 @@ pkgs.llvmPackages_14.stdenv.mkDerivation {
|
|||
|
||||
dontAddStaticConfigureFlags = true;
|
||||
makeStatic = true;
|
||||
doCheck = true;
|
||||
doCheck = testing;
|
||||
|
||||
configureFlags = [];
|
||||
|
||||
|
@ -62,4 +63,4 @@ pkgs.llvmPackages_14.stdenv.mkDerivation {
|
|||
done
|
||||
'';
|
||||
outputs = [ "bin" "out" ];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
namespace ton {
|
||||
|
||||
// See doc/GlobalVersions.md
|
||||
const int SUPPORTED_VERSION = 4;
|
||||
const int SUPPORTED_VERSION = 5;
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
= 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
|
||||
= GasLimitsPrices;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
||||
block::gen::GasLimitsPrices::Record_gas_prices_v3 rec_v3;
|
||||
vm::CellSlice cs0 = cs;
|
||||
if (tlb::unpack(cs, rec)) {
|
||||
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 {
|
||||
block::gen::GasLimitsPrices::Record_gas_prices rec0;
|
||||
if (tlb::unpack(cs = cs0, rec0)) {
|
||||
|
|
|
@ -349,7 +349,6 @@ struct GasLimitsPrices {
|
|||
td::uint64 block_gas_limit{0};
|
||||
td::uint64 freeze_due_limit{0};
|
||||
td::uint64 delete_due_limit{0};
|
||||
bool special_full_limit{false};
|
||||
|
||||
td::RefInt256 compute_gas_price(td::uint64 gas_used) const;
|
||||
};
|
||||
|
|
|
@ -1039,12 +1039,8 @@ bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, t
|
|||
delete_due_limit = td::make_refint(r.delete_due_limit);
|
||||
};
|
||||
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
||||
block::gen::GasLimitsPrices::Record_gas_prices_v3 rec_v3;
|
||||
if (tlb::csr_unpack(cs, rec)) {
|
||||
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 {
|
||||
block::gen::GasLimitsPrices::Record_gas_prices 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.
|
||||
* See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened.
|
||||
* Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu
|
||||
* It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-16).
|
||||
* It is activated by setting gas_prices_v3 in ConfigParam 20 (config_mc_gas_prices).
|
||||
* 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 global version to 5 in ConfigParam 8.
|
||||
* This config change also activates new behavior for special accounts in masterchain.
|
||||
*
|
||||
* @param cfg The compute phase configuration.
|
||||
|
@ -1164,10 +1160,10 @@ namespace transaction {
|
|||
* @returns True if gas_limit override is required, false otherwise
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD";
|
||||
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_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
|
||||
vm.set_chksig_always_succeed(cfg.ignore_chksig);
|
||||
vm.set_stop_on_accept_message(cfg.stop_on_accept_message);
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
|
||||
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),
|
||||
"cannot unpack masterchain gas prices and limits: ");
|
||||
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;
|
||||
compute_phase_cfg->block_rand_seed = *rand_seed;
|
||||
compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth;
|
||||
|
|
|
@ -120,6 +120,7 @@ struct ComputePhaseConfig {
|
|||
std::unique_ptr<vm::Dictionary> suspended_addresses;
|
||||
SizeLimitsConfig size_limits;
|
||||
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) {
|
||||
compute_threshold();
|
||||
|
|
|
@ -892,6 +892,40 @@ int exec_load_special_cell(VmState* st, bool quiet) {
|
|||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute XLOAD" << (quiet ? "Q" : "");
|
||||
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);
|
||||
if (quiet) {
|
||||
stack.push_bool(true);
|
||||
|
|
|
@ -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
|
||||
// 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) {
|
||||
auto* vm_state_interface = VmStateInterface::get();
|
||||
bool library_loaded = false;
|
||||
while (true) {
|
||||
auto* vm_state_interface = VmStateInterface::get();
|
||||
if (vm_state_interface) {
|
||||
if (vm_state_interface && !library_loaded) {
|
||||
vm_state_interface->register_cell_load(cell->get_hash());
|
||||
}
|
||||
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()) {
|
||||
if (loaded_cell.data_cell->special_type() == DataCell::SpecialType::Library) {
|
||||
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));
|
||||
DCHECK(cs.size() == Cell::hash_bits + 8);
|
||||
auto library_cell = vm_state_interface->load_library(cs.data_bits() + 8);
|
||||
|
|
|
@ -67,6 +67,10 @@ int exec_set_gas_generic(VmState* st, long long new_gas_limit) {
|
|||
throw VmNoGas{};
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ class VmState final : public VmStateInterface {
|
|||
td::HashSet<CellHash> loaded_cells;
|
||||
int stack_trace{0}, debug_off{0};
|
||||
bool chksig_always_succeed{false};
|
||||
bool stop_on_accept_message{false};
|
||||
td::optional<td::Bits256> missing_library;
|
||||
td::uint16 max_data_depth = 512; // Default value
|
||||
int global_version{0};
|
||||
|
@ -339,7 +340,7 @@ class VmState final : public VmStateInterface {
|
|||
void preclear_cr(const ControlRegs& save) {
|
||||
cr &= save;
|
||||
}
|
||||
int get_global_version() const {
|
||||
int get_global_version() const override {
|
||||
return global_version;
|
||||
}
|
||||
void set_global_version(int version) {
|
||||
|
@ -381,6 +382,12 @@ class VmState final : public VmStateInterface {
|
|||
bool get_chksig_always_succeed() const {
|
||||
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 {
|
||||
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
#include "common/refcnt.hpp"
|
||||
#include "vm/cells.h"
|
||||
#include "common/global-version.h"
|
||||
|
||||
#include "td/utils/Context.h"
|
||||
|
||||
|
@ -38,6 +39,9 @@ class VmStateInterface : public td::Context<VmStateInterface> {
|
|||
virtual bool register_op(int op_units = 1) {
|
||||
return true;
|
||||
};
|
||||
virtual int get_global_version() const {
|
||||
return ton::SUPPORTED_VERSION;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -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.
|
||||
|
||||
### 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.
|
|
@ -1,11 +1,17 @@
|
|||
## 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).
|
||||
2. Improvements in LS behavior
|
||||
* 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
|
||||
* 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.
|
||||
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).
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "validator-session/validator-session-description.h"
|
||||
#include "validator-session/validator-session-state.h"
|
||||
#include "validator-session/validator-session-description.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
@ -48,17 +49,13 @@ class Description : public ton::validatorsession::ValidatorSessionDescription {
|
|||
return 0;
|
||||
}
|
||||
void *alloc(size_t size, size_t align, bool temp) override {
|
||||
size = (size + 15) / 16 * 16;
|
||||
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);
|
||||
return (temp ? mem_temp_ : mem_perm_).alloc(size, align);
|
||||
}
|
||||
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 {
|
||||
pdata_cur_[1] = 0;
|
||||
mem_temp_.clear();
|
||||
}
|
||||
|
||||
ton::PublicKeyHash get_source_id(td::uint32 idx) const override {
|
||||
|
@ -189,21 +186,8 @@ class Description : public ton::validatorsession::ValidatorSessionDescription {
|
|||
return opts_;
|
||||
}
|
||||
|
||||
~Description() {
|
||||
delete[] pdata_[0];
|
||||
delete[] pdata_[1];
|
||||
}
|
||||
|
||||
Description(ton::validatorsession::ValidatorSessionOptions opts, td::uint32 total_nodes)
|
||||
: opts_(opts), total_nodes_(total_nodes) {
|
||||
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;
|
||||
|
||||
: opts_(opts), total_nodes_(total_nodes), mem_perm_(1 << 30), mem_temp_(1 << 22) {
|
||||
for (auto &el : cache_) {
|
||||
Cached v{nullptr};
|
||||
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_;
|
||||
|
||||
td::uint8 *pdata_[2];
|
||||
std::atomic<size_t> pdata_cur_[2];
|
||||
size_t pdata_size_[2];
|
||||
ton::validatorsession::ValidatorSessionDescriptionImpl::MemPool mem_perm_, mem_temp_;
|
||||
};
|
||||
|
||||
double myrand() {
|
||||
|
|
|
@ -58,6 +58,7 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
|
|||
};
|
||||
std::array<std::atomic<Cached>, cache_size> cache_;
|
||||
|
||||
public:
|
||||
class MemPool {
|
||||
public:
|
||||
explicit MemPool(size_t chunk_size);
|
||||
|
@ -71,6 +72,8 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
|
|||
std::vector<td::uint8 *> data_;
|
||||
size_t ptr_ = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
MemPool mem_perm_ = MemPool(mem_chunk_size_perm);
|
||||
MemPool mem_temp_ = MemPool(mem_chunk_size_temp);
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ class Collator final : public td::actor::Actor {
|
|||
Ref<vm::Cell>& in_msg);
|
||||
bool create_ticktock_transactions(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 unpack_last_mc_state();
|
||||
bool unpack_last_state();
|
||||
|
|
|
@ -2667,8 +2667,7 @@ bool Collator::create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, t
|
|||
return fatal_error(td::Status::Error(
|
||||
-666, std::string{"cannot serialize new transaction for smart contract "} + smc_addr.to_hex()));
|
||||
}
|
||||
if (!trans->update_limits(*block_limit_status_,
|
||||
/* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) {
|
||||
if (!trans->update_limits(*block_limit_status_, /* with_gas = */ false)) {
|
||||
return fatal_error(-666, "cannot update block limit status to include the new transaction");
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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;
|
||||
auto cs = vm::load_cell_slice(msg_root);
|
||||
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();
|
||||
|
||||
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");
|
||||
return {};
|
||||
}
|
||||
|
@ -3019,7 +3019,7 @@ int Collator::process_one_new_message(block::NewOutMsg msg, bool enqueue_only, R
|
|||
return -1;
|
||||
}
|
||||
// 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()) {
|
||||
fatal_error("cannot create transaction for re-processing output message");
|
||||
return -1;
|
||||
|
|
|
@ -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_.with_vm_log = true;
|
||||
compute_phase_cfg_.stop_on_accept_message = true;
|
||||
|
||||
auto res = Collator::impl_create_ordinary_transaction(msg_root, acc, utime, lt,
|
||||
&storage_phase_cfg_, &compute_phase_cfg_,
|
||||
|
|
|
@ -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: "));
|
||||
}
|
||||
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;
|
||||
compute_phase_cfg_.block_rand_seed = rand_seed_;
|
||||
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};
|
||||
// check input message
|
||||
block::CurrencyCollection money_imported(0), money_exported(0);
|
||||
bool is_special_tx = false; // recover/mint transaction
|
||||
if (in_msg_root.not_null()) {
|
||||
auto in_descr_cs = in_msg_dict_->lookup(in_msg_root->get_hash().as_bitslice());
|
||||
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, "
|
||||
"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
|
||||
// have still to check its destination address and imported value
|
||||
// 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 "
|
||||
<< 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);
|
||||
}
|
||||
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
|
||||
<< " for smart contract " << addr.to_hex());
|
||||
}
|
||||
if (!trs->update_limits(*block_limit_status_,
|
||||
/* with_gas = */ !account.is_special && !trs->gas_limit_overridden,
|
||||
/* with_size = */ false)) {
|
||||
if (!trs->update_limits(*block_limit_status_, /* with_gas = */ false, /* with_size = */ false)) {
|
||||
return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account "
|
||||
<< 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 ("
|
||||
<< "total_gas_used=" << block_limit_status_->gas_used
|
||||
<< "total_gas_used=" << total_gas_used_
|
||||
<< ", gas_limit_hard=" << block_limits_->gas.hard()
|
||||
<< ", 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);
|
||||
if (trans_root2.is_null()) {
|
||||
return reject_query(PSTRING() << "the re-created transaction " << lt << " for smart contract " << addr.to_hex()
|
||||
|
|
|
@ -195,6 +195,7 @@ class ValidateQuery : public td::actor::Actor {
|
|||
ton::LogicalTime prev_key_block_lt_;
|
||||
std::unique_ptr<block::BlockLimits> block_limits_;
|
||||
std::unique_ptr<block::BlockLimitStatus> block_limit_status_;
|
||||
td::uint64 total_gas_used_{0}, total_special_gas_used_{0};
|
||||
|
||||
LogicalTime start_lt_, end_lt_;
|
||||
UnixTime prev_now_{~0u}, now_{~0u};
|
||||
|
|
|
@ -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) {
|
||||
if (!shard_client_.empty() && !from_db) {
|
||||
td::actor::send_closure(shard_client_, &ShardClient::get_processed_masterchain_block_id, std::move(promise));
|
||||
if (shard_client_handle_ && !from_db) {
|
||||
promise.set_result(shard_client_handle_->id());
|
||||
} else {
|
||||
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue