mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Add account state by transaction and emulator (extended) (#592)
* account_state_by_transaction * Correct time calculation * Bug fixes * Refactor * namespace block::transaction * smc.forget * RunEmulator: remove wallet_id * Refactor & fixes * AccountStateByTransaction: use shardchain block instead of masterchain block * transaction emulator core * refactor * tx emulator major functionality * small format changes * readme * clean * return json, add support for init messages * tx emulator readme * refactor getConfigParam and getConfigAll * add shardchain_libs_boc parameter * option to change verbosity level of transaction emulator * fix deserializing ShardAccount with account_none * add mode needSpecialSmc when unpack config * emulator: block::Transaction -> block::transaction::Transaction * Refactor * emulator: Fix bug * emulator: Support for emulator-extern * emulator: Refactor * Return vm log and vm exit code. * fix build on macos, emulator_static added * adjust documentation * ignore_chksig for external messages * tvm emulator, run get method * Added more params for transaction emulator * Added setters for optional transaction emulator params, moved libs to a new setter * Added actions cell output to transaction emulator * fix tonlib build * refactoring, rand seed as hex size 64, tvm emulator send message * tvm send message, small refactoring * fix config decoding, rename * improve documentation * macos export symbols * Added run_get_method to transaction emulator emscipten wrapper * Fixed empty action list serialization * Changed actions list cell to serialize as json null instead of empty string in transaction emulator * stack as boc * log gas remaining * Fix prev_block_id * fix build errors * Refactor fetch_config_params * fix failing unwrap of optional rand_seed * lookup correct shard, choose prev_block based on account shard * fix tonlib android jni build --------- Co-authored-by: legaii <jgates.ardux@gmail.com> Co-authored-by: ms <dungeon666master@protonmail.com> Co-authored-by: krigga <krigga7@gmail.com>
This commit is contained in:
parent
adf67aa869
commit
3b3c25b654
32 changed files with 2095 additions and 158 deletions
|
@ -274,6 +274,10 @@ add_library(ton_crypto STATIC ${TON_CRYPTO_SOURCE})
|
|||
target_include_directories(ton_crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(ton_crypto PUBLIC ${OPENSSL_CRYPTO_LIBRARY} tdutils tddb_utils)
|
||||
if (USE_EMSCRIPTEN)
|
||||
target_link_options(ton_crypto PRIVATE -fexceptions)
|
||||
target_compile_options(ton_crypto PRIVATE -fexceptions)
|
||||
endif()
|
||||
if (NOT WIN32)
|
||||
find_library(DL dl)
|
||||
if (DL)
|
||||
|
|
|
@ -1000,7 +1000,7 @@ bool Account::skip_copy_depth_balance(vm::CellBuilder& cb, vm::CellSlice& cs) co
|
|||
}
|
||||
|
||||
const Account t_Account, t_AccountE{true};
|
||||
const RefTo<Account> t_Ref_Account;
|
||||
const RefTo<Account> t_Ref_AccountE{true};
|
||||
|
||||
bool ShardAccount::extract_account_state(Ref<vm::CellSlice> cs_ref, Ref<vm::Cell>& acc_state) {
|
||||
if (cs_ref.is_null()) {
|
||||
|
|
|
@ -536,7 +536,7 @@ struct Account final : TLB_Complex {
|
|||
};
|
||||
|
||||
extern const Account t_Account, t_AccountE;
|
||||
extern const RefTo<Account> t_Ref_Account;
|
||||
extern const RefTo<Account> t_Ref_AccountE;
|
||||
|
||||
struct AccountStatus final : TLB {
|
||||
enum { acc_state_uninit, acc_state_frozen, acc_state_active, acc_state_nonexist };
|
||||
|
@ -572,7 +572,7 @@ struct ShardAccount final : TLB_Complex {
|
|||
return cs.advance_ext(0x140, 1);
|
||||
}
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.advance(0x140) && t_Ref_Account.validate_skip(ops, cs, weak);
|
||||
return cs.advance(0x140) && t_Ref_AccountE.validate_skip(ops, cs, weak);
|
||||
}
|
||||
static bool unpack(vm::CellSlice& cs, Record& info) {
|
||||
return info.unpack(cs);
|
||||
|
|
|
@ -366,7 +366,7 @@ trans_merge_install$0111 split_info:SplitMergeInfo
|
|||
smc_info#076ef1ea actions:uint16 msgs_sent:uint16
|
||||
unixtime:uint32 block_lt:uint64 trans_lt:uint64
|
||||
rand_seed:bits256 balance_remaining:CurrencyCollection
|
||||
myself:MsgAddressInt = SmartContractInfo;
|
||||
myself:MsgAddressInt global_config:(Maybe Cell) = SmartContractInfo;
|
||||
//
|
||||
//
|
||||
out_list_empty$_ = OutList 0;
|
||||
|
|
|
@ -632,7 +632,6 @@ class Config {
|
|||
static td::Result<std::vector<int>> unpack_param_dict(vm::Dictionary& dict);
|
||||
static td::Result<std::vector<int>> unpack_param_dict(Ref<vm::Cell> dict_root);
|
||||
|
||||
protected:
|
||||
Config(int _mode) : mode(_mode) {
|
||||
config_addr.set_zero();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "block/block.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "crypto/openssl/rand.hpp"
|
||||
#include "td/utils/bits.h"
|
||||
#include "td/utils/uint128.h"
|
||||
#include "ton/ton-shard.h"
|
||||
|
@ -513,6 +514,7 @@ td::RefInt256 Account::compute_storage_fees(ton::UnixTime now, const std::vector
|
|||
return StoragePrices::compute_storage_fees(now, pricing, storage_stat, last_paid, is_special, is_masterchain());
|
||||
}
|
||||
|
||||
namespace transaction {
|
||||
Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now,
|
||||
Ref<vm::Cell> _inmsg)
|
||||
: trans_type(ttype)
|
||||
|
@ -745,6 +747,7 @@ bool Transaction::prepare_credit_phase() {
|
|||
total_fees += std::move(collected);
|
||||
return true;
|
||||
}
|
||||
} // namespace transaction
|
||||
|
||||
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit,
|
||||
td::RefInt256& delete_due_limit) {
|
||||
|
@ -837,6 +840,7 @@ td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
|
|||
: td::rshift(gas_price256 * (gas_used - flat_gas_limit), 16, 1) + flat_gas_price;
|
||||
}
|
||||
|
||||
namespace transaction {
|
||||
bool Transaction::compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig& cfg) {
|
||||
// Compute gas limits
|
||||
if (account.is_special) {
|
||||
|
@ -1057,13 +1061,21 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
std::unique_ptr<StringLoggerTail> logger;
|
||||
auto vm_log = vm::VmLog();
|
||||
if (cfg.with_vm_log) {
|
||||
logger = std::make_unique<StringLoggerTail>();
|
||||
size_t log_max_size = cfg.vm_log_verbosity > 0 ? 1024 * 1024 : 256;
|
||||
logger = std::make_unique<StringLoggerTail>(log_max_size);
|
||||
vm_log.log_interface = logger.get();
|
||||
vm_log.log_options = td::LogOptions(VERBOSITY_NAME(DEBUG), true, false);
|
||||
if (cfg.vm_log_verbosity > 1) {
|
||||
vm_log.log_mask |= vm::VmLog::ExecLocation;
|
||||
if (cfg.vm_log_verbosity > 2) {
|
||||
vm_log.log_mask |= vm::VmLog::DumpStack | vm::VmLog::GasRemaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
vm::VmState vm{new_code, 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_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
|
||||
vm.set_chksig_always_succeed(cfg.ignore_chksig);
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
|
||||
LOG(DEBUG) << "starting VM";
|
||||
|
@ -1338,6 +1350,7 @@ int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, c
|
|||
ap.spec_actions++;
|
||||
return 0;
|
||||
}
|
||||
} // namespace transaction
|
||||
|
||||
// msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
|
||||
// ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms
|
||||
|
@ -1372,6 +1385,7 @@ td::RefInt256 MsgPrices::get_next_part(td::RefInt256 total) const {
|
|||
return (std::move(total) * next_frac) >> 16;
|
||||
}
|
||||
|
||||
namespace transaction {
|
||||
bool Transaction::check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const {
|
||||
int t = (int)src_addr->prefetch_ulong(2);
|
||||
if (!t && src_addr->size_ext() == 2) {
|
||||
|
@ -1978,6 +1992,7 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
|
|||
bp.ok = true;
|
||||
return true;
|
||||
}
|
||||
} // namespace transaction
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -2033,6 +2048,7 @@ static td::optional<vm::CellStorageStat> try_update_storage_stat(const vm::CellS
|
|||
return new_stat;
|
||||
}
|
||||
|
||||
namespace transaction {
|
||||
bool Transaction::compute_state() {
|
||||
if (new_total_state.not_null()) {
|
||||
return true;
|
||||
|
@ -2460,6 +2476,7 @@ void Transaction::extract_out_msgs(std::vector<LtCellRef>& list) {
|
|||
list.emplace_back(start_lt + i + 1, std::move(out_msgs[i]));
|
||||
}
|
||||
}
|
||||
} // namespace transaction
|
||||
|
||||
void Account::push_transaction(Ref<vm::Cell> trans_root, ton::LogicalTime trans_lt) {
|
||||
transactions.emplace_back(trans_lt, std::move(trans_root));
|
||||
|
@ -2503,4 +2520,82 @@ bool Account::libraries_changed() const {
|
|||
}
|
||||
}
|
||||
|
||||
td::Status FetchConfigParams::fetch_config_params(const block::Config& config,
|
||||
Ref<vm::Cell>* old_mparams,
|
||||
std::vector<block::StoragePrices>* storage_prices,
|
||||
block::StoragePhaseConfig* storage_phase_cfg,
|
||||
td::BitArray<256>* rand_seed,
|
||||
block::ComputePhaseConfig* compute_phase_cfg,
|
||||
block::ActionPhaseConfig* action_phase_cfg,
|
||||
td::RefInt256* masterchain_create_fee,
|
||||
td::RefInt256* basechain_create_fee,
|
||||
ton::WorkchainId wc,
|
||||
ton::UnixTime now) {
|
||||
*old_mparams = config.get_config_param(9);
|
||||
{
|
||||
auto res = config.get_storage_prices();
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
*storage_prices = res.move_as_ok();
|
||||
}
|
||||
if (rand_seed->is_zero()) {
|
||||
// generate rand seed
|
||||
prng::rand_gen().strong_rand_bytes(rand_seed->data(), 32);
|
||||
LOG(DEBUG) << "block random seed set to " << rand_seed->to_hex();
|
||||
}
|
||||
TRY_RESULT(size_limits, config.get_size_limits_config());
|
||||
{
|
||||
// compute compute_phase_cfg / storage_phase_cfg
|
||||
auto cell = config.get_config_param(wc == ton::masterchainId ? 20 : 21);
|
||||
if (cell.is_null()) {
|
||||
return td::Status::Error(-668, "cannot fetch current gas prices and limits from masterchain configuration");
|
||||
}
|
||||
if (!compute_phase_cfg->parse_GasLimitsPrices(std::move(cell), storage_phase_cfg->freeze_due_limit,
|
||||
storage_phase_cfg->delete_due_limit)) {
|
||||
return td::Status::Error(-668, "cannot unpack current gas prices and limits from masterchain configuration");
|
||||
}
|
||||
compute_phase_cfg->block_rand_seed = *rand_seed;
|
||||
compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth;
|
||||
compute_phase_cfg->global_config = config.get_root_cell();
|
||||
compute_phase_cfg->suspended_addresses = config.get_suspended_addresses(now);
|
||||
}
|
||||
{
|
||||
// compute action_phase_cfg
|
||||
block::gen::MsgForwardPrices::Record rec;
|
||||
auto cell = config.get_config_param(24);
|
||||
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
|
||||
return td::Status::Error(-668, "cannot fetch masterchain message transfer prices from masterchain configuration");
|
||||
}
|
||||
action_phase_cfg->fwd_mc =
|
||||
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
|
||||
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
|
||||
cell = config.get_config_param(25);
|
||||
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
|
||||
return td::Status::Error(-668, "cannot fetch standard message transfer prices from masterchain configuration");
|
||||
}
|
||||
action_phase_cfg->fwd_std =
|
||||
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
|
||||
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
|
||||
action_phase_cfg->workchains = &config.get_workchain_list();
|
||||
action_phase_cfg->bounce_msg_body = (config.has_capability(ton::capBounceMsgBody) ? 256 : 0);
|
||||
action_phase_cfg->size_limits = size_limits;
|
||||
}
|
||||
{
|
||||
// fetch block_grams_created
|
||||
auto cell = config.get_config_param(14);
|
||||
if (cell.is_null()) {
|
||||
*basechain_create_fee = *masterchain_create_fee = td::zero_refint();
|
||||
} else {
|
||||
block::gen::BlockCreateFees::Record create_fees;
|
||||
if (!(tlb::unpack_cell(cell, create_fees) &&
|
||||
block::tlb::t_Grams.as_integer_to(create_fees.masterchain_block_fee, *masterchain_create_fee) &&
|
||||
block::tlb::t_Grams.as_integer_to(create_fees.basechain_block_fee, *basechain_create_fee))) {
|
||||
return td::Status::Error(-668, "cannot unpack BlockCreateFees from configuration parameter #14");
|
||||
}
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
} // namespace block
|
||||
|
|
|
@ -35,7 +35,10 @@ using td::Ref;
|
|||
using LtCellRef = std::pair<ton::LogicalTime, Ref<vm::Cell>>;
|
||||
|
||||
struct Account;
|
||||
|
||||
namespace transaction {
|
||||
struct Transaction;
|
||||
} // namespace transaction
|
||||
|
||||
struct CollatorError {
|
||||
std::string msg;
|
||||
|
@ -106,9 +109,11 @@ struct ComputePhaseConfig {
|
|||
std::unique_ptr<vm::Dictionary> libraries;
|
||||
Ref<vm::Cell> global_config;
|
||||
td::BitArray<256> block_rand_seed;
|
||||
bool ignore_chksig{false};
|
||||
bool with_vm_log{false};
|
||||
td::uint16 max_vm_data_depth = 512;
|
||||
std::unique_ptr<vm::Dictionary> suspended_addresses;
|
||||
int vm_log_verbosity = 0;
|
||||
ComputePhaseConfig(td::uint64 _gas_price = 0, td::uint64 _gas_limit = 0, td::uint64 _gas_credit = 0)
|
||||
: gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_gas_limit), gas_credit(_gas_credit) {
|
||||
compute_threshold();
|
||||
|
@ -273,7 +278,7 @@ struct Account {
|
|||
bool create_account_block(vm::CellBuilder& cb); // stores an AccountBlock with all transactions
|
||||
|
||||
protected:
|
||||
friend struct Transaction;
|
||||
friend struct transaction::Transaction;
|
||||
bool set_split_depth(int split_depth);
|
||||
bool check_split_depth(int split_depth) const;
|
||||
bool forget_split_depth();
|
||||
|
@ -288,6 +293,7 @@ struct Account {
|
|||
bool compute_my_addr(bool force = false);
|
||||
};
|
||||
|
||||
namespace transaction {
|
||||
struct Transaction {
|
||||
enum {
|
||||
tr_none,
|
||||
|
@ -390,5 +396,20 @@ struct Transaction {
|
|||
bool serialize_bounce_phase(vm::CellBuilder& cb);
|
||||
bool unpack_msg_state(bool lib_only = false);
|
||||
};
|
||||
} // namespace transaction
|
||||
|
||||
struct FetchConfigParams {
|
||||
static td::Status fetch_config_params(const block::Config& config,
|
||||
Ref<vm::Cell>* old_mparams,
|
||||
std::vector<block::StoragePrices>* storage_prices,
|
||||
StoragePhaseConfig* storage_phase_cfg,
|
||||
td::BitArray<256>* rand_seed,
|
||||
ComputePhaseConfig* compute_phase_cfg,
|
||||
ActionPhaseConfig* action_phase_cfg,
|
||||
td::RefInt256* masterchain_create_fee,
|
||||
td::RefInt256* basechain_create_fee,
|
||||
ton::WorkchainId wc,
|
||||
ton::UnixTime now);
|
||||
};
|
||||
|
||||
} // namespace block
|
||||
|
|
|
@ -54,7 +54,11 @@ td::Ref<vm::Stack> prepare_vm_stack(td::RefInt256 amount, td::Ref<vm::CellSlice>
|
|||
|
||||
td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
|
||||
td::BitArray<256> rand_seed;
|
||||
rand_seed.as_slice().fill(0);
|
||||
if (args.rand_seed) {
|
||||
rand_seed = args.rand_seed.unwrap();
|
||||
} else {
|
||||
rand_seed.as_slice().fill(0);
|
||||
}
|
||||
td::RefInt256 rand_seed_int{true};
|
||||
rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false);
|
||||
|
||||
|
@ -96,7 +100,7 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
|
|||
}
|
||||
|
||||
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
|
||||
vm::GasLimits gas, bool ignore_chksig, td::Ref<vm::Cell> libraries) {
|
||||
vm::GasLimits gas, bool ignore_chksig, td::Ref<vm::Cell> libraries, int vm_log_verbosity) {
|
||||
auto gas_credit = gas.gas_credit;
|
||||
vm::init_op_cp0();
|
||||
vm::DictionaryBase::get_empty_dictionary();
|
||||
|
@ -109,15 +113,12 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
std::string res;
|
||||
};
|
||||
Logger logger;
|
||||
vm::VmLog log{&logger, td::LogOptions::plain()};
|
||||
|
||||
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
|
||||
log.log_options.level = 4;
|
||||
log.log_options.fix_newlines = true;
|
||||
log.log_mask |= vm::VmLog::DumpStack;
|
||||
} else {
|
||||
log.log_options.level = 0;
|
||||
log.log_mask = 0;
|
||||
vm::VmLog log{&logger, td::LogOptions(VERBOSITY_NAME(DEBUG), true, false)};
|
||||
if (vm_log_verbosity > 1) {
|
||||
log.log_mask |= vm::VmLog::ExecLocation;
|
||||
if (vm_log_verbosity > 2) {
|
||||
log.log_mask |= vm::VmLog::DumpStack | vm::VmLog::GasRemaining;
|
||||
}
|
||||
}
|
||||
|
||||
SmartContract::Answer res;
|
||||
|
@ -137,13 +138,13 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
} catch (...) {
|
||||
LOG(FATAL) << "catch unhandled exception";
|
||||
}
|
||||
td::ConstBitPtr mlib = vm.get_missing_library();
|
||||
res.new_state = std::move(state);
|
||||
res.stack = vm.get_stack_ref();
|
||||
gas = vm.get_gas_limits();
|
||||
res.gas_used = gas.gas_consumed();
|
||||
res.accepted = gas.gas_credit == 0;
|
||||
res.success = (res.accepted && (unsigned)res.code <= 1);
|
||||
res.vm_log = logger.res;
|
||||
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
|
||||
LOG(DEBUG) << "VM log\n" << logger.res;
|
||||
std::ostringstream os;
|
||||
|
@ -153,6 +154,7 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
LOG(DEBUG) << "VM accepted: " << res.accepted;
|
||||
LOG(DEBUG) << "VM success: " << res.success;
|
||||
}
|
||||
td::ConstBitPtr mlib = vm.get_missing_library();
|
||||
if (!mlib.is_null()) {
|
||||
LOG(DEBUG) << "Missing library: " << mlib.to_hex(256);
|
||||
res.missing_library = mlib;
|
||||
|
@ -219,7 +221,7 @@ SmartContract::Answer SmartContract::run_method(Args args) {
|
|||
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
||||
auto res =
|
||||
run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig,
|
||||
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{});
|
||||
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{}, args.vm_log_verbosity_level);
|
||||
state_ = res.new_state;
|
||||
return res;
|
||||
}
|
||||
|
@ -237,7 +239,7 @@ SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
|||
CHECK(args.method_id);
|
||||
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
||||
return run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig,
|
||||
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{});
|
||||
args.libraries ? args.libraries.unwrap().get_root_cell() : td::Ref<vm::Cell>{}, args.vm_log_verbosity_level);
|
||||
}
|
||||
|
||||
SmartContract::Answer SmartContract::run_get_method(td::Slice method, Args args) const {
|
||||
|
|
|
@ -50,6 +50,7 @@ class SmartContract : public td::CntObject {
|
|||
td::int32 code;
|
||||
td::int64 gas_used;
|
||||
td::ConstBitPtr missing_library{0};
|
||||
std::string vm_log;
|
||||
static int output_actions_count(td::Ref<vm::Cell> list);
|
||||
};
|
||||
|
||||
|
@ -59,9 +60,11 @@ class SmartContract : public td::CntObject {
|
|||
td::optional<td::Ref<vm::Tuple>> c7;
|
||||
td::optional<td::Ref<vm::Stack>> stack;
|
||||
td::optional<td::int32> now;
|
||||
td::optional<td::BitArray<256>> rand_seed;
|
||||
bool ignore_chksig{false};
|
||||
td::uint64 amount{0};
|
||||
td::uint64 balance{0};
|
||||
int vm_log_verbosity_level{0};
|
||||
|
||||
td::optional<block::StdAddress> address;
|
||||
td::optional<std::shared_ptr<const block::Config>> config;
|
||||
|
@ -100,6 +103,10 @@ class SmartContract : public td::CntObject {
|
|||
this->stack = std::move(stack);
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_rand_seed(td::BitArray<256> rand_seed) {
|
||||
this->rand_seed = std::move(rand_seed);
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_ignore_chksig(bool ignore_chksig) {
|
||||
this->ignore_chksig = ignore_chksig;
|
||||
return std::move(*this);
|
||||
|
@ -124,6 +131,10 @@ class SmartContract : public td::CntObject {
|
|||
this->libraries = libraries;
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_vm_verbosity_level(int vm_log_verbosity_level) {
|
||||
this->vm_log_verbosity_level = vm_log_verbosity_level;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
td::Result<td::int32> get_method_id() const {
|
||||
if (!method_id) {
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace vm {
|
|||
struct VmLog {
|
||||
td::LogInterface *log_interface{td::log_interface};
|
||||
td::LogOptions log_options{td::log_options};
|
||||
enum { DumpStack = 2 };
|
||||
enum { DumpStack = 2, ExecLocation = 4, GasRemaining = 8 };
|
||||
int log_mask{1};
|
||||
static VmLog Null() {
|
||||
VmLog res;
|
||||
|
|
|
@ -433,18 +433,24 @@ void VmState::change_gas_limit(long long new_limit) {
|
|||
|
||||
int VmState::step() {
|
||||
CHECK(code.not_null() && stack.not_null());
|
||||
//VM_LOG(st) << "stack:"; stack->dump(VM_LOG(st));
|
||||
//VM_LOG(st) << "; cr0.refcnt = " << get_c0()->get_refcnt() - 1 << std::endl;
|
||||
if (log.log_mask & vm::VmLog::DumpStack) {
|
||||
std::stringstream ss;
|
||||
stack->dump(ss, 3);
|
||||
VM_LOG(this) << "stack:" << ss.str();
|
||||
}
|
||||
if (stack_trace) {
|
||||
stack->dump(std::cerr, 3);
|
||||
}
|
||||
++steps;
|
||||
if (code->size()) {
|
||||
VM_LOG_MASK(this, vm::VmLog::ExecLocation) << "code cell hash: " << code->get_base_cell()->get_hash().to_hex() << " offset: " << code->cur_pos();
|
||||
return dispatch->dispatch(this, code.write());
|
||||
} else if (code->size_refs()) {
|
||||
VM_LOG(this) << "execute implicit JMPREF";
|
||||
auto ref_cell = code->prefetch_ref();
|
||||
VM_LOG_MASK(this, vm::VmLog::ExecLocation) << "code cell hash: " << ref_cell->get_hash().to_hex() << " offset: 0";
|
||||
gas.consume_chk(implicit_jmpref_gas_price);
|
||||
Ref<Continuation> cont = Ref<OrdCont>{true, load_cell_slice_ref(code->prefetch_ref()), get_cp()};
|
||||
Ref<Continuation> cont = Ref<OrdCont>{true, load_cell_slice_ref(std::move(ref_cell)), get_cp()};
|
||||
return jump(std::move(cont));
|
||||
} else {
|
||||
VM_LOG(this) << "execute implicit RET";
|
||||
|
@ -465,6 +471,7 @@ int VmState::run() {
|
|||
try {
|
||||
try {
|
||||
res = step();
|
||||
VM_LOG_MASK(this, vm::VmLog::GasRemaining) << "gas remaining: " << gas.gas_remaining;
|
||||
gas.check();
|
||||
} catch (vm::CellBuilder::CellWriteError) {
|
||||
throw VmError{Excno::cell_ov};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue