Skip to content

Commit fe46f0e

Browse files
authored
Merge pull request #1482 from ton-blockchain/tvm-v9
Tvm v9
2 parents e060515 + e42b0cb commit fe46f0e

File tree

13 files changed

+147
-81
lines changed

13 files changed

+147
-81
lines changed

crypto/block/mc-config.cpp

+27-7
Original file line numberDiff line numberDiff line change
@@ -2292,7 +2292,8 @@ Ref<vm::Cell> ConfigInfo::lookup_library(td::ConstBitPtr root_hash) const {
22922292
td::Result<Ref<vm::Tuple>> ConfigInfo::get_prev_blocks_info() const {
22932293
// [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
22942294
// [ last_mc_blocks:[BlockId...]
2295-
// prev_key_block:BlockId ] : PrevBlocksInfo
2295+
// prev_key_block:BlockId
2296+
// last_mc_blocks_100[BlockId...] ] : PrevBlocksInfo
22962297
auto block_id_to_tuple = [](const ton::BlockIdExt& block_id) -> vm::Ref<vm::Tuple> {
22972298
td::RefInt256 shard = td::make_refint(block_id.id.shard);
22982299
if (shard->sgn() < 0) {
@@ -2302,25 +2303,44 @@ td::Result<Ref<vm::Tuple>> ConfigInfo::get_prev_blocks_info() const {
23022303
td::make_refint(block_id.id.seqno), td::bits_to_refint(block_id.root_hash.bits(), 256),
23032304
td::bits_to_refint(block_id.file_hash.bits(), 256));
23042305
};
2305-
std::vector<vm::StackEntry> last_mc_blocks;
2306+
std::vector<vm::StackEntry> tuple;
23062307

2308+
std::vector<vm::StackEntry> last_mc_blocks;
23072309
last_mc_blocks.push_back(block_id_to_tuple(block_id));
23082310
for (ton::BlockSeqno seqno = block_id.id.seqno; seqno > 0 && last_mc_blocks.size() < 16;) {
23092311
--seqno;
2310-
ton::BlockIdExt block_id;
2311-
if (!get_old_mc_block_id(seqno, block_id)) {
2312+
ton::BlockIdExt id;
2313+
if (!get_old_mc_block_id(seqno, id)) {
23122314
return td::Status::Error("cannot fetch old mc block");
23132315
}
2314-
last_mc_blocks.push_back(block_id_to_tuple(block_id));
2316+
last_mc_blocks.push_back(block_id_to_tuple(id));
23152317
}
2318+
tuple.push_back(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks)));
23162319

23172320
ton::BlockIdExt last_key_block;
23182321
ton::LogicalTime last_key_block_lt;
23192322
if (!get_last_key_block(last_key_block, last_key_block_lt)) {
23202323
return td::Status::Error("cannot fetch last key block");
23212324
}
2322-
return vm::make_tuple_ref(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks)),
2323-
block_id_to_tuple(last_key_block));
2325+
tuple.push_back(block_id_to_tuple(last_key_block));
2326+
2327+
if (get_global_version() >= 9) {
2328+
std::vector<vm::StackEntry> last_mc_blocks_100;
2329+
for (ton::BlockSeqno seqno = block_id.id.seqno / 100 * 100; last_mc_blocks_100.size() < 16;) {
2330+
ton::BlockIdExt id;
2331+
if (!get_old_mc_block_id(seqno, id)) {
2332+
return td::Status::Error("cannot fetch old mc block");
2333+
}
2334+
last_mc_blocks_100.push_back(block_id_to_tuple(id));
2335+
if (seqno < 100) {
2336+
break;
2337+
}
2338+
seqno -= 100;
2339+
}
2340+
tuple.push_back(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks_100)));
2341+
}
2342+
2343+
return td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
23242344
}
23252345

23262346
td::optional<PrecompiledContractsConfig::Contract> PrecompiledContractsConfig::get_contract(

crypto/block/transaction.cpp

+51-16
Original file line numberDiff line numberDiff line change
@@ -1145,31 +1145,64 @@ td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
11451145
namespace transaction {
11461146

11471147
/**
1148-
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) to special_gas_limit * 2
1149-
* from masterchain GasLimitsPrices config for the transaction.
1148+
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) for the transaction
11501149
*
11511150
* In January 2024 a highload wallet of @wallet Telegram bot in mainnet was stuck because current gas limit (1M) is
11521151
* not enough to clean up old queires, thus locking funds inside.
11531152
* See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened.
11541153
* Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu
1155-
* It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-29).
1154+
* It was proposed to validators to increase gas limit for this account to 70M for a limited amount
1155+
* of time (until 2024-02-29).
11561156
* It is activated by setting global version to 5 in ConfigParam 8.
11571157
* This config change also activates new behavior for special accounts in masterchain.
11581158
*
1159+
* In Augost 2024 it was decided to unlock other old highload wallets that got into the same situation.
1160+
* See https://t.me/tondev_news/129
1161+
* It is activated by setting global version to 9.
1162+
*
11591163
* @param cfg The compute phase configuration.
11601164
* @param now The Unix time of the transaction.
11611165
* @param account The account of the transaction.
11621166
*
1163-
* @returns True if gas_limit override is required, false otherwise
1167+
* @returns Overridden gas limit or empty td::optional
11641168
*/
1165-
static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) {
1166-
if (!cfg.special_gas_full) {
1167-
return false;
1169+
static td::optional<td::uint64> override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now,
1170+
const Account& account) {
1171+
struct OverridenGasLimit {
1172+
td::uint64 new_limit;
1173+
int from_version;
1174+
ton::UnixTime until;
1175+
};
1176+
static std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, OverridenGasLimit> accounts = []() {
1177+
auto parse_addr = [](const char* s) -> std::pair<ton::WorkchainId, ton::StdSmcAddress> {
1178+
auto r_addr = StdAddress::parse(td::Slice(s));
1179+
r_addr.ensure();
1180+
return {r_addr.ok().workchain, r_addr.ok().addr};
1181+
};
1182+
std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, OverridenGasLimit> accounts;
1183+
1184+
// Increase limit for EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu until 2024-02-29 00:00:00 UTC
1185+
accounts[parse_addr("0:FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD")] = {
1186+
.new_limit = 70'000'000, .from_version = 5, .until = 1709164800};
1187+
1188+
// Increase limit for multiple accounts (https://t.me/tondev_news/129) until 2025-03-01 00:00:00 UTC
1189+
accounts[parse_addr("UQBeSl-dumOHieZ3DJkNKVkjeso7wZ0VpzR4LCbLGTQ8xr57")] = {
1190+
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
1191+
accounts[parse_addr("EQC3VcQ-43klww9UfimR58TBjBzk7GPupXQ3CNuthoNp-uTR")] = {
1192+
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
1193+
accounts[parse_addr("EQBhwBb8jvokGvfreHRRoeVxI237PrOJgyrsAhLA-4rBC_H5")] = {
1194+
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
1195+
accounts[parse_addr("EQCkoRp4OE-SFUoMEnYfL3vF43T3AzNfW8jyTC4yzk8cJqMS")] = {
1196+
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
1197+
accounts[parse_addr("EQBDanbCeUqI4_v-xrnAN0_I2wRvEIaLg1Qg2ZN5c6Zl1KOh")] = {
1198+
.new_limit = 225'000'000, .from_version = 9, .until = 1740787200};
1199+
return accounts;
1200+
}();
1201+
auto it = accounts.find({account.workchain, account.addr});
1202+
if (it == accounts.end() || cfg.global_version < it->second.from_version || now >= it->second.until) {
1203+
return {};
11681204
}
1169-
ton::UnixTime until = 1709164800; // 2024-02-29 00:00:00 UTC
1170-
ton::WorkchainId wc = 0;
1171-
const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD";
1172-
return now < until && account.workchain == wc && account.addr.to_hex() == addr_hex;
1205+
return it->second.new_limit;
11731206
}
11741207

11751208
/**
@@ -1183,10 +1216,12 @@ static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now,
11831216
* @returns The amount of gas.
11841217
*/
11851218
td::uint64 Transaction::gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms) {
1186-
if (override_gas_limit(cfg, now, account)) {
1219+
if (auto new_limit = override_gas_limit(cfg, now, account)) {
11871220
gas_limit_overridden = true;
11881221
// Same as ComputePhaseConfig::gas_bought for, but with other gas_limit and max_gas_threshold
1189-
auto gas_limit = cfg.mc_gas_prices.special_gas_limit * 2;
1222+
auto gas_limit = new_limit.value();
1223+
LOG(INFO) << "overridding gas limit for account " << account.workchain << ":" << account.addr.to_hex() << " to "
1224+
<< gas_limit;
11901225
auto max_gas_threshold =
11911226
compute_max_gas_threshold(cfg.gas_price256, gas_limit, cfg.flat_gas_limit, cfg.flat_gas_price);
11921227
if (nanograms.is_null() || sgn(nanograms) < 0) {
@@ -1336,7 +1371,8 @@ Ref<vm::Tuple> Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const {
13361371
// See crypto/block/mc-config.cpp#2223 (get_prev_blocks_info)
13371372
// [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
13381373
// [ last_mc_blocks:[BlockId...]
1339-
// prev_key_block:BlockId ] : PrevBlocksInfo
1374+
// prev_key_block:BlockId
1375+
// last_mc_blocks_100:[BlockId...] ] : PrevBlocksInfo
13401376
// The only context where PrevBlocksInfo (13 parameter of c7) is null is inside emulator
13411377
// where it need to be set via transaction_emulator_set_prev_blocks_info (see emulator/emulator-extern.cpp)
13421378
// Inside validator, collator and liteserver checking external message contexts
@@ -1691,9 +1727,8 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
16911727
}
16921728
}
16931729
}
1694-
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
1730+
vm::VmState vm{new_code, cfg.global_version, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
16951731
vm.set_max_data_depth(cfg.max_vm_data_depth);
1696-
vm.set_global_version(cfg.global_version);
16971732
vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
16981733
vm.set_chksig_always_succeed(cfg.ignore_chksig);
16991734
vm.set_stop_on_accept_message(cfg.stop_on_accept_message);

crypto/fift/lib/Asm.fif

+1
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

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

crypto/vm/contops.cpp

+3-3
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/dictops.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ int exec_dict_getnear(VmState* st, unsigned args) {
566566
int exec_pfx_dict_set(VmState* st, Dictionary::SetMode mode, const char* name) {
567567
Stack& stack = st->get_stack();
568568
VM_LOG(st) << "execute PFXDICT" << name;
569-
stack.check_underflow(3);
569+
stack.check_underflow(st->get_global_version() >= 9 ? 4 : 3);
570570
int n = stack.pop_smallint_range(PrefixDictionary::max_key_bits);
571571
PrefixDictionary dict{stack.pop_maybe_cell(), n};
572572
auto key_slice = stack.pop_cellslice();
@@ -580,7 +580,7 @@ int exec_pfx_dict_set(VmState* st, Dictionary::SetMode mode, const char* name) {
580580
int exec_pfx_dict_delete(VmState* st) {
581581
Stack& stack = st->get_stack();
582582
VM_LOG(st) << "execute PFXDICTDEL\n";
583-
stack.check_underflow(2);
583+
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 2);
584584
int n = stack.pop_smallint_range(PrefixDictionary::max_key_bits);
585585
PrefixDictionary dict{stack.pop_maybe_cell(), n};
586586
auto key_slice = stack.pop_cellslice();

crypto/vm/tonops.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ int exec_get_global_id(VmState* st) {
279279
int exec_get_gas_fee(VmState* st) {
280280
VM_LOG(st) << "execute GETGASFEE";
281281
Stack& stack = st->get_stack();
282+
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
282283
bool is_masterchain = stack.pop_bool();
283284
td::uint64 gas = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
284285
block::GasLimitsPrices prices = util::get_gas_prices(get_unpacked_config_tuple(st), is_masterchain);
@@ -289,6 +290,7 @@ int exec_get_gas_fee(VmState* st) {
289290
int exec_get_storage_fee(VmState* st) {
290291
VM_LOG(st) << "execute GETSTORAGEFEE";
291292
Stack& stack = st->get_stack();
293+
stack.check_underflow(st->get_global_version() >= 9 ? 4 : 0);
292294
bool is_masterchain = stack.pop_bool();
293295
td::int64 delta = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
294296
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
@@ -302,6 +304,7 @@ int exec_get_storage_fee(VmState* st) {
302304
int exec_get_forward_fee(VmState* st) {
303305
VM_LOG(st) << "execute GETFORWARDFEE";
304306
Stack& stack = st->get_stack();
307+
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 0);
305308
bool is_masterchain = stack.pop_bool();
306309
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
307310
td::uint64 cells = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
@@ -320,6 +323,7 @@ int exec_get_precompiled_gas(VmState* st) {
320323
int exec_get_original_fwd_fee(VmState* st) {
321324
VM_LOG(st) << "execute GETORIGINALFWDFEE";
322325
Stack& stack = st->get_stack();
326+
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
323327
bool is_masterchain = stack.pop_bool();
324328
td::RefInt256 fwd_fee = stack.pop_int_finite();
325329
if (fwd_fee->sgn() < 0) {
@@ -333,6 +337,7 @@ int exec_get_original_fwd_fee(VmState* st) {
333337
int exec_get_gas_fee_simple(VmState* st) {
334338
VM_LOG(st) << "execute GETGASFEESIMPLE";
335339
Stack& stack = st->get_stack();
340+
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
336341
bool is_masterchain = stack.pop_bool();
337342
td::uint64 gas = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
338343
block::GasLimitsPrices prices = util::get_gas_prices(get_unpacked_config_tuple(st), is_masterchain);
@@ -343,6 +348,7 @@ int exec_get_gas_fee_simple(VmState* st) {
343348
int exec_get_forward_fee_simple(VmState* st) {
344349
VM_LOG(st) << "execute GETFORWARDFEESIMPLE";
345350
Stack& stack = st->get_stack();
351+
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 0);
346352
bool is_masterchain = stack.pop_bool();
347353
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
348354
td::uint64 cells = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
@@ -373,6 +379,7 @@ void register_ton_config_ops(OpcodeTable& cp0) {
373379
.insert(OpcodeInstr::mksimple(0xf833, 16, "CONFIGOPTPARAM", std::bind(exec_get_config_param, _1, true)))
374380
.insert(OpcodeInstr::mksimple(0xf83400, 24, "PREVMCBLOCKS", std::bind(exec_get_prev_blocks_info, _1, 0, "PREVMCBLOCKS"))->require_version(4))
375381
.insert(OpcodeInstr::mksimple(0xf83401, 24, "PREVKEYBLOCK", std::bind(exec_get_prev_blocks_info, _1, 1, "PREVKEYBLOCK"))->require_version(4))
382+
.insert(OpcodeInstr::mksimple(0xf83402, 24, "PREVMCBLOCKS_100", std::bind(exec_get_prev_blocks_info, _1, 2, "PREVMCBLOCKS_100"))->require_version(9))
376383
.insert(OpcodeInstr::mksimple(0xf835, 16, "GLOBALID", exec_get_global_id)->require_version(4))
377384
.insert(OpcodeInstr::mksimple(0xf836, 16, "GETGASFEE", exec_get_gas_fee)->require_version(6))
378385
.insert(OpcodeInstr::mksimple(0xf837, 16, "GETSTORAGEFEE", exec_get_storage_fee)->require_version(6))
@@ -538,9 +545,10 @@ int exec_hash_ext(VmState* st, unsigned args) {
538545
VM_LOG(st) << "execute HASHEXT" << (append ? "A" : "") << (rev ? "R" : "") << " " << (hash_id == 255 ? -1 : hash_id);
539546
Stack& stack = st->get_stack();
540547
if (hash_id == 255) {
548+
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
541549
hash_id = stack.pop_smallint_range(254);
542550
}
543-
int cnt = stack.pop_smallint_range(stack.depth() - 1);
551+
int cnt = stack.pop_smallint_range(stack.depth() - 1 - (st->get_global_version() >= 9 ? (int)append : 0));
544552
Hasher hasher{hash_id};
545553
size_t total_bits = 0;
546554
long long gas_consumed = 0;

crypto/vm/vm.cpp

+22-32
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) {

0 commit comments

Comments
 (0)