Skip to content

Commit

Permalink
Activate new changes in TVM by version>=5, reduce gas cost for loadin…
Browse files Browse the repository at this point in the history
…g libraries (#875)

Co-authored-by: SpyCheese <[email protected]>
  • Loading branch information
EmelyanenkoK and SpyCheese authored Jan 24, 2024
1 parent 9f1b370 commit 49d62dc
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 31 deletions.
47 changes: 25 additions & 22 deletions crypto/vm/cellops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"};
}
}
}
}
Expand Down
14 changes: 8 additions & 6 deletions crypto/vm/cells/CellSlice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1056,10 +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();
Expand All @@ -1077,11 +1077,13 @@ VirtualCell::LoadedCell load_cell_slice_impl(Ref<Cell> 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);
Expand Down
2 changes: 1 addition & 1 deletion crypto/vm/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions crypto/vm/vmstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#pragma once
#include "common/refcnt.hpp"
#include "vm/cells.h"
#include "common/global-version.h"

#include "td/utils/Context.h"

Expand All @@ -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
11 changes: 9 additions & 2 deletions doc/GlobalVersions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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.

0 comments on commit 49d62dc

Please sign in to comment.