Skip to content

Commit eb45c48

Browse files
EmelyanenkoKdungeon-master-666yma-het
authored
Smart cont try fetch config (#1717)
* SmartContract: try fetch config from c7 if it's not set * feat: Added tvm_emulator_emulate_run_method clone with logs available * free * fix cast warning * bf --------- Co-authored-by: Marat S <[email protected]> Co-authored-by: Yma Het <[email protected]>
1 parent 5b2221a commit eb45c48

File tree

4 files changed

+111
-7
lines changed

4 files changed

+111
-7
lines changed

crypto/smc-envelope/SmartContract.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,42 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args, td::Ref<vm::Cell> cod
191191
return vm::make_tuple_ref(std::move(tuple_ref));
192192
}
193193

194+
std::shared_ptr<const block::Config> try_fetch_config_from_c7(td::Ref<vm::Tuple> c7) {
195+
if (c7.is_null() || c7->size() < 1) {
196+
return nullptr;
197+
}
198+
auto c7_tuple = c7->at(0).as_tuple();
199+
if (c7_tuple.is_null() || c7_tuple->size() < 10) {
200+
return nullptr;
201+
}
202+
auto config_cell = c7_tuple->at(9).as_cell();
203+
if (config_cell.is_null()) {
204+
return nullptr;
205+
}
206+
auto config_dict = std::make_unique<vm::Dictionary>(config_cell, 32);
207+
auto config_addr_cell = config_dict->lookup_ref(td::BitArray<32>::zero());
208+
ton::StdSmcAddress config_addr;
209+
if (config_addr_cell.is_null()) {
210+
config_addr = ton::StdSmcAddress::zero();
211+
} else {
212+
auto config_addr_cs = vm::load_cell_slice(std::move(config_addr_cell));
213+
if (config_addr_cs.size() != 0x100) {
214+
LOG(WARNING) << "Config parameter 0 with config address has wrong size";
215+
config_addr = ton::StdSmcAddress::zero();
216+
} else {
217+
config_addr_cs.fetch_bits_to(config_addr);
218+
}
219+
}
220+
auto global_config = block::Config(config_cell, std::move(config_addr),
221+
block::Config::needWorkchainInfo | block::Config::needSpecialSmc | block::Config::needCapabilities);
222+
auto unpack_res = global_config.unpack();
223+
if (unpack_res.is_error()) {
224+
LOG(ERROR) << "Failed to unpack config: " << unpack_res.error();
225+
return nullptr;
226+
}
227+
return std::make_shared<block::Config>(std::move(global_config));
228+
}
229+
194230
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
195231
vm::GasLimits gas, bool ignore_chksig, td::Ref<vm::Cell> libraries,
196232
int vm_log_verbosity, bool debug_enabled,
@@ -314,6 +350,9 @@ td::Ref<vm::Cell> SmartContract::get_init_state() const {
314350
}
315351

316352
SmartContract::Answer SmartContract::run_method(Args args) {
353+
if (args.c7 && !args.config) {
354+
args.config = try_fetch_config_from_c7(args.c7.value());
355+
}
317356
if (!args.c7) {
318357
args.c7 = prepare_vm_c7(args, state_.code);
319358
}
@@ -335,6 +374,9 @@ SmartContract::Answer SmartContract::run_method(Args args) {
335374
}
336375

337376
SmartContract::Answer SmartContract::run_get_method(Args args) const {
377+
if (args.c7 && !args.config) {
378+
args.config = try_fetch_config_from_c7(args.c7.value());
379+
}
338380
if (!args.c7) {
339381
args.c7 = prepare_vm_c7(args, state_.code);
340382
}

emulator/emulator-extern.cpp

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -639,10 +639,16 @@ const char *tvm_emulator_run_get_method(void *tvm_emulator, int method_id, const
639639
return strdup(jb.string_builder().as_cslice().c_str());
640640
}
641641

642-
const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc, int64_t gas_limit) {
642+
struct TvmEulatorEmulateRunMethodResponse
643+
{
644+
const char *response;
645+
const char *log;
646+
};
647+
648+
TvmEulatorEmulateRunMethodResponse emulate_run_method(uint32_t len, const char *params_boc, int64_t gas_limit) {
643649
auto params_cell = vm::std_boc_deserialize(td::Slice(params_boc, len));
644650
if (params_cell.is_error()) {
645-
return nullptr;
651+
return { nullptr, nullptr };
646652
}
647653
auto params_cs = vm::load_cell_slice(params_cell.move_as_ok());
648654
auto code = params_cs.fetch_ref();
@@ -657,12 +663,12 @@ const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc
657663

658664
td::Ref<vm::Stack> stack;
659665
if (!vm::Stack::deserialize_to(stack_cs, stack)) {
660-
return nullptr;
666+
return { nullptr, nullptr };
661667
}
662668

663669
td::Ref<vm::Stack> c7;
664670
if (!vm::Stack::deserialize_to(c7_cs, c7)) {
665-
return nullptr;
671+
return { nullptr, nullptr };
666672
}
667673

668674
auto emulator = new emulator::TvmEmulator(code, data);
@@ -677,7 +683,7 @@ const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc
677683

678684
vm::CellBuilder stack_cb;
679685
if (!result.stack->serialize(stack_cb)) {
680-
return nullptr;
686+
return { nullptr, nullptr };
681687
}
682688

683689
vm::CellBuilder cb;
@@ -687,7 +693,7 @@ const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc
687693

688694
auto ser = vm::std_boc_serialize(cb.finalize());
689695
if (!ser.is_ok()) {
690-
return nullptr;
696+
return { nullptr, nullptr };
691697
}
692698
auto sok = ser.move_as_ok();
693699

@@ -696,7 +702,24 @@ const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc
696702
memcpy(rn, &sz, 4);
697703
memcpy(rn+4, sok.data(), sz);
698704

699-
return rn;
705+
return { rn, strdup(result.vm_log.data()) };
706+
}
707+
708+
const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc, int64_t gas_limit) {
709+
auto result = emulate_run_method(len, params_boc, gas_limit);
710+
return result.response;
711+
}
712+
713+
void *tvm_emulator_emulate_run_method_detailed(uint32_t len, const char *params_boc, int64_t gas_limit) {
714+
auto result = emulate_run_method(len, params_boc, gas_limit);
715+
return new TvmEulatorEmulateRunMethodResponse(result);
716+
}
717+
718+
void run_method_detailed_result_destroy(void *detailed_result) {
719+
auto result = static_cast<TvmEulatorEmulateRunMethodResponse *>(detailed_result);
720+
free(const_cast<char*>(result->response));
721+
free(const_cast<char*>(result->log));
722+
delete result;
700723
}
701724

702725
const char *tvm_emulator_send_external_message(void *tvm_emulator, const char *message_body_boc) {
@@ -773,6 +796,12 @@ void emulator_config_destroy(void *config) {
773796
delete static_cast<block::Config *>(config);
774797
}
775798

799+
void string_destroy(const char *str) {
800+
if (str != nullptr) {
801+
free(const_cast<char *>(str));
802+
}
803+
}
804+
776805
const char* emulator_version() {
777806
auto version_json = td::JsonBuilder();
778807
auto obj = version_json.enter_object();

emulator/emulator-extern.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,27 @@ EMULATOR_EXPORT const char *tvm_emulator_run_get_method(void *tvm_emulator, int
254254
*/
255255
EMULATOR_EXPORT const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc, int64_t gas_limit);
256256

257+
/**
258+
* @brief Optimized version of "run get method" with all passed parameters in a single call. Also returns log.
259+
* @param len Length of params_boc buffer
260+
* @param params_boc BoC serialized parameters, scheme: request$_ code:^Cell data:^Cell stack:^VmStack params:^[c7:^VmStack libs:^Cell] method_id:(## 32)
261+
* @param gas_limit Gas limit
262+
* @return Pointer to struct with two fields:
263+
* - response: Char* with first 4 bytes defining length, and the rest BoC serialized result
264+
* Scheme: result$_ exit_code:(## 32) gas_used:(## 32) stack:^VmStack
265+
* - log: Char* with VM log string
266+
*/
267+
EMULATOR_EXPORT void *tvm_emulator_emulate_run_method_detailed(uint32_t len, const char *params_boc, int64_t gas_limit);
268+
269+
/**
270+
* @brief Destroy detailed result of "tvm_emulator_emulate_run_method_detailed"
271+
* @param detailed_result Pointer to detailed result struct returned by "tvm_emulator_emulate_run_method_detailed"
272+
*
273+
* Caller should not use string_destroy() for fields of this struct,
274+
* as they are already freed in this function.
275+
*/
276+
EMULATOR_EXPORT void run_method_detailed_result_destroy(void *detailed_result);
277+
257278
/**
258279
* @brief Send external message
259280
* @param tvm_emulator Pointer to TVM emulator
@@ -315,6 +336,15 @@ EMULATOR_EXPORT void tvm_emulator_destroy(void *tvm_emulator);
315336
*/
316337
EMULATOR_EXPORT void emulator_config_destroy(void *config);
317338

339+
/**
340+
* @brief Destroy string created by emulator library
341+
* @param string Pointer to string to destroy
342+
*
343+
* This function should be used to free strings returned by emulator library functions.
344+
* It is not safe to use caller's free() on them, as they may have been allocated using a different allocator.
345+
*/
346+
EMULATOR_EXPORT void string_destroy(const char *string);
347+
318348
/**
319349
* @brief Get git commit hash and date of the library
320350
*/

emulator/emulator_export_list

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,7 @@ _tvm_emulator_send_external_message
2727
_tvm_emulator_send_internal_message
2828
_tvm_emulator_destroy
2929
_tvm_emulator_emulate_run_method
30+
_tvm_emulator_emulate_run_method_detailed
31+
_run_method_detailed_result_destroy
32+
_string_destroy
3033
_emulator_version

0 commit comments

Comments
 (0)