mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
Fix returning config from LS, add extra c7 elements in getmethods (#713)
Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
parent
049ed0c737
commit
6b941dcceb
10 changed files with 111 additions and 32 deletions
|
@ -120,7 +120,7 @@ td::Ref<vm::Stack> prepare_vm_stack(td::RefInt256 amount, td::Ref<vm::CellSlice>
|
||||||
return stack_ref;
|
return stack_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
|
td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args, td::Ref<vm::Cell> code) {
|
||||||
td::BitArray<256> rand_seed;
|
td::BitArray<256> rand_seed;
|
||||||
if (args.rand_seed) {
|
if (args.rand_seed) {
|
||||||
rand_seed = args.rand_seed.unwrap();
|
rand_seed = args.rand_seed.unwrap();
|
||||||
|
@ -139,10 +139,7 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
|
||||||
if (args.address) {
|
if (args.address) {
|
||||||
td::BigInt256 dest_addr;
|
td::BigInt256 dest_addr;
|
||||||
dest_addr.import_bits((*args.address).addr.as_bitslice());
|
dest_addr.import_bits((*args.address).addr.as_bitslice());
|
||||||
cb.store_ones(1)
|
cb.store_ones(1).store_zeroes(2).store_long((*args.address).workchain, 8).store_int256(dest_addr, 256);
|
||||||
.store_zeroes(2)
|
|
||||||
.store_long((*args.address).workchain, 8)
|
|
||||||
.store_int256(dest_addr, 256);
|
|
||||||
}
|
}
|
||||||
auto address = cb.finalize();
|
auto address = cb.finalize();
|
||||||
auto config = td::Ref<vm::Cell>();
|
auto config = td::Ref<vm::Cell>();
|
||||||
|
@ -151,20 +148,32 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
|
||||||
config = (*args.config)->get_root_cell();
|
config = (*args.config)->get_root_cell();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tuple = vm::make_tuple_ref(
|
std::vector<vm::StackEntry> tuple = {
|
||||||
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
|
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
|
||||||
td::make_refint(0), // actions:Integer
|
td::make_refint(0), // actions:Integer
|
||||||
td::make_refint(0), // msgs_sent:Integer
|
td::make_refint(0), // msgs_sent:Integer
|
||||||
td::make_refint(now), // unixtime:Integer
|
td::make_refint(now), // unixtime:Integer
|
||||||
td::make_refint(0), //TODO: // block_lt:Integer
|
td::make_refint(0), //TODO: // block_lt:Integer
|
||||||
td::make_refint(0), //TODO: // trans_lt:Integer
|
td::make_refint(0), //TODO: // trans_lt:Integer
|
||||||
std::move(rand_seed_int), // rand_seed:Integer
|
std::move(rand_seed_int), // rand_seed:Integer
|
||||||
block::CurrencyCollection(args.balance).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
block::CurrencyCollection(args.balance).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||||
vm::load_cell_slice_ref(address), // myself:MsgAddressInt
|
vm::load_cell_slice_ref(address), // myself:MsgAddressInt
|
||||||
vm::StackEntry::maybe(config) //vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
vm::StackEntry::maybe(config) //vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
||||||
); // global_config:(Maybe Cell) ] = SmartContractInfo;
|
};
|
||||||
|
if (args.config && args.config.value()->get_global_version() >= 4) {
|
||||||
|
tuple.push_back(code.not_null() ? code : vm::StackEntry{}); // code:Cell
|
||||||
|
tuple.push_back(block::CurrencyCollection::zero().as_vm_tuple()); // in_msg_value:[Integer (Maybe Cell)]
|
||||||
|
tuple.push_back(td::zero_refint()); // storage_fees:Integer
|
||||||
|
|
||||||
|
// See crypto/block/mc-config.cpp#2115 (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
|
||||||
|
tuple.push_back(args.prev_blocks_info ? args.prev_blocks_info.value() : vm::StackEntry{}); // prev_block_info
|
||||||
|
}
|
||||||
|
auto tuple_ref = td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
|
||||||
//LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
|
//LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
|
||||||
return vm::make_tuple_ref(std::move(tuple));
|
return vm::make_tuple_ref(std::move(tuple_ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
|
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
|
||||||
|
@ -282,7 +291,7 @@ td::Ref<vm::Cell> SmartContract::get_init_state() const {
|
||||||
|
|
||||||
SmartContract::Answer SmartContract::run_method(Args args) {
|
SmartContract::Answer SmartContract::run_method(Args args) {
|
||||||
if (!args.c7) {
|
if (!args.c7) {
|
||||||
args.c7 = prepare_vm_c7(args);
|
args.c7 = prepare_vm_c7(args, state_.code);
|
||||||
}
|
}
|
||||||
if (!args.limits) {
|
if (!args.limits) {
|
||||||
bool is_internal = args.get_method_id().ok() == 0;
|
bool is_internal = args.get_method_id().ok() == 0;
|
||||||
|
@ -302,7 +311,7 @@ SmartContract::Answer SmartContract::run_method(Args args) {
|
||||||
|
|
||||||
SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
||||||
if (!args.c7) {
|
if (!args.c7) {
|
||||||
args.c7 = prepare_vm_c7(args);
|
args.c7 = prepare_vm_c7(args, state_.code);
|
||||||
}
|
}
|
||||||
if (!args.limits) {
|
if (!args.limits) {
|
||||||
args.limits = vm::GasLimits{1000000, 1000000};
|
args.limits = vm::GasLimits{1000000, 1000000};
|
||||||
|
|
|
@ -70,6 +70,7 @@ class SmartContract : public td::CntObject {
|
||||||
td::optional<block::StdAddress> address;
|
td::optional<block::StdAddress> address;
|
||||||
td::optional<std::shared_ptr<const block::Config>> config;
|
td::optional<std::shared_ptr<const block::Config>> config;
|
||||||
td::optional<vm::Dictionary> libraries;
|
td::optional<vm::Dictionary> libraries;
|
||||||
|
td::optional<td::Ref<vm::Tuple>> prev_blocks_info;
|
||||||
|
|
||||||
Args() {
|
Args() {
|
||||||
}
|
}
|
||||||
|
@ -124,7 +125,7 @@ class SmartContract : public td::CntObject {
|
||||||
this->address = address;
|
this->address = address;
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
}
|
}
|
||||||
Args&& set_config(std::shared_ptr<const block::Config>& config) {
|
Args&& set_config(const std::shared_ptr<const block::Config>& config) {
|
||||||
this->config = config;
|
this->config = config;
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
}
|
}
|
||||||
|
@ -132,6 +133,14 @@ class SmartContract : public td::CntObject {
|
||||||
this->libraries = libraries;
|
this->libraries = libraries;
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
}
|
}
|
||||||
|
Args&& set_prev_blocks_info(td::Ref<vm::Tuple> tuple) {
|
||||||
|
if (tuple.is_null()) {
|
||||||
|
this->prev_blocks_info = {};
|
||||||
|
} else {
|
||||||
|
this->prev_blocks_info = std::move(tuple);
|
||||||
|
}
|
||||||
|
return std::move(*this);
|
||||||
|
}
|
||||||
Args&& set_vm_verbosity_level(int vm_log_verbosity_level) {
|
Args&& set_vm_verbosity_level(int vm_log_verbosity_level) {
|
||||||
this->vm_log_verbosity_level = vm_log_verbosity_level;
|
this->vm_log_verbosity_level = vm_log_verbosity_level;
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
|
|
|
@ -448,6 +448,33 @@ bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tvm_emulator_set_prev_blocks_info(void *tvm_emulator, const char* info_boc) {
|
||||||
|
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
||||||
|
|
||||||
|
if (info_boc != nullptr) {
|
||||||
|
auto info_cell = boc_b64_to_cell(info_boc);
|
||||||
|
if (info_cell.is_error()) {
|
||||||
|
LOG(ERROR) << "Can't deserialize previous blocks boc: " << info_cell.move_as_error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vm::StackEntry info_value;
|
||||||
|
if (!info_value.deserialize(info_cell.move_as_ok())) {
|
||||||
|
LOG(ERROR) << "Can't deserialize previous blocks tuple";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (info_value.is_null()) {
|
||||||
|
emulator->set_prev_blocks_info({});
|
||||||
|
} else if (info_value.is_tuple()) {
|
||||||
|
emulator->set_prev_blocks_info(info_value.as_tuple());
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Can't set previous blocks tuple: not a tuple";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool tvm_emulator_set_gas_limit(void *tvm_emulator, int64_t gas_limit) {
|
bool tvm_emulator_set_gas_limit(void *tvm_emulator, int64_t gas_limit) {
|
||||||
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
||||||
emulator->set_gas_limit(gas_limit);
|
emulator->set_gas_limit(gas_limit);
|
||||||
|
|
|
@ -167,6 +167,14 @@ EMULATOR_EXPORT bool tvm_emulator_set_libraries(void *tvm_emulator, const char *
|
||||||
*/
|
*/
|
||||||
EMULATOR_EXPORT bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config);
|
EMULATOR_EXPORT bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set tuple of previous blocks (13th element of c7)
|
||||||
|
* @param tvm_emulator Pointer to TVM emulator
|
||||||
|
* @param info_boc Base64 encoded BoC serialized TVM tuple (VmStackValue).
|
||||||
|
* @return true in case of success, false in case of error
|
||||||
|
*/
|
||||||
|
EMULATOR_EXPORT bool tvm_emulator_set_prev_blocks_info(void *tvm_emulator, const char* info_boc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set TVM gas limit
|
* @brief Set TVM gas limit
|
||||||
* @param tvm_emulator Pointer to TVM emulator
|
* @param tvm_emulator Pointer to TVM emulator
|
||||||
|
|
|
@ -14,6 +14,7 @@ _emulator_set_verbosity_level
|
||||||
_tvm_emulator_create
|
_tvm_emulator_create
|
||||||
_tvm_emulator_set_libraries
|
_tvm_emulator_set_libraries
|
||||||
_tvm_emulator_set_c7
|
_tvm_emulator_set_c7
|
||||||
|
_tvm_emulator_set_prev_blocks_info
|
||||||
_tvm_emulator_set_gas_limit
|
_tvm_emulator_set_gas_limit
|
||||||
_tvm_emulator_set_debug_enabled
|
_tvm_emulator_set_debug_enabled
|
||||||
_tvm_emulator_run_get_method
|
_tvm_emulator_run_get_method
|
||||||
|
|
|
@ -33,6 +33,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_prev_blocks_info(td::Ref<vm::Tuple> tuple) {
|
||||||
|
args_.set_prev_blocks_info(std::move(tuple));
|
||||||
|
}
|
||||||
|
|
||||||
void set_debug_enabled(bool debug_enabled) {
|
void set_debug_enabled(bool debug_enabled) {
|
||||||
args_.set_debug_enabled(debug_enabled);
|
args_.set_debug_enabled(debug_enabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ void LastConfig::with_last_block(td::Result<LastBlockState> r_last_block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto last_block = r_last_block.move_as_ok();
|
auto last_block = r_last_block.move_as_ok();
|
||||||
client_.send_query(ton::lite_api::liteServer_getConfigAll(0, create_tl_lite_block_id(last_block.last_block_id)),
|
client_.send_query(ton::lite_api::liteServer_getConfigAll(block::ConfigInfo::needPrevBlocks,
|
||||||
|
create_tl_lite_block_id(last_block.last_block_id)),
|
||||||
[this](auto r_config) { this->on_config(std::move(r_config)); });
|
[this](auto r_config) { this->on_config(std::move(r_config)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ td::Status LastConfig::process_config_proof(ton::ton_api::object_ptr<ton::lite_a
|
||||||
}
|
}
|
||||||
TRY_RESULT(state, block::check_extract_state_proof(blkid, raw_config->state_proof_.as_slice(),
|
TRY_RESULT(state, block::check_extract_state_proof(blkid, raw_config->state_proof_.as_slice(),
|
||||||
raw_config->config_proof_.as_slice()));
|
raw_config->config_proof_.as_slice()));
|
||||||
TRY_RESULT(config, block::Config::extract_from_state(std::move(state), 0));
|
TRY_RESULT(config, block::ConfigInfo::extract_config(std::move(state), block::ConfigInfo::needPrevBlocks));
|
||||||
|
|
||||||
for (auto i : params_) {
|
for (auto i : params_) {
|
||||||
VLOG(last_config) << "ConfigParam(" << i << ") = ";
|
VLOG(last_config) << "ConfigParam(" << i << ") = ";
|
||||||
|
@ -109,6 +110,7 @@ td::Status LastConfig::process_config_proof(ton::ton_api::object_ptr<ton::lite_a
|
||||||
VLOG(last_config) << os.str();
|
VLOG(last_config) << os.str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TRY_RESULT_ASSIGN(state_.prev_blocks_info, config->get_prev_blocks_info());
|
||||||
state_.config.reset(config.release());
|
state_.config.reset(config.release());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
struct LastConfigState {
|
struct LastConfigState {
|
||||||
std::shared_ptr<const block::Config> config;
|
std::shared_ptr<const block::Config> config;
|
||||||
|
td::Ref<vm::Tuple> prev_blocks_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
td::StringBuilder& operator<<(td::StringBuilder& sb, const LastConfigState& state);
|
td::StringBuilder& operator<<(td::StringBuilder& sb, const LastConfigState& state);
|
||||||
|
|
|
@ -890,8 +890,10 @@ class Query {
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig, std::shared_ptr<const block::Config>& cfg, vm::Dictionary& libraries) {
|
td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig, const LastConfigState& state,
|
||||||
|
vm::Dictionary& libraries) {
|
||||||
// gas fees
|
// gas fees
|
||||||
|
const auto& cfg = state.config;
|
||||||
bool is_masterchain = raw_.source->get_address().workchain == ton::masterchainId;
|
bool is_masterchain = raw_.source->get_address().workchain == ton::masterchainId;
|
||||||
TRY_RESULT(gas_limits_prices, cfg->get_gas_limits_prices(is_masterchain));
|
TRY_RESULT(gas_limits_prices, cfg->get_gas_limits_prices(is_masterchain));
|
||||||
TRY_RESULT(storage_prices, cfg->get_storage_prices());
|
TRY_RESULT(storage_prices, cfg->get_storage_prices());
|
||||||
|
@ -919,7 +921,9 @@ class Query {
|
||||||
.set_now(raw_.source->get_sync_time())
|
.set_now(raw_.source->get_sync_time())
|
||||||
.set_ignore_chksig(ignore_chksig)
|
.set_ignore_chksig(ignore_chksig)
|
||||||
.set_address(raw_.source->get_address())
|
.set_address(raw_.source->get_address())
|
||||||
.set_config(cfg).set_libraries(libraries));
|
.set_config(cfg)
|
||||||
|
.set_prev_blocks_info(state.prev_blocks_info)
|
||||||
|
.set_libraries(libraries));
|
||||||
td::int64 fwd_fee = 0;
|
td::int64 fwd_fee = 0;
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
LOG(DEBUG) << "output actions:\n"
|
LOG(DEBUG) << "output actions:\n"
|
||||||
|
@ -4109,7 +4113,7 @@ void TonlibClient::query_estimate_fees(td::int64 id, bool ignore_chksig, td::Res
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TRY_RESULT_PROMISE(promise, state, std::move(r_state));
|
TRY_RESULT_PROMISE(promise, state, std::move(r_state));
|
||||||
TRY_RESULT_PROMISE_PREFIX(promise, fees, TRY_VM(it->second->estimate_fees(ignore_chksig, state.config, libraries)),
|
TRY_RESULT_PROMISE_PREFIX(promise, fees, TRY_VM(it->second->estimate_fees(ignore_chksig, state, libraries)),
|
||||||
TonlibError::Internal());
|
TonlibError::Internal());
|
||||||
promise.set_value(tonlib_api::make_object<tonlib_api::query_fees>(
|
promise.set_value(tonlib_api::make_object<tonlib_api::query_fees>(
|
||||||
fees.first.to_tonlib_api(), td::transform(fees.second, [](auto& x) { return x.to_tonlib_api(); })));
|
fees.first.to_tonlib_api(), td::transform(fees.second, [](auto& x) { return x.to_tonlib_api(); })));
|
||||||
|
@ -4474,6 +4478,7 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
|
||||||
](td::Result<LastConfigState> r_state) mutable {
|
](td::Result<LastConfigState> r_state) mutable {
|
||||||
TRY_RESULT_PROMISE(promise, state, std::move(r_state));
|
TRY_RESULT_PROMISE(promise, state, std::move(r_state));
|
||||||
args.set_config(state.config);
|
args.set_config(state.config);
|
||||||
|
args.set_prev_blocks_info(state.prev_blocks_info);
|
||||||
|
|
||||||
auto code = smc->get_state().code;
|
auto code = smc->get_state().code;
|
||||||
if (code.not_null()) {
|
if (code.not_null()) {
|
||||||
|
|
|
@ -1688,13 +1688,23 @@ void LiteQuery::continue_getConfigParams(int mode, std::vector<int> param_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = keyblk ? block::Config::extract_from_key_block(mpb.root(), mode)
|
std::unique_ptr<block::Config> cfg;
|
||||||
: block::Config::extract_from_state(mpb.root(), mode);
|
if (keyblk || !(mode & block::ConfigInfo::needPrevBlocks)) {
|
||||||
if (res.is_error()) {
|
auto res = keyblk ? block::Config::extract_from_key_block(mpb.root(), mode)
|
||||||
fatal_error(res.move_as_error());
|
: block::Config::extract_from_state(mpb.root(), mode);
|
||||||
return;
|
if (res.is_error()) {
|
||||||
|
fatal_error(res.move_as_error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cfg = res.move_as_ok();
|
||||||
|
} else {
|
||||||
|
auto res = block::ConfigInfo::extract_config(mpb.root(), mode);
|
||||||
|
if (res.is_error()) {
|
||||||
|
fatal_error(res.move_as_error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cfg = res.move_as_ok();
|
||||||
}
|
}
|
||||||
auto cfg = res.move_as_ok();
|
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
fatal_error("cannot extract configuration from last mc state");
|
fatal_error("cannot extract configuration from last mc state");
|
||||||
return;
|
return;
|
||||||
|
@ -1707,6 +1717,9 @@ void LiteQuery::continue_getConfigParams(int mode, std::vector<int> param_list)
|
||||||
visit(cfg->get_config_param(i));
|
visit(cfg->get_config_param(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!keyblk && mode & block::ConfigInfo::needPrevBlocks) {
|
||||||
|
((block::ConfigInfo*)cfg.get())->get_prev_blocks_info();
|
||||||
|
}
|
||||||
} catch (vm::VmError& err) {
|
} catch (vm::VmError& err) {
|
||||||
fatal_error("error while traversing required configuration parameters: "s + err.get_msg());
|
fatal_error("error while traversing required configuration parameters: "s + err.get_msg());
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue