mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			257 lines
		
	
	
		
			No EOL
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			257 lines
		
	
	
		
			No EOL
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "emulator-extern.h"
 | 
						|
#include "td/utils/logging.h"
 | 
						|
#include "td/utils/JsonBuilder.h"
 | 
						|
#include "td/utils/misc.h"
 | 
						|
#include "td/utils/optional.h"
 | 
						|
#include "StringLog.h"
 | 
						|
#include <iostream>
 | 
						|
#include "crypto/common/bitstring.h"
 | 
						|
 | 
						|
struct TransactionEmulationParams {
 | 
						|
  uint32_t utime;
 | 
						|
  uint64_t lt;
 | 
						|
  td::optional<std::string> rand_seed_hex;
 | 
						|
  bool ignore_chksig;
 | 
						|
  bool is_tick_tock;
 | 
						|
  bool is_tock;
 | 
						|
  bool debug_enabled;
 | 
						|
};
 | 
						|
 | 
						|
td::Result<TransactionEmulationParams> decode_transaction_emulation_params(const char* json) {
 | 
						|
  TransactionEmulationParams params;
 | 
						|
 | 
						|
  std::string json_str(json);
 | 
						|
  TRY_RESULT(input_json, td::json_decode(td::MutableSlice(json_str)));
 | 
						|
  auto &obj = input_json.get_object();
 | 
						|
 | 
						|
  TRY_RESULT(utime_field, td::get_json_object_field(obj, "utime", td::JsonValue::Type::Number, false));
 | 
						|
  TRY_RESULT(utime, td::to_integer_safe<td::uint32>(utime_field.get_number()));
 | 
						|
  params.utime = utime;
 | 
						|
 | 
						|
  TRY_RESULT(lt_field, td::get_json_object_field(obj, "lt", td::JsonValue::Type::String, false));
 | 
						|
  TRY_RESULT(lt, td::to_integer_safe<td::uint64>(lt_field.get_string()));
 | 
						|
  params.lt = lt;
 | 
						|
 | 
						|
  TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", true));
 | 
						|
  if (rand_seed_str.size() > 0) {
 | 
						|
    params.rand_seed_hex = rand_seed_str;
 | 
						|
  }
 | 
						|
 | 
						|
  TRY_RESULT(ignore_chksig, td::get_json_object_bool_field(obj, "ignore_chksig", false));
 | 
						|
  params.ignore_chksig = ignore_chksig;
 | 
						|
 | 
						|
  TRY_RESULT(debug_enabled, td::get_json_object_bool_field(obj, "debug_enabled", false));
 | 
						|
  params.debug_enabled = debug_enabled;
 | 
						|
 | 
						|
  TRY_RESULT(is_tick_tock, td::get_json_object_bool_field(obj, "is_tick_tock", true, false));
 | 
						|
  params.is_tick_tock = is_tick_tock;
 | 
						|
 | 
						|
  TRY_RESULT(is_tock, td::get_json_object_bool_field(obj, "is_tock", true, false));
 | 
						|
  params.is_tock = is_tock;
 | 
						|
 | 
						|
  if (is_tock && !is_tick_tock) {
 | 
						|
    return td::Status::Error("Inconsistent parameters is_tick_tock=false, is_tock=true");
 | 
						|
  }
 | 
						|
 | 
						|
  return params;
 | 
						|
}
 | 
						|
 | 
						|
struct GetMethodParams {
 | 
						|
  std::string code;
 | 
						|
  std::string data;
 | 
						|
  int verbosity;
 | 
						|
  td::optional<std::string> libs;
 | 
						|
  td::optional<std::string> prev_blocks_info;
 | 
						|
  std::string address;
 | 
						|
  uint32_t unixtime;
 | 
						|
  uint64_t balance;
 | 
						|
  std::string rand_seed_hex;
 | 
						|
  int64_t gas_limit;
 | 
						|
  int method_id;
 | 
						|
  bool debug_enabled;
 | 
						|
};
 | 
						|
 | 
						|
td::Result<GetMethodParams> decode_get_method_params(const char* json) {
 | 
						|
  GetMethodParams params;
 | 
						|
 | 
						|
  std::string json_str(json);
 | 
						|
  TRY_RESULT(input_json, td::json_decode(td::MutableSlice(json_str)));
 | 
						|
  auto &obj = input_json.get_object();
 | 
						|
 | 
						|
  TRY_RESULT(code, td::get_json_object_string_field(obj, "code", false));
 | 
						|
  params.code = code;
 | 
						|
 | 
						|
  TRY_RESULT(data, td::get_json_object_string_field(obj, "data", false));
 | 
						|
  params.data = data;
 | 
						|
 | 
						|
  TRY_RESULT(verbosity, td::get_json_object_int_field(obj, "verbosity", false));
 | 
						|
  params.verbosity = verbosity;
 | 
						|
 | 
						|
  TRY_RESULT(libs, td::get_json_object_string_field(obj, "libs", true));
 | 
						|
  if (libs.size() > 0) {
 | 
						|
    params.libs = libs;
 | 
						|
  }
 | 
						|
 | 
						|
  TRY_RESULT(prev_blocks_info, td::get_json_object_string_field(obj, "prev_blocks_info", true));
 | 
						|
  if (prev_blocks_info.size() > 0) {
 | 
						|
    params.prev_blocks_info = prev_blocks_info;
 | 
						|
  }
 | 
						|
 | 
						|
  TRY_RESULT(address, td::get_json_object_string_field(obj, "address", false));
 | 
						|
  params.address = address;
 | 
						|
 | 
						|
  TRY_RESULT(unixtime_field, td::get_json_object_field(obj, "unixtime", td::JsonValue::Type::Number, false));
 | 
						|
  TRY_RESULT(unixtime, td::to_integer_safe<td::uint32>(unixtime_field.get_number()));
 | 
						|
  params.unixtime = unixtime;
 | 
						|
 | 
						|
  TRY_RESULT(balance_field, td::get_json_object_field(obj, "balance", td::JsonValue::Type::String, false));
 | 
						|
  TRY_RESULT(balance, td::to_integer_safe<td::uint64>(balance_field.get_string()));
 | 
						|
  params.balance = balance;
 | 
						|
 | 
						|
  TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", false));
 | 
						|
  params.rand_seed_hex = rand_seed_str;
 | 
						|
 | 
						|
  TRY_RESULT(gas_limit_field, td::get_json_object_field(obj, "gas_limit", td::JsonValue::Type::String, false));
 | 
						|
  TRY_RESULT(gas_limit, td::to_integer_safe<td::uint64>(gas_limit_field.get_string()));
 | 
						|
  params.gas_limit = gas_limit;
 | 
						|
 | 
						|
  TRY_RESULT(method_id, td::get_json_object_int_field(obj, "method_id", false));
 | 
						|
  params.method_id = method_id;
 | 
						|
 | 
						|
  TRY_RESULT(debug_enabled, td::get_json_object_bool_field(obj, "debug_enabled", false));
 | 
						|
  params.debug_enabled = debug_enabled;
 | 
						|
 | 
						|
  return params;
 | 
						|
}
 | 
						|
 | 
						|
class NoopLog : public td::LogInterface {
 | 
						|
 public:
 | 
						|
  NoopLog() {
 | 
						|
  }
 | 
						|
 | 
						|
  void append(td::CSlice new_slice, int log_level) override {
 | 
						|
  }
 | 
						|
 | 
						|
  void rotate() override {
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
extern "C" {
 | 
						|
 | 
						|
void* create_emulator(const char *config, int verbosity) {
 | 
						|
    NoopLog logger;
 | 
						|
 | 
						|
    td::log_interface = &logger;
 | 
						|
 | 
						|
    SET_VERBOSITY_LEVEL(verbosity_NEVER);
 | 
						|
    return transaction_emulator_create(config, verbosity);
 | 
						|
}
 | 
						|
 | 
						|
void destroy_emulator(void* em) {
 | 
						|
    NoopLog logger;
 | 
						|
 | 
						|
    td::log_interface = &logger;
 | 
						|
 | 
						|
    SET_VERBOSITY_LEVEL(verbosity_NEVER);
 | 
						|
    transaction_emulator_destroy(em);
 | 
						|
}
 | 
						|
 | 
						|
const char *emulate_with_emulator(void* em, const char* libs, const char* account, const char* message, const char* params) {
 | 
						|
    StringLog logger;
 | 
						|
 | 
						|
    td::log_interface = &logger;
 | 
						|
    SET_VERBOSITY_LEVEL(verbosity_DEBUG);
 | 
						|
 | 
						|
    auto decoded_params_res = decode_transaction_emulation_params(params);
 | 
						|
    if (decoded_params_res.is_error()) {
 | 
						|
        return strdup(R"({"fail":true,"message":"Can't decode other params"})");
 | 
						|
    }
 | 
						|
    auto decoded_params = decoded_params_res.move_as_ok();
 | 
						|
 | 
						|
    bool rand_seed_set = true;
 | 
						|
    if (decoded_params.rand_seed_hex) {
 | 
						|
      rand_seed_set = transaction_emulator_set_rand_seed(em, decoded_params.rand_seed_hex.unwrap().c_str());
 | 
						|
    }
 | 
						|
 | 
						|
    if (!transaction_emulator_set_libs(em, libs) ||
 | 
						|
        !transaction_emulator_set_lt(em, decoded_params.lt) ||
 | 
						|
        !transaction_emulator_set_unixtime(em, decoded_params.utime) ||
 | 
						|
        !transaction_emulator_set_ignore_chksig(em, decoded_params.ignore_chksig) ||
 | 
						|
        !transaction_emulator_set_debug_enabled(em, decoded_params.debug_enabled) ||
 | 
						|
        !rand_seed_set) {
 | 
						|
        transaction_emulator_destroy(em);
 | 
						|
        return strdup(R"({"fail":true,"message":"Can't set params"})");
 | 
						|
    }
 | 
						|
 | 
						|
    const char *result;
 | 
						|
    if (decoded_params.is_tick_tock) {
 | 
						|
      result = transaction_emulator_emulate_tick_tock_transaction(em, account, decoded_params.is_tock);
 | 
						|
    } else {
 | 
						|
      result = transaction_emulator_emulate_transaction(em, account, message);
 | 
						|
    }
 | 
						|
 | 
						|
    const char* output = nullptr;
 | 
						|
    {
 | 
						|
        td::JsonBuilder jb;
 | 
						|
        auto json_obj = jb.enter_object();
 | 
						|
        json_obj("output", td::JsonRaw(td::Slice(result)));
 | 
						|
        json_obj("logs", logger.get_string());
 | 
						|
        json_obj.leave();
 | 
						|
        output = strdup(jb.string_builder().as_cslice().c_str());
 | 
						|
    }
 | 
						|
    free((void*) result);
 | 
						|
 | 
						|
    return output;
 | 
						|
}
 | 
						|
 | 
						|
const char *emulate(const char *config, const char* libs, int verbosity, const char* account, const char* message, const char* params) {
 | 
						|
    auto em = transaction_emulator_create(config, verbosity);
 | 
						|
    auto result = emulate_with_emulator(em, libs, account, message, params);
 | 
						|
    transaction_emulator_destroy(em);
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
const char *run_get_method(const char *params, const char* stack, const char* config) {
 | 
						|
    StringLog logger;
 | 
						|
 | 
						|
    td::log_interface = &logger;
 | 
						|
    SET_VERBOSITY_LEVEL(verbosity_DEBUG);
 | 
						|
 | 
						|
    auto decoded_params_res = decode_get_method_params(params);
 | 
						|
    if (decoded_params_res.is_error()) {
 | 
						|
        return strdup(R"({"fail":true,"message":"Can't decode params"})");
 | 
						|
    }
 | 
						|
    auto decoded_params = decoded_params_res.move_as_ok();
 | 
						|
 | 
						|
    auto tvm = tvm_emulator_create(decoded_params.code.c_str(), decoded_params.data.c_str(), decoded_params.verbosity);
 | 
						|
 | 
						|
    if ((decoded_params.libs && !tvm_emulator_set_libraries(tvm, decoded_params.libs.value().c_str())) ||
 | 
						|
        !tvm_emulator_set_c7(tvm, decoded_params.address.c_str(), decoded_params.unixtime, decoded_params.balance,
 | 
						|
                             decoded_params.rand_seed_hex.c_str(), config) ||
 | 
						|
        (decoded_params.prev_blocks_info &&
 | 
						|
         !tvm_emulator_set_prev_blocks_info(tvm, decoded_params.prev_blocks_info.value().c_str())) ||
 | 
						|
        (decoded_params.gas_limit > 0 && !tvm_emulator_set_gas_limit(tvm, decoded_params.gas_limit)) ||
 | 
						|
        !tvm_emulator_set_debug_enabled(tvm, decoded_params.debug_enabled)) {
 | 
						|
        tvm_emulator_destroy(tvm);
 | 
						|
        return strdup(R"({"fail":true,"message":"Can't set params"})");
 | 
						|
    }
 | 
						|
 | 
						|
    auto res = tvm_emulator_run_get_method(tvm, decoded_params.method_id, stack);
 | 
						|
 | 
						|
    tvm_emulator_destroy(tvm);
 | 
						|
 | 
						|
    const char* output = nullptr;
 | 
						|
    {
 | 
						|
        td::JsonBuilder jb;
 | 
						|
        auto json_obj = jb.enter_object();
 | 
						|
        json_obj("output", td::JsonRaw(td::Slice(res)));
 | 
						|
        json_obj("logs", logger.get_string());
 | 
						|
        json_obj.leave();
 | 
						|
        output = strdup(jb.string_builder().as_cslice().c_str());
 | 
						|
    }
 | 
						|
    free((void*) res);
 | 
						|
 | 
						|
    return output;
 | 
						|
}
 | 
						|
 | 
						|
} |