mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
tonlib use correct c7: config and address when executing
This commit is contained in:
parent
64615a9766
commit
7dc980562f
7 changed files with 99 additions and 38 deletions
|
@ -52,30 +52,51 @@ 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(td::uint32 now, td::uint64 balance) {
|
td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args) {
|
||||||
// TODO: fix initialization of c7
|
|
||||||
td::BitArray<256> rand_seed;
|
td::BitArray<256> rand_seed;
|
||||||
rand_seed.as_slice().fill(0);
|
rand_seed.as_slice().fill(0);
|
||||||
td::RefInt256 rand_seed_int{true};
|
td::RefInt256 rand_seed_int{true};
|
||||||
rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false);
|
rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false);
|
||||||
|
|
||||||
|
td::uint32 now = 0;
|
||||||
|
if (args.now) {
|
||||||
|
now = args.now.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
vm::CellBuilder cb;
|
||||||
|
if (args.address) {
|
||||||
|
td::BigInt256 dest_addr;
|
||||||
|
dest_addr.import_bits((*args.address).addr.as_bitslice());
|
||||||
|
cb.store_ones(1)
|
||||||
|
.store_zeroes(2)
|
||||||
|
.store_long((*args.address).workchain, 8)
|
||||||
|
.store_int256(dest_addr, 256);
|
||||||
|
}
|
||||||
|
auto address = cb.finalize();
|
||||||
|
auto config = td::Ref<vm::Cell>();
|
||||||
|
|
||||||
|
if (args.config) {
|
||||||
|
config = (*args.config)->get_root_cell();
|
||||||
|
}
|
||||||
|
|
||||||
auto tuple = vm::make_tuple_ref(
|
auto tuple = vm::make_tuple_ref(
|
||||||
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), // block_lt:Integer
|
td::make_refint(0), //TODO: // block_lt:Integer
|
||||||
td::make_refint(0), // 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(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(vm::CellBuilder().finalize()) // myself:MsgAddressInt
|
vm::load_cell_slice_ref(address), // myself:MsgAddressInt
|
||||||
//vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
vm::StackEntry::maybe(config) //vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
||||||
); // global_config:(Maybe Cell) ] = SmartContractInfo;
|
); // global_config:(Maybe Cell) ] = SmartContractInfo;
|
||||||
//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));
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
vm::GasLimits gas, bool ignore_chksig) {
|
vm::GasLimits gas, bool ignore_chksig, td::Ref<vm::Cell> libraries) {
|
||||||
auto gas_credit = gas.gas_credit;
|
auto gas_credit = gas.gas_credit;
|
||||||
vm::init_op_cp0();
|
vm::init_op_cp0();
|
||||||
vm::DictionaryBase::get_empty_dictionary();
|
vm::DictionaryBase::get_empty_dictionary();
|
||||||
|
@ -108,11 +129,14 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
||||||
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
|
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
|
||||||
vm.set_c7(std::move(c7));
|
vm.set_c7(std::move(c7));
|
||||||
vm.set_chksig_always_succeed(ignore_chksig);
|
vm.set_chksig_always_succeed(ignore_chksig);
|
||||||
|
if (!libraries.is_null())
|
||||||
|
vm.register_library_collection(libraries);
|
||||||
try {
|
try {
|
||||||
res.code = ~vm.run();
|
res.code = ~vm.run();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LOG(FATAL) << "catch unhandled exception";
|
LOG(FATAL) << "catch unhandled exception";
|
||||||
}
|
}
|
||||||
|
td::ConstBitPtr mlib = vm.get_missing_library();
|
||||||
res.new_state = std::move(state);
|
res.new_state = std::move(state);
|
||||||
res.stack = vm.get_stack_ref();
|
res.stack = vm.get_stack_ref();
|
||||||
gas = vm.get_gas_limits();
|
gas = vm.get_gas_limits();
|
||||||
|
@ -128,13 +152,17 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
||||||
LOG(DEBUG) << "VM accepted: " << res.accepted;
|
LOG(DEBUG) << "VM accepted: " << res.accepted;
|
||||||
LOG(DEBUG) << "VM success: " << res.success;
|
LOG(DEBUG) << "VM success: " << res.success;
|
||||||
}
|
}
|
||||||
|
if (!mlib.is_null()) {
|
||||||
|
LOG(DEBUG) << "Missing library: " << mlib.to_hex(256);
|
||||||
|
res.missing_library = mlib;
|
||||||
|
}
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
res.new_state.data = vm.get_c4();
|
res.new_state.data = vm.get_c4();
|
||||||
res.actions = vm.get_d(5);
|
res.actions = vm.get_d(5);
|
||||||
LOG(DEBUG) << "output actions:\n"
|
LOG(DEBUG) << "output actions:\n"
|
||||||
<< block::gen::OutList{res.output_actions_count(res.actions)}.as_string_ref(res.actions);
|
<< block::gen::OutList{res.output_actions_count(res.actions)}.as_string_ref(res.actions);
|
||||||
}
|
}
|
||||||
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success))
|
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success) && mlib.is_null())
|
||||||
<< "Accepted but failed with code " << res.code << "\n"
|
<< "Accepted but failed with code " << res.code << "\n"
|
||||||
<< res.gas_used << "\n";
|
<< res.gas_used << "\n";
|
||||||
return res;
|
return res;
|
||||||
|
@ -176,12 +204,8 @@ td::Ref<vm::Cell> SmartContract::get_init_state() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartContract::Answer SmartContract::run_method(Args args) {
|
SmartContract::Answer SmartContract::run_method(Args args) {
|
||||||
td::uint32 now = 0;
|
|
||||||
if (args.now) {
|
|
||||||
now = args.now.unwrap();
|
|
||||||
}
|
|
||||||
if (!args.c7) {
|
if (!args.c7) {
|
||||||
args.c7 = prepare_vm_c7(now, args.balance);
|
args.c7 = prepare_vm_c7(args);
|
||||||
}
|
}
|
||||||
if (!args.limits) {
|
if (!args.limits) {
|
||||||
bool is_internal = args.get_method_id().ok() == 0;
|
bool is_internal = args.get_method_id().ok() == 0;
|
||||||
|
@ -193,18 +217,15 @@ SmartContract::Answer SmartContract::run_method(Args args) {
|
||||||
CHECK(args.method_id);
|
CHECK(args.method_id);
|
||||||
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
||||||
auto res =
|
auto res =
|
||||||
run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig);
|
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>{});
|
||||||
state_ = res.new_state;
|
state_ = res.new_state;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
||||||
td::uint32 now = 0;
|
|
||||||
if (args.now) {
|
|
||||||
now = args.now.unwrap();
|
|
||||||
}
|
|
||||||
if (!args.c7) {
|
if (!args.c7) {
|
||||||
args.c7 = prepare_vm_c7(now, args.balance);
|
args.c7 = prepare_vm_c7(args);
|
||||||
}
|
}
|
||||||
if (!args.limits) {
|
if (!args.limits) {
|
||||||
args.limits = vm::GasLimits{1000000, 1000000};
|
args.limits = vm::GasLimits{1000000, 1000000};
|
||||||
|
@ -214,7 +235,8 @@ SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
||||||
}
|
}
|
||||||
CHECK(args.method_id);
|
CHECK(args.method_id);
|
||||||
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
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);
|
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>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartContract::Answer SmartContract::run_get_method(td::Slice method, Args args) const {
|
SmartContract::Answer SmartContract::run_get_method(td::Slice method, Args args) const {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "td/utils/crypto.h"
|
#include "td/utils/crypto.h"
|
||||||
|
|
||||||
#include "block/block.h"
|
#include "block/block.h"
|
||||||
|
#include "block/mc-config.h"
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
class SmartContract : public td::CntObject {
|
class SmartContract : public td::CntObject {
|
||||||
|
@ -48,6 +49,7 @@ class SmartContract : public td::CntObject {
|
||||||
td::Ref<vm::Cell> actions;
|
td::Ref<vm::Cell> actions;
|
||||||
td::int32 code;
|
td::int32 code;
|
||||||
td::int64 gas_used;
|
td::int64 gas_used;
|
||||||
|
td::ConstBitPtr missing_library{0};
|
||||||
static int output_actions_count(td::Ref<vm::Cell> list);
|
static int output_actions_count(td::Ref<vm::Cell> list);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,6 +63,10 @@ class SmartContract : public td::CntObject {
|
||||||
td::uint64 amount{0};
|
td::uint64 amount{0};
|
||||||
td::uint64 balance{0};
|
td::uint64 balance{0};
|
||||||
|
|
||||||
|
td::optional<block::StdAddress> address;
|
||||||
|
td::optional<std::shared_ptr<const block::Config>> config;
|
||||||
|
td::optional<vm::Dictionary> libraries;
|
||||||
|
|
||||||
Args() {
|
Args() {
|
||||||
}
|
}
|
||||||
Args(std::initializer_list<vm::StackEntry> stack)
|
Args(std::initializer_list<vm::StackEntry> stack)
|
||||||
|
@ -106,6 +112,18 @@ class SmartContract : public td::CntObject {
|
||||||
this->balance = balance;
|
this->balance = balance;
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
}
|
}
|
||||||
|
Args&& set_address(block::StdAddress address) {
|
||||||
|
this->address = address;
|
||||||
|
return std::move(*this);
|
||||||
|
}
|
||||||
|
Args&& set_config(std::shared_ptr<const block::Config>& config) {
|
||||||
|
this->config = config;
|
||||||
|
return std::move(*this);
|
||||||
|
}
|
||||||
|
Args&& set_libraries(vm::Dictionary libraries) {
|
||||||
|
this->libraries = libraries;
|
||||||
|
return std::move(*this);
|
||||||
|
}
|
||||||
|
|
||||||
td::Result<td::int32> get_method_id() const {
|
td::Result<td::int32> get_method_id() const {
|
||||||
if (!method_id) {
|
if (!method_id) {
|
||||||
|
|
|
@ -604,6 +604,7 @@ Ref<Cell> VmState::load_library(td::ConstBitPtr hash) {
|
||||||
return lib;
|
return lib;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
missing_library = hash;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ class VmState final : public VmStateInterface {
|
||||||
td::int64 loaded_cells_count{0};
|
td::int64 loaded_cells_count{0};
|
||||||
int stack_trace{0}, debug_off{0};
|
int stack_trace{0}, debug_off{0};
|
||||||
bool chksig_always_succeed{false};
|
bool chksig_always_succeed{false};
|
||||||
|
td::ConstBitPtr missing_library{0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
|
@ -321,6 +322,9 @@ class VmState final : public VmStateInterface {
|
||||||
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
|
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
|
||||||
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
|
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
|
||||||
}
|
}
|
||||||
|
td::ConstBitPtr get_missing_library() const {
|
||||||
|
return missing_library;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init_cregs(bool same_c3 = false, bool push_0 = true);
|
void init_cregs(bool same_c3 = false, bool push_0 = true);
|
||||||
|
|
|
@ -62,9 +62,7 @@ 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();
|
||||||
auto params = params_;
|
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_getConfigParams(0, create_tl_lite_block_id(last_block.last_block_id),
|
|
||||||
std::move(params)),
|
|
||||||
[this](auto r_config) { this->on_config(std::move(r_config)); });
|
[this](auto r_config) { this->on_config(std::move(r_config)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -861,13 +861,13 @@ class Query {
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig, const block::Config& cfg) {
|
td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig, std::shared_ptr<const block::Config>& cfg, vm::Dictionary& libraries) {
|
||||||
// gas fees
|
// gas fees
|
||||||
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());
|
||||||
TRY_RESULT(masterchain_msg_prices, cfg.get_msg_prices(true));
|
TRY_RESULT(masterchain_msg_prices, cfg->get_msg_prices(true));
|
||||||
TRY_RESULT(basechain_msg_prices, cfg.get_msg_prices(false));
|
TRY_RESULT(basechain_msg_prices, cfg->get_msg_prices(false));
|
||||||
block::MsgPrices* msg_prices[2] = {&basechain_msg_prices, &masterchain_msg_prices};
|
block::MsgPrices* msg_prices[2] = {&basechain_msg_prices, &masterchain_msg_prices};
|
||||||
auto storage_fee_256 = block::StoragePrices::compute_storage_fees(
|
auto storage_fee_256 = block::StoragePrices::compute_storage_fees(
|
||||||
raw_.source->get_sync_time(), storage_prices, raw_.source->raw().storage_stat,
|
raw_.source->get_sync_time(), storage_prices, raw_.source->raw().storage_stat,
|
||||||
|
@ -888,7 +888,9 @@ class Query {
|
||||||
.set_limits(gas_limits)
|
.set_limits(gas_limits)
|
||||||
.set_balance(raw_.source->get_balance())
|
.set_balance(raw_.source->get_balance())
|
||||||
.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_config(cfg).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"
|
||||||
|
@ -910,7 +912,7 @@ class Query {
|
||||||
|
|
||||||
for (auto& destination : raw_.destinations) {
|
for (auto& destination : raw_.destinations) {
|
||||||
bool dest_is_masterchain = destination && destination->get_address().workchain == ton::masterchainId;
|
bool dest_is_masterchain = destination && destination->get_address().workchain == ton::masterchainId;
|
||||||
TRY_RESULT(dest_gas_limits_prices, cfg.get_gas_limits_prices(dest_is_masterchain));
|
TRY_RESULT(dest_gas_limits_prices, cfg->get_gas_limits_prices(dest_is_masterchain));
|
||||||
auto dest_storage_fee_256 =
|
auto dest_storage_fee_256 =
|
||||||
destination ? block::StoragePrices::compute_storage_fees(
|
destination ? block::StoragePrices::compute_storage_fees(
|
||||||
destination->get_sync_time(), storage_prices, destination->raw().storage_stat,
|
destination->get_sync_time(), storage_prices, destination->raw().storage_stat,
|
||||||
|
@ -3266,7 +3268,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)),
|
TRY_RESULT_PROMISE_PREFIX(promise, fees, TRY_VM(it->second->estimate_fees(ignore_chksig, state.config, 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(); })));
|
||||||
|
@ -3493,14 +3495,29 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
|
||||||
args.set_stack(std::move(stack));
|
args.set_stack(std::move(stack));
|
||||||
args.set_balance(it->second->get_balance());
|
args.set_balance(it->second->get_balance());
|
||||||
args.set_now(it->second->get_sync_time());
|
args.set_now(it->second->get_sync_time());
|
||||||
auto res = smc->run_get_method(std::move(args));
|
args.set_address(it->second->get_address());
|
||||||
|
|
||||||
// smc.runResult gas_used:int53 stack:vector<tvm.StackEntry> exit_code:int32 = smc.RunResult;
|
auto code = smc->get_state().code;
|
||||||
std::vector<object_ptr<tonlib_api::tvm_StackEntry>> res_stack;
|
if (code.not_null()) {
|
||||||
for (auto& entry : res.stack->as_span()) {
|
std::vector<td::Bits256> libraryList;
|
||||||
res_stack.push_back(to_tonlib_api(entry));
|
|
||||||
}
|
}
|
||||||
promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
|
|
||||||
|
args.set_libraries(libraries);
|
||||||
|
|
||||||
|
client_.with_last_config([smc=std::move(smc), args=std::move(args),
|
||||||
|
promise = std::move(promise)](td::Result<LastConfigState> r_state) mutable {
|
||||||
|
TRY_RESULT_PROMISE(promise, state, std::move(r_state));
|
||||||
|
args.set_config(state.config);
|
||||||
|
|
||||||
|
auto res = smc->run_get_method(std::move(args));
|
||||||
|
|
||||||
|
// smc.runResult gas_used:int53 stack:vector<tvm.StackEntry> exit_code:int32 = smc.RunResult;
|
||||||
|
std::vector<object_ptr<tonlib_api::tvm_StackEntry>> res_stack;
|
||||||
|
for (auto& entry : res.stack->as_span()) {
|
||||||
|
res_stack.push_back(to_tonlib_api(entry));
|
||||||
|
}
|
||||||
|
promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
|
||||||
|
});
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ class TonlibClient : public td::actor::Actor {
|
||||||
td::optional<ton::BlockIdExt> block_id;
|
td::optional<ton::BlockIdExt> block_id;
|
||||||
};
|
};
|
||||||
QueryContext query_context_;
|
QueryContext query_context_;
|
||||||
|
vm::Dictionary libraries{256};
|
||||||
|
|
||||||
// network
|
// network
|
||||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
|
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue