Skip to content

Commit 0fff1bd

Browse files
committed
Fix loading library cell in contract code
1 parent a01c7e2 commit 0fff1bd

File tree

10 files changed

+49
-56
lines changed

10 files changed

+49
-56
lines changed

crypto/block/transaction.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,9 +1692,8 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
16921692
}
16931693
}
16941694
}
1695-
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
1695+
vm::VmState vm{new_code, cfg.global_version, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
16961696
vm.set_max_data_depth(cfg.max_vm_data_depth);
1697-
vm.set_global_version(cfg.global_version);
16981697
vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
16991698
vm.set_chksig_always_succeed(cfg.ignore_chksig);
17001699
vm.set_stop_on_accept_message(cfg.stop_on_accept_message);

crypto/fift/lib/Asm.fif

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,7 @@ x{F832} @Defop CONFIGPARAM
13121312
x{F833} @Defop CONFIGOPTPARAM
13131313
x{F83400} @Defop PREVMCBLOCKS
13141314
x{F83401} @Defop PREVKEYBLOCK
1315+
x{F83402} @Defop PREVMCBLOCKS_100
13151316
x{F835} @Defop GLOBALID
13161317
x{F836} @Defop GETGASFEE
13171318
x{F837} @Defop GETSTORAGEFEE

crypto/smc-envelope/SmartContract.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,14 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
222222
stack->dump(os, 2);
223223
LOG(DEBUG) << "VM stack:\n" << os.str();
224224
}
225-
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
225+
int global_version = config ? config->get_global_version() : 0;
226+
vm::VmState vm{state.code, global_version, std::move(stack), gas, 1, state.data, log};
226227
vm.set_c7(std::move(c7));
227228
vm.set_chksig_always_succeed(ignore_chksig);
228229
if (!libraries.is_null()) {
229230
vm.register_library_collection(libraries);
230231
}
231232
if (config) {
232-
vm.set_global_version(config->get_global_version());
233233
auto r_limits = config->get_size_limits_config();
234234
if (r_limits.is_ok()) {
235235
vm.set_max_data_depth(r_limits.ok().max_vm_data_depth);

crypto/vm/contops.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,10 @@ int exec_runvm_common(VmState* st, unsigned mode) {
261261
vm::GasLimits gas{gas_limit, gas_max};
262262

263263
VmStateInterface::Guard guard{nullptr}; // Don't consume gas for creating/loading cells during VM init
264-
VmState new_state{std::move(code), std::move(new_stack), gas, (int)mode & 3, std::move(data),
265-
VmLog{}, std::vector<Ref<Cell>>{}, std::move(c7)};
264+
VmState new_state{
265+
std::move(code), st->get_global_version(), std::move(new_stack), gas, (int)mode & 3, std::move(data),
266+
VmLog{}, std::vector<Ref<Cell>>{}, std::move(c7)};
266267
new_state.set_chksig_always_succeed(st->get_chksig_always_succeed());
267-
new_state.set_global_version(st->get_global_version());
268268
st->run_child_vm(std::move(new_state), with_data, mode & 32, mode & 8, mode & 128, ret_vals);
269269
return 0;
270270
}

crypto/vm/vm.cpp

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "vm/log.h"
2323
#include "vm/vm.h"
2424
#include "cp0.h"
25+
#include "memo.h"
26+
2527
#include <sodium.h>
2628

2729
namespace vm {
@@ -31,33 +33,8 @@ VmState::VmState() : cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), qu
3133
init_cregs();
3234
}
3335

34-
VmState::VmState(Ref<CellSlice> _code)
35-
: code(std::move(_code)), cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) {
36-
ensure_throw(init_cp(0));
37-
init_cregs();
38-
}
39-
40-
VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, int flags, Ref<Cell> _data, VmLog log,
41-
std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
42-
: code(std::move(_code))
43-
, stack(std::move(_stack))
44-
, cp(-1)
45-
, dispatch(&dummy_dispatch_table)
46-
, quit0(true, 0)
47-
, quit1(true, 1)
48-
, log(log)
49-
, libraries(std::move(_libraries))
50-
, stack_trace((flags >> 2) & 1) {
51-
ensure_throw(init_cp(0));
52-
set_c4(std::move(_data));
53-
if (init_c7.not_null()) {
54-
set_c7(std::move(init_c7));
55-
}
56-
init_cregs(flags & 1, flags & 2);
57-
}
58-
59-
VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas, int flags, Ref<Cell> _data, VmLog log,
60-
std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
36+
VmState::VmState(Ref<CellSlice> _code, int global_version, Ref<Stack> _stack, const GasLimits& gas, int flags,
37+
Ref<Cell> _data, VmLog log, std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
6138
: code(std::move(_code))
6239
, stack(std::move(_stack))
6340
, cp(-1)
@@ -67,7 +44,8 @@ VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas,
6744
, log(log)
6845
, gas(gas)
6946
, libraries(std::move(_libraries))
70-
, stack_trace((flags >> 2) & 1) {
47+
, stack_trace((flags >> 2) & 1)
48+
, global_version(global_version) {
7149
ensure_throw(init_cp(0));
7250
set_c4(std::move(_data));
7351
if (init_c7.not_null()) {
@@ -102,12 +80,24 @@ void VmState::init_cregs(bool same_c3, bool push_0) {
10280
}
10381
}
10482

105-
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell) {
83+
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell, int global_version,
84+
const std::vector<Ref<Cell>>& libraries) {
10685
if (code_cell.is_null()) {
10786
return {};
10887
}
109-
Ref<CellSlice> csr{true, NoVmOrd(), code_cell};
110-
if (csr->is_valid()) {
88+
Ref<CellSlice> csr;
89+
if (global_version >= 9) {
90+
// Use DummyVmState instead of this to avoid consuming gas for cell loading
91+
DummyVmState dummy{libraries, global_version};
92+
Guard guard(&dummy);
93+
try {
94+
csr = load_cell_slice_ref(code_cell);
95+
} catch (VmError&) { // NOLINT(*-empty-catch)
96+
}
97+
} else {
98+
csr = td::Ref<CellSlice>{true, NoVmOrd(), code_cell};
99+
}
100+
if (csr.not_null() && csr->is_valid()) {
111101
return csr;
112102
}
113103
return load_cell_slice_ref(CellBuilder{}.store_ref(std::move(code_cell)).finalize());
@@ -577,14 +567,14 @@ int run_vm_code(Ref<CellSlice> code, Ref<Stack>& stack, int flags, Ref<Cell>* da
577567
GasLimits* gas_limits, std::vector<Ref<Cell>> libraries, Ref<Tuple> init_c7, Ref<Cell>* actions_ptr,
578568
int global_version) {
579569
VmState vm{code,
570+
global_version,
580571
std::move(stack),
581572
gas_limits ? *gas_limits : GasLimits{},
582573
flags,
583574
data_ptr ? *data_ptr : Ref<Cell>{},
584575
log,
585576
std::move(libraries),
586577
std::move(init_c7)};
587-
vm.set_global_version(global_version);
588578
int res = vm.run();
589579
stack = vm.get_stack_ref();
590580
if (vm.committed() && data_ptr) {

crypto/vm/vm.h

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,12 @@ class VmState final : public VmStateInterface {
164164
bls_pairing_element_gas_price = 11800
165165
};
166166
VmState();
167-
VmState(Ref<CellSlice> _code);
168-
VmState(Ref<CellSlice> _code, Ref<Stack> _stack, int flags = 0, Ref<Cell> _data = {}, VmLog log = {},
169-
std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {});
170-
VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0, Ref<Cell> _data = {},
167+
VmState(Ref<CellSlice> _code, int global_version, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0, Ref<Cell> _data = {},
171168
VmLog log = {}, std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {});
172-
template <typename... Args>
173-
VmState(Ref<Cell> code_cell, Args&&... args)
174-
: VmState(convert_code_cell(std::move(code_cell)), std::forward<Args>(args)...) {
169+
VmState(Ref<Cell> _code, int global_version, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0,
170+
Ref<Cell> _data = {}, VmLog log = {}, std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {})
171+
: VmState(convert_code_cell(std::move(_code), global_version, _libraries), global_version, std::move(_stack),
172+
_gas, flags, std::move(_data), std::move(log), _libraries, std::move(init_c7)) {
175173
}
176174
VmState(const VmState&) = delete;
177175
VmState(VmState&&) = default;
@@ -345,9 +343,6 @@ class VmState final : public VmStateInterface {
345343
int get_global_version() const override {
346344
return global_version;
347345
}
348-
void set_global_version(int version) {
349-
global_version = version;
350-
}
351346
int call(Ref<Continuation> cont);
352347
int call(Ref<Continuation> cont, int pass_args, int ret_args = -1);
353348
int jump(Ref<Continuation> cont);
@@ -382,7 +377,8 @@ class VmState final : public VmStateInterface {
382377
}
383378
return res;
384379
}
385-
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
380+
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell, int global_version,
381+
const std::vector<Ref<Cell>>& libraries);
386382
bool try_commit();
387383
void force_commit();
388384

doc/GlobalVersions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,5 @@ Example: if the last masterchain block seqno is `19071` then the list contains b
130130
- Previously it did not work if storage fee was greater than the original balance.
131131
- Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code).
132132
- Fix exception code in some TVM instructions: now `stk_und` has priority over other error codes.
133-
- `PFXDICTADD`, `PFXDICTSET`, `PFXDICTREPLACE`, `PFXDICTDEL`, `GETGASFEE`, `GETSTORAGEFEE`, `GETFORWARDFEE`, `GETORIGINALFWDFEE`, `GETGASFEESIMPLE`, `GETFORWARDFEESIMPLE`, `HASHEXT`
133+
- `PFXDICTADD`, `PFXDICTSET`, `PFXDICTREPLACE`, `PFXDICTDEL`, `GETGASFEE`, `GETSTORAGEFEE`, `GETFORWARDFEE`, `GETORIGINALFWDFEE`, `GETGASFEESIMPLE`, `GETFORWARDFEESIMPLE`, `HASHEXT`
134+
- Now setting the contract code to a library cell does not consume additional gas on execution of the code.

lite-client/lite-client.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2227,7 +2227,7 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
22272227
// auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
22282228
vm::GasLimits gas{gas_limit};
22292229
LOG(DEBUG) << "creating VM";
2230-
vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
2230+
vm::VmState vm{code, ton::SUPPORTED_VERSION, std::move(stack), gas, 1, data, vm::VmLog()};
22312231
vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()),
22322232
balance)); // tuple with SmartContractInfo
22332233
// vm.incr_stack_trace(1); // enable stack dump after each step

utils/opcode-timing.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ runInfo time_run_vm(td::Slice command, td::Ref<vm::Stack> stack) {
135135
CHECK(stack.is_unique());
136136
try {
137137
vm::GasLimits gas_limit;
138-
vm::VmState vm{vm::load_cell_slice_ref(cell), std::move(stack), gas_limit, 0, {}, vm::VmLog{}, {}, c7};
139-
vm.set_global_version(ton::SUPPORTED_VERSION);
138+
vm::VmState vm{
139+
vm::load_cell_slice_ref(cell), ton::SUPPORTED_VERSION, std::move(stack), gas_limit, 0, {}, vm::VmLog{}, {}, c7};
140140
std::clock_t cStart = std::clock();
141141
int ret = ~vm.run();
142142
std::clock_t cEnd = std::clock();

validator/impl/liteserver.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,11 +1520,17 @@ void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice
15201520
libraries.push_back(acc_libs);
15211521
}
15221522
vm::GasLimits gas{gas_limit, gas_limit};
1523-
vm::VmState vm{code, std::move(stack_), gas, 1, std::move(data), vm::VmLog::Null(), std::move(libraries)};
1523+
vm::VmState vm{code,
1524+
config->get_global_version(),
1525+
std::move(stack_),
1526+
gas,
1527+
1,
1528+
std::move(data),
1529+
vm::VmLog::Null(),
1530+
std::move(libraries)};
15241531
auto c7 = prepare_vm_c7(gen_utime, gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()), balance, config.get(),
15251532
std::move(code), due_payment);
15261533
vm.set_c7(c7); // tuple with SmartContractInfo
1527-
vm.set_global_version(config->get_global_version());
15281534
// vm.incr_stack_trace(1); // enable stack dump after each step
15291535
LOG(INFO) << "starting VM to run GET-method of smart contract " << acc_workchain_ << ":" << acc_addr_.to_hex();
15301536
// **** RUN VM ****

0 commit comments

Comments
 (0)