From 49d62dc3bb075605b9174d1fb68aadda0a7412b2 Mon Sep 17 00:00:00 2001 From: EmelyanenkoK Date: Wed, 24 Jan 2024 13:05:22 +0300 Subject: [PATCH] Activate new changes in TVM by version>=5, reduce gas cost for loading libraries (#875) Co-authored-by: SpyCheese --- crypto/vm/cellops.cpp | 47 +++++++++++++++++++---------------- crypto/vm/cells/CellSlice.cpp | 14 ++++++----- crypto/vm/vm.h | 2 +- crypto/vm/vmstate.h | 4 +++ doc/GlobalVersions.md | 11 ++++++-- 5 files changed, 47 insertions(+), 31 deletions(-) diff --git a/crypto/vm/cellops.cpp b/crypto/vm/cellops.cpp index 9b702fcd8..af84a67e5 100644 --- a/crypto/vm/cellops.cpp +++ b/crypto/vm/cellops.cpp @@ -892,34 +892,37 @@ 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(); - 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 (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, "unexpected special cell"}; + throw VmError{Excno::cell_und, "failed to load 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"}; + 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"}; + } } } } diff --git a/crypto/vm/cells/CellSlice.cpp b/crypto/vm/cells/CellSlice.cpp index cbfc9e50e..ee5f6941a 100644 --- a/crypto/vm/cells/CellSlice.cpp +++ b/crypto/vm/cells/CellSlice.cpp @@ -1056,10 +1056,10 @@ std::ostream& operator<<(std::ostream& os, Ref 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, 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,11 +1077,13 @@ VirtualCell::LoadedCell load_cell_slice_impl(Ref cell, bool* can_be_specia *can_be_special = 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 (library_loaded) { - throw VmError{Excno::cell_und, "failed to load library cell: recursive library cells are not allowed"}; - } - library_loaded = true; 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); diff --git a/crypto/vm/vm.h b/crypto/vm/vm.h index fd18f92d8..e5cca026c 100644 --- a/crypto/vm/vm.h +++ b/crypto/vm/vm.h @@ -340,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) { diff --git a/crypto/vm/vmstate.h b/crypto/vm/vmstate.h index a81a4e78d..0d6c3fdf9 100644 --- a/crypto/vm/vmstate.h +++ b/crypto/vm/vmstate.h @@ -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 { virtual bool register_op(int op_units = 1) { return true; }; + virtual int get_global_version() const { + return ton::SUPPORTED_VERSION; + } }; } // namespace vm diff --git a/doc/GlobalVersions.md b/doc/GlobalVersions.md index 7d9729f88..d2064b901 100644 --- a/doc/GlobalVersions.md +++ b/doc/GlobalVersions.md @@ -39,11 +39,18 @@ intermediate value before division (e.g. `(xy+w)/z`). * 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 could use up to `gas_limit` gas (1M). +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. \ No newline at end of file +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. \ No newline at end of file