mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
commit
fe46f0e238
13 changed files with 147 additions and 81 deletions
|
@ -2292,7 +2292,8 @@ Ref<vm::Cell> ConfigInfo::lookup_library(td::ConstBitPtr root_hash) const {
|
|||
td::Result<Ref<vm::Tuple>> ConfigInfo::get_prev_blocks_info() const {
|
||||
// [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
|
||||
// [ last_mc_blocks:[BlockId...]
|
||||
// prev_key_block:BlockId ] : PrevBlocksInfo
|
||||
// prev_key_block:BlockId
|
||||
// last_mc_blocks_100[BlockId...] ] : PrevBlocksInfo
|
||||
auto block_id_to_tuple = [](const ton::BlockIdExt& block_id) -> vm::Ref<vm::Tuple> {
|
||||
td::RefInt256 shard = td::make_refint(block_id.id.shard);
|
||||
if (shard->sgn() < 0) {
|
||||
|
@ -2302,25 +2303,44 @@ td::Result<Ref<vm::Tuple>> ConfigInfo::get_prev_blocks_info() const {
|
|||
td::make_refint(block_id.id.seqno), td::bits_to_refint(block_id.root_hash.bits(), 256),
|
||||
td::bits_to_refint(block_id.file_hash.bits(), 256));
|
||||
};
|
||||
std::vector<vm::StackEntry> last_mc_blocks;
|
||||
std::vector<vm::StackEntry> tuple;
|
||||
|
||||
std::vector<vm::StackEntry> last_mc_blocks;
|
||||
last_mc_blocks.push_back(block_id_to_tuple(block_id));
|
||||
for (ton::BlockSeqno seqno = block_id.id.seqno; seqno > 0 && last_mc_blocks.size() < 16;) {
|
||||
--seqno;
|
||||
ton::BlockIdExt block_id;
|
||||
if (!get_old_mc_block_id(seqno, block_id)) {
|
||||
ton::BlockIdExt id;
|
||||
if (!get_old_mc_block_id(seqno, id)) {
|
||||
return td::Status::Error("cannot fetch old mc block");
|
||||
}
|
||||
last_mc_blocks.push_back(block_id_to_tuple(block_id));
|
||||
last_mc_blocks.push_back(block_id_to_tuple(id));
|
||||
}
|
||||
tuple.push_back(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks)));
|
||||
|
||||
ton::BlockIdExt last_key_block;
|
||||
ton::LogicalTime last_key_block_lt;
|
||||
if (!get_last_key_block(last_key_block, last_key_block_lt)) {
|
||||
return td::Status::Error("cannot fetch last key block");
|
||||
}
|
||||
return vm::make_tuple_ref(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks)),
|
||||
block_id_to_tuple(last_key_block));
|
||||
tuple.push_back(block_id_to_tuple(last_key_block));
|
||||
|
||||
if (get_global_version() >= 9) {
|
||||
std::vector<vm::StackEntry> last_mc_blocks_100;
|
||||
for (ton::BlockSeqno seqno = block_id.id.seqno / 100 * 100; last_mc_blocks_100.size() < 16;) {
|
||||
ton::BlockIdExt id;
|
||||
if (!get_old_mc_block_id(seqno, id)) {
|
||||
return td::Status::Error("cannot fetch old mc block");
|
||||
}
|
||||
last_mc_blocks_100.push_back(block_id_to_tuple(id));
|
||||
if (seqno < 100) {
|
||||
break;
|
||||
}
|
||||
seqno -= 100;
|
||||
}
|
||||
tuple.push_back(td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(last_mc_blocks_100)));
|
||||
}
|
||||
|
||||
return td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
|
||||
}
|
||||
|
||||
td::optional<PrecompiledContractsConfig::Contract> PrecompiledContractsConfig::get_contract(
|
||||
|
|
|
@ -1145,31 +1145,64 @@ td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
|
|||
namespace transaction {
|
||||
|
||||
/**
|
||||
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) to special_gas_limit * 2
|
||||
* from masterchain GasLimitsPrices config for the transaction.
|
||||
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) for the transaction
|
||||
*
|
||||
* In January 2024 a highload wallet of @wallet Telegram bot in mainnet was stuck because current gas limit (1M) is
|
||||
* 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-29).
|
||||
* It was proposed to validators to increase gas limit for this account to 70M 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.
|
||||
*
|
||||
* In Augost 2024 it was decided to unlock other old highload wallets that got into the same situation.
|
||||
* See https://t.me/tondev_news/129
|
||||
* It is activated by setting global version to 9.
|
||||
*
|
||||
* @param cfg The compute phase configuration.
|
||||
* @param now The Unix time of the transaction.
|
||||
* @param account The account of the transaction.
|
||||
*
|
||||
* @returns True if gas_limit override is required, false otherwise
|
||||
* @returns Overridden gas limit or empty td::optional
|
||||
*/
|
||||
static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) {
|
||||
if (!cfg.special_gas_full) {
|
||||
return false;
|
||||
static td::optional<td::uint64> override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now,
|
||||
const Account& account) {
|
||||
struct OverridenGasLimit {
|
||||
td::uint64 new_limit;
|
||||
int from_version;
|
||||
ton::UnixTime until;
|
||||
};
|
||||
static std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, OverridenGasLimit> accounts = []() {
|
||||
auto parse_addr = [](const char* s) -> std::pair<ton::WorkchainId, ton::StdSmcAddress> {
|
||||
auto r_addr = StdAddress::parse(td::Slice(s));
|
||||
r_addr.ensure();
|
||||
return {r_addr.ok().workchain, r_addr.ok().addr};
|
||||
};
|
||||
std::map<std::pair<ton::WorkchainId, ton::StdSmcAddress>, OverridenGasLimit> accounts;
|
||||
|
||||
// Increase limit for EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu until 2024-02-29 00:00:00 UTC
|
||||
accounts[parse_addr("0:FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD")] = {
|
||||
.new_limit = 70'000'000, .from_version = 5, .until = 1709164800};
|
||||
|
||||
// Increase limit for multiple accounts (https://t.me/tondev_news/129) until 2025-03-01 00:00:00 UTC
|
||||
accounts[parse_addr("UQBeSl-dumOHieZ3DJkNKVkjeso7wZ0VpzR4LCbLGTQ8xr57")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQC3VcQ-43klww9UfimR58TBjBzk7GPupXQ3CNuthoNp-uTR")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQBhwBb8jvokGvfreHRRoeVxI237PrOJgyrsAhLA-4rBC_H5")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQCkoRp4OE-SFUoMEnYfL3vF43T3AzNfW8jyTC4yzk8cJqMS")] = {
|
||||
.new_limit = 70'000'000, .from_version = 9, .until = 1740787200};
|
||||
accounts[parse_addr("EQBDanbCeUqI4_v-xrnAN0_I2wRvEIaLg1Qg2ZN5c6Zl1KOh")] = {
|
||||
.new_limit = 225'000'000, .from_version = 9, .until = 1740787200};
|
||||
return accounts;
|
||||
}();
|
||||
auto it = accounts.find({account.workchain, account.addr});
|
||||
if (it == accounts.end() || cfg.global_version < it->second.from_version || now >= it->second.until) {
|
||||
return {};
|
||||
}
|
||||
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;
|
||||
return it->second.new_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1183,10 +1216,12 @@ static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now,
|
|||
* @returns The amount of gas.
|
||||
*/
|
||||
td::uint64 Transaction::gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms) {
|
||||
if (override_gas_limit(cfg, now, account)) {
|
||||
if (auto new_limit = override_gas_limit(cfg, now, account)) {
|
||||
gas_limit_overridden = true;
|
||||
// Same as ComputePhaseConfig::gas_bought for, but with other gas_limit and max_gas_threshold
|
||||
auto gas_limit = cfg.mc_gas_prices.special_gas_limit * 2;
|
||||
auto gas_limit = new_limit.value();
|
||||
LOG(INFO) << "overridding gas limit for account " << account.workchain << ":" << account.addr.to_hex() << " to "
|
||||
<< gas_limit;
|
||||
auto max_gas_threshold =
|
||||
compute_max_gas_threshold(cfg.gas_price256, gas_limit, cfg.flat_gas_limit, cfg.flat_gas_price);
|
||||
if (nanograms.is_null() || sgn(nanograms) < 0) {
|
||||
|
@ -1336,7 +1371,8 @@ Ref<vm::Tuple> Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const {
|
|||
// See crypto/block/mc-config.cpp#2223 (get_prev_blocks_info)
|
||||
// [ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer] = BlockId;
|
||||
// [ last_mc_blocks:[BlockId...]
|
||||
// prev_key_block:BlockId ] : PrevBlocksInfo
|
||||
// prev_key_block:BlockId
|
||||
// last_mc_blocks_100:[BlockId...] ] : PrevBlocksInfo
|
||||
// The only context where PrevBlocksInfo (13 parameter of c7) is null is inside emulator
|
||||
// where it need to be set via transaction_emulator_set_prev_blocks_info (see emulator/emulator-extern.cpp)
|
||||
// Inside validator, collator and liteserver checking external message contexts
|
||||
|
@ -1691,9 +1727,8 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
}
|
||||
}
|
||||
}
|
||||
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
|
||||
vm::VmState vm{new_code, cfg.global_version, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
|
||||
vm.set_max_data_depth(cfg.max_vm_data_depth);
|
||||
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);
|
||||
|
|
|
@ -1312,6 +1312,7 @@ x{F832} @Defop CONFIGPARAM
|
|||
x{F833} @Defop CONFIGOPTPARAM
|
||||
x{F83400} @Defop PREVMCBLOCKS
|
||||
x{F83401} @Defop PREVKEYBLOCK
|
||||
x{F83402} @Defop PREVMCBLOCKS_100
|
||||
x{F835} @Defop GLOBALID
|
||||
x{F836} @Defop GETGASFEE
|
||||
x{F837} @Defop GETSTORAGEFEE
|
||||
|
|
|
@ -223,14 +223,14 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
stack->dump(os, 2);
|
||||
LOG(DEBUG) << "VM stack:\n" << os.str();
|
||||
}
|
||||
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
|
||||
int global_version = config ? config->get_global_version() : 0;
|
||||
vm::VmState vm{state.code, global_version, std::move(stack), gas, 1, state.data, log};
|
||||
vm.set_c7(std::move(c7));
|
||||
vm.set_chksig_always_succeed(ignore_chksig);
|
||||
if (!libraries.is_null()) {
|
||||
vm.register_library_collection(libraries);
|
||||
}
|
||||
if (config) {
|
||||
vm.set_global_version(config->get_global_version());
|
||||
auto r_limits = config->get_size_limits_config();
|
||||
if (r_limits.is_ok()) {
|
||||
vm.set_max_data_depth(r_limits.ok().max_vm_data_depth);
|
||||
|
|
|
@ -261,10 +261,10 @@ int exec_runvm_common(VmState* st, unsigned mode) {
|
|||
vm::GasLimits gas{gas_limit, gas_max};
|
||||
|
||||
VmStateInterface::Guard guard{nullptr}; // Don't consume gas for creating/loading cells during VM init
|
||||
VmState new_state{std::move(code), std::move(new_stack), gas, (int)mode & 3, std::move(data),
|
||||
VmLog{}, std::vector<Ref<Cell>>{}, std::move(c7)};
|
||||
VmState new_state{
|
||||
std::move(code), st->get_global_version(), std::move(new_stack), gas, (int)mode & 3, std::move(data),
|
||||
VmLog{}, std::vector<Ref<Cell>>{}, std::move(c7)};
|
||||
new_state.set_chksig_always_succeed(st->get_chksig_always_succeed());
|
||||
new_state.set_global_version(st->get_global_version());
|
||||
st->run_child_vm(std::move(new_state), with_data, mode & 32, mode & 8, mode & 128, ret_vals);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -566,7 +566,7 @@ int exec_dict_getnear(VmState* st, unsigned args) {
|
|||
int exec_pfx_dict_set(VmState* st, Dictionary::SetMode mode, const char* name) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute PFXDICT" << name;
|
||||
stack.check_underflow(3);
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 4 : 3);
|
||||
int n = stack.pop_smallint_range(PrefixDictionary::max_key_bits);
|
||||
PrefixDictionary dict{stack.pop_maybe_cell(), n};
|
||||
auto key_slice = stack.pop_cellslice();
|
||||
|
@ -580,7 +580,7 @@ int exec_pfx_dict_set(VmState* st, Dictionary::SetMode mode, const char* name) {
|
|||
int exec_pfx_dict_delete(VmState* st) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute PFXDICTDEL\n";
|
||||
stack.check_underflow(2);
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 2);
|
||||
int n = stack.pop_smallint_range(PrefixDictionary::max_key_bits);
|
||||
PrefixDictionary dict{stack.pop_maybe_cell(), n};
|
||||
auto key_slice = stack.pop_cellslice();
|
||||
|
|
|
@ -279,6 +279,7 @@ int exec_get_global_id(VmState* st) {
|
|||
int exec_get_gas_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETGASFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 gas = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
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) {
|
|||
int exec_get_storage_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETSTORAGEFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 4 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::int64 delta = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
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) {
|
|||
int exec_get_forward_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETFORWARDFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
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) {
|
|||
int exec_get_original_fwd_fee(VmState* st) {
|
||||
VM_LOG(st) << "execute GETORIGINALFWDFEE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::RefInt256 fwd_fee = stack.pop_int_finite();
|
||||
if (fwd_fee->sgn() < 0) {
|
||||
|
@ -333,6 +337,7 @@ int exec_get_original_fwd_fee(VmState* st) {
|
|||
int exec_get_gas_fee_simple(VmState* st) {
|
||||
VM_LOG(st) << "execute GETGASFEESIMPLE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 gas = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
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) {
|
|||
int exec_get_forward_fee_simple(VmState* st) {
|
||||
VM_LOG(st) << "execute GETFORWARDFEESIMPLE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 3 : 0);
|
||||
bool is_masterchain = stack.pop_bool();
|
||||
td::uint64 bits = stack.pop_long_range(std::numeric_limits<td::int64>::max(), 0);
|
||||
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) {
|
|||
.insert(OpcodeInstr::mksimple(0xf833, 16, "CONFIGOPTPARAM", std::bind(exec_get_config_param, _1, true)))
|
||||
.insert(OpcodeInstr::mksimple(0xf83400, 24, "PREVMCBLOCKS", std::bind(exec_get_prev_blocks_info, _1, 0, "PREVMCBLOCKS"))->require_version(4))
|
||||
.insert(OpcodeInstr::mksimple(0xf83401, 24, "PREVKEYBLOCK", std::bind(exec_get_prev_blocks_info, _1, 1, "PREVKEYBLOCK"))->require_version(4))
|
||||
.insert(OpcodeInstr::mksimple(0xf83402, 24, "PREVMCBLOCKS_100", std::bind(exec_get_prev_blocks_info, _1, 2, "PREVMCBLOCKS_100"))->require_version(9))
|
||||
.insert(OpcodeInstr::mksimple(0xf835, 16, "GLOBALID", exec_get_global_id)->require_version(4))
|
||||
.insert(OpcodeInstr::mksimple(0xf836, 16, "GETGASFEE", exec_get_gas_fee)->require_version(6))
|
||||
.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) {
|
|||
VM_LOG(st) << "execute HASHEXT" << (append ? "A" : "") << (rev ? "R" : "") << " " << (hash_id == 255 ? -1 : hash_id);
|
||||
Stack& stack = st->get_stack();
|
||||
if (hash_id == 255) {
|
||||
stack.check_underflow(st->get_global_version() >= 9 ? 2 : 0);
|
||||
hash_id = stack.pop_smallint_range(254);
|
||||
}
|
||||
int cnt = stack.pop_smallint_range(stack.depth() - 1);
|
||||
int cnt = stack.pop_smallint_range(stack.depth() - 1 - (st->get_global_version() >= 9 ? (int)append : 0));
|
||||
Hasher hasher{hash_id};
|
||||
size_t total_bits = 0;
|
||||
long long gas_consumed = 0;
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "vm/log.h"
|
||||
#include "vm/vm.h"
|
||||
#include "cp0.h"
|
||||
#include "memo.h"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
namespace vm {
|
||||
|
@ -31,33 +33,8 @@ VmState::VmState() : cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), qu
|
|||
init_cregs();
|
||||
}
|
||||
|
||||
VmState::VmState(Ref<CellSlice> _code)
|
||||
: code(std::move(_code)), cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) {
|
||||
ensure_throw(init_cp(0));
|
||||
init_cregs();
|
||||
}
|
||||
|
||||
VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, int flags, Ref<Cell> _data, VmLog log,
|
||||
std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
|
||||
: code(std::move(_code))
|
||||
, stack(std::move(_stack))
|
||||
, cp(-1)
|
||||
, dispatch(&dummy_dispatch_table)
|
||||
, quit0(true, 0)
|
||||
, quit1(true, 1)
|
||||
, log(log)
|
||||
, libraries(std::move(_libraries))
|
||||
, stack_trace((flags >> 2) & 1) {
|
||||
ensure_throw(init_cp(0));
|
||||
set_c4(std::move(_data));
|
||||
if (init_c7.not_null()) {
|
||||
set_c7(std::move(init_c7));
|
||||
}
|
||||
init_cregs(flags & 1, flags & 2);
|
||||
}
|
||||
|
||||
VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas, int flags, Ref<Cell> _data, VmLog log,
|
||||
std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
|
||||
VmState::VmState(Ref<CellSlice> _code, int global_version, Ref<Stack> _stack, const GasLimits& gas, int flags,
|
||||
Ref<Cell> _data, VmLog log, std::vector<Ref<Cell>> _libraries, Ref<Tuple> init_c7)
|
||||
: code(std::move(_code))
|
||||
, stack(std::move(_stack))
|
||||
, cp(-1)
|
||||
|
@ -67,7 +44,8 @@ VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas,
|
|||
, log(log)
|
||||
, gas(gas)
|
||||
, libraries(std::move(_libraries))
|
||||
, stack_trace((flags >> 2) & 1) {
|
||||
, stack_trace((flags >> 2) & 1)
|
||||
, global_version(global_version) {
|
||||
ensure_throw(init_cp(0));
|
||||
set_c4(std::move(_data));
|
||||
if (init_c7.not_null()) {
|
||||
|
@ -102,12 +80,24 @@ void VmState::init_cregs(bool same_c3, bool push_0) {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell) {
|
||||
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell, int global_version,
|
||||
const std::vector<Ref<Cell>>& libraries) {
|
||||
if (code_cell.is_null()) {
|
||||
return {};
|
||||
}
|
||||
Ref<CellSlice> csr{true, NoVmOrd(), code_cell};
|
||||
if (csr->is_valid()) {
|
||||
Ref<CellSlice> csr;
|
||||
if (global_version >= 9) {
|
||||
// Use DummyVmState instead of this to avoid consuming gas for cell loading
|
||||
DummyVmState dummy{libraries, global_version};
|
||||
Guard guard(&dummy);
|
||||
try {
|
||||
csr = load_cell_slice_ref(code_cell);
|
||||
} catch (VmError&) { // NOLINT(*-empty-catch)
|
||||
}
|
||||
} else {
|
||||
csr = td::Ref<CellSlice>{true, NoVmOrd(), code_cell};
|
||||
}
|
||||
if (csr.not_null() && csr->is_valid()) {
|
||||
return csr;
|
||||
}
|
||||
return load_cell_slice_ref(CellBuilder{}.store_ref(std::move(code_cell)).finalize());
|
||||
|
@ -577,6 +567,7 @@ int run_vm_code(Ref<CellSlice> code, Ref<Stack>& stack, int flags, Ref<Cell>* da
|
|||
GasLimits* gas_limits, std::vector<Ref<Cell>> libraries, Ref<Tuple> init_c7, Ref<Cell>* actions_ptr,
|
||||
int global_version) {
|
||||
VmState vm{code,
|
||||
global_version,
|
||||
std::move(stack),
|
||||
gas_limits ? *gas_limits : GasLimits{},
|
||||
flags,
|
||||
|
@ -584,7 +575,6 @@ int run_vm_code(Ref<CellSlice> code, Ref<Stack>& stack, int flags, Ref<Cell>* da
|
|||
log,
|
||||
std::move(libraries),
|
||||
std::move(init_c7)};
|
||||
vm.set_global_version(global_version);
|
||||
int res = vm.run();
|
||||
stack = vm.get_stack_ref();
|
||||
if (vm.committed() && data_ptr) {
|
||||
|
|
|
@ -164,14 +164,12 @@ class VmState final : public VmStateInterface {
|
|||
bls_pairing_element_gas_price = 11800
|
||||
};
|
||||
VmState();
|
||||
VmState(Ref<CellSlice> _code);
|
||||
VmState(Ref<CellSlice> _code, Ref<Stack> _stack, int flags = 0, Ref<Cell> _data = {}, VmLog log = {},
|
||||
std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {});
|
||||
VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0, Ref<Cell> _data = {},
|
||||
VmState(Ref<CellSlice> _code, int global_version, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0, Ref<Cell> _data = {},
|
||||
VmLog log = {}, std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {});
|
||||
template <typename... Args>
|
||||
VmState(Ref<Cell> code_cell, Args&&... args)
|
||||
: VmState(convert_code_cell(std::move(code_cell)), std::forward<Args>(args)...) {
|
||||
VmState(Ref<Cell> _code, int global_version, Ref<Stack> _stack, const GasLimits& _gas, int flags = 0,
|
||||
Ref<Cell> _data = {}, VmLog log = {}, std::vector<Ref<Cell>> _libraries = {}, Ref<Tuple> init_c7 = {})
|
||||
: VmState(convert_code_cell(std::move(_code), global_version, _libraries), global_version, std::move(_stack),
|
||||
_gas, flags, std::move(_data), std::move(log), _libraries, std::move(init_c7)) {
|
||||
}
|
||||
VmState(const VmState&) = delete;
|
||||
VmState(VmState&&) = default;
|
||||
|
@ -345,9 +343,6 @@ class VmState final : public VmStateInterface {
|
|||
int get_global_version() const override {
|
||||
return global_version;
|
||||
}
|
||||
void set_global_version(int version) {
|
||||
global_version = version;
|
||||
}
|
||||
int call(Ref<Continuation> cont);
|
||||
int call(Ref<Continuation> cont, int pass_args, int ret_args = -1);
|
||||
int jump(Ref<Continuation> cont);
|
||||
|
@ -382,7 +377,8 @@ class VmState final : public VmStateInterface {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
|
||||
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell, int global_version,
|
||||
const std::vector<Ref<Cell>>& libraries);
|
||||
bool try_commit();
|
||||
void force_commit();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ Global version is a parameter specified in `ConfigParam 8` ([block.tlb](https://
|
|||
Various features are enabled depending on the global version.
|
||||
|
||||
## Version 4
|
||||
New features of version 4 are desctibed in detail in [the documentation](https://docs.ton.org/v3/documentation/tvm/changelog/tvm-upgrade-2023-07).
|
||||
|
||||
### New TVM instructions
|
||||
* `PREVMCBLOCKS`, `PREVKEYBLOCK`
|
||||
|
@ -47,7 +48,7 @@ Version 5 enables higher gas limits for special contracts.
|
|||
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.
|
||||
* Gas limit on `EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu` is increased to 70M (`special_gas_limit * 2`) until 2024-02-29.
|
||||
See [this post](https://t.me/tonstatus/88) for details.
|
||||
|
||||
### Loading libraries
|
||||
|
@ -113,14 +114,23 @@ Operations for working with Merkle proofs, where cells can have non-zero level a
|
|||
|
||||
## Version 9
|
||||
|
||||
### c7 tuple
|
||||
c7 tuple parameter number **13** (previous blocks info tuple) now has the third element. It contains ids of the 16 last masterchain blocks with seqno divisible by 100.
|
||||
Example: if the last masterchain block seqno is `19071` then the list contains block ids with seqnos `19000`, `18900`, ..., `17500`.
|
||||
|
||||
### New TVM instructions
|
||||
- `SECP256K1_XONLY_PUBKEY_TWEAK_ADD` (`key tweak - 0 or f x y -1`) - performs [`secp256k1_xonly_pubkey_tweak_add`](https://github.com/bitcoin-core/secp256k1/blob/master/include/secp256k1_extrakeys.h#L120).
|
||||
`key` and `tweak` are 256-bit unsigned integers. 65-byte public key is returned as `uint8 f`, `uint256 x, y` (as in `ECRECOVER`). Gas cost: `1276`.
|
||||
- `mask SETCONTCTRMANY` (`cont - cont'`) - takes continuation, performs the equivalent of `c[i] PUSHCTR SWAP c[i] SETCONTCNR` for each `i` that is set in `mask` (mask is in `0..255`).
|
||||
- `SETCONTCTRMANYX` (`cont mask - cont'`) - same as `SETCONTCTRMANY`, but takes `mask` from stack.
|
||||
- `PREVMCBLOCKS_100` returns the third element of the previous block info tuple (see above).
|
||||
|
||||
### Other changes
|
||||
- Fix `RAWRESERVE` action with flag `4` (use original balance of the account) by explicitly setting `original_balance` to `balance - msg_balance_remaining`.
|
||||
- Previously it did not work if storage fee was greater than the original balance.
|
||||
- Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code).
|
||||
- Support extra currencies in reserve action with `+2` mode.
|
||||
- Support extra currencies in reserve action with `+2` mode.
|
||||
- Fix exception code in some TVM instructions: now `stk_und` has priority over other error codes.
|
||||
- `PFXDICTADD`, `PFXDICTSET`, `PFXDICTREPLACE`, `PFXDICTDEL`, `GETGASFEE`, `GETSTORAGEFEE`, `GETFORWARDFEE`, `GETORIGINALFWDFEE`, `GETGASFEESIMPLE`, `GETFORWARDFEESIMPLE`, `HASHEXT`
|
||||
- Now setting the contract code to a library cell does not consume additional gas on execution of the code.
|
||||
- Temporary increase gas limit for some accounts (see [this post](https://t.me/tondev_news/129) for details, `override_gas_limit` in `transaction.cpp` for the list of accounts).
|
|
@ -2227,7 +2227,7 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
// auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
|
||||
vm::GasLimits gas{gas_limit};
|
||||
LOG(DEBUG) << "creating VM";
|
||||
vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
|
||||
vm::VmState vm{code, ton::SUPPORTED_VERSION, std::move(stack), gas, 1, data, vm::VmLog()};
|
||||
vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()),
|
||||
balance)); // tuple with SmartContractInfo
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
|
|
|
@ -135,8 +135,8 @@ runInfo time_run_vm(td::Slice command, td::Ref<vm::Stack> stack) {
|
|||
CHECK(stack.is_unique());
|
||||
try {
|
||||
vm::GasLimits gas_limit;
|
||||
vm::VmState vm{vm::load_cell_slice_ref(cell), std::move(stack), gas_limit, 0, {}, vm::VmLog{}, {}, c7};
|
||||
vm.set_global_version(ton::SUPPORTED_VERSION);
|
||||
vm::VmState vm{
|
||||
vm::load_cell_slice_ref(cell), ton::SUPPORTED_VERSION, std::move(stack), gas_limit, 0, {}, vm::VmLog{}, {}, c7};
|
||||
std::clock_t cStart = std::clock();
|
||||
int ret = ~vm.run();
|
||||
std::clock_t cEnd = std::clock();
|
||||
|
|
|
@ -1520,11 +1520,17 @@ void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice
|
|||
libraries.push_back(acc_libs);
|
||||
}
|
||||
vm::GasLimits gas{gas_limit, gas_limit};
|
||||
vm::VmState vm{code, std::move(stack_), gas, 1, std::move(data), vm::VmLog::Null(), std::move(libraries)};
|
||||
vm::VmState vm{code,
|
||||
config->get_global_version(),
|
||||
std::move(stack_),
|
||||
gas,
|
||||
1,
|
||||
std::move(data),
|
||||
vm::VmLog::Null(),
|
||||
std::move(libraries)};
|
||||
auto c7 = prepare_vm_c7(gen_utime, gen_lt, td::make_ref<vm::CellSlice>(acc.addr->clone()), balance, config.get(),
|
||||
std::move(code), due_payment);
|
||||
vm.set_c7(c7); // tuple with SmartContractInfo
|
||||
vm.set_global_version(config->get_global_version());
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
LOG(INFO) << "starting VM to run GET-method of smart contract " << acc_workchain_ << ":" << acc_addr_.to_hex();
|
||||
// **** RUN VM ****
|
||||
|
|
Loading…
Reference in a new issue