(std::move(data), true);
if (F.is_error()) {
abort_query(F.move_as_error());
return;
}
auto f = F.move_as_ok();
state_proof_ = std::move(f->state_proof_);
config_proof_ = std::move(f->config_proof_);
finish_query();
}
void HttpQueryConfig::finish_query() {
if (promise_) {
auto page = [&]() -> std::string {
HttpAnswer A{"config", prefix_};
A.set_block_id(block_id_);
auto R = block::check_extract_state_proof(block_id_, state_proof_.as_slice(), config_proof_.as_slice());
if (R.is_error()) {
A.abort(PSTRING() << "masterchain state proof for " << block_id_.to_str()
<< " is invalid : " << R.move_as_error());
return A.finish();
}
try {
auto res = block::Config::extract_from_state(R.move_as_ok(), 0);
if (res.is_error()) {
A.abort(PSTRING() << "cannot unpack configuration: " << res.move_as_error());
return A.finish();
}
auto config = res.move_as_ok();
if (params_.size() > 0) {
A << "params: ";
for (int i : params_) {
auto value = config->get_config_param(i);
if (value.not_null()) {
A << "" << i << " ";
}
}
A << "
";
for (int i : params_) {
auto value = config->get_config_param(i);
if (value.not_null()) {
A << HttpAnswer::ConfigParam{i, value};
} else {
A << HttpAnswer::Error{td::Status::Error(404, PSTRING() << "empty param " << i)};
}
}
} else {
A << "params: ";
config->foreach_config_param([&](int i, td::Ref value) {
if (value.not_null()) {
A << "" << i << " ";
}
return true;
});
A << "
";
config->foreach_config_param([&](int i, td::Ref value) {
if (value.not_null()) {
A << HttpAnswer::ConfigParam{i, value};
}
return true;
});
}
} catch (vm::VmError &err) {
A.abort(PSTRING() << "error while traversing configuration: " << err.get_msg());
} catch (vm::VmVirtError &err) {
A.abort(PSTRING() << "virtualization error while traversing configuration: " << err.get_msg());
}
return A.finish();
}();
auto R = MHD_create_response_from_buffer(page.length(), const_cast(page.c_str()), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(R, "Content-Type", "text/html");
promise_.set_value(std::move(R));
}
stop();
}
HttpQuerySendForm::HttpQuerySendForm(std::string prefix, td::Promise promise)
: HttpQueryCommon(prefix, std::move(promise)) {
}
HttpQuerySendForm::HttpQuerySendForm(std::map opts, std::string prefix,
td::Promise promise)
: HttpQueryCommon(prefix, std::move(promise)) {
}
void HttpQuerySendForm::start_up() {
finish_query();
}
void HttpQuerySendForm::finish_query() {
if (promise_) {
auto page = [&]() -> std::string {
HttpAnswer A{"send", prefix_};
A << "";
return A.finish();
}();
auto R = MHD_create_response_from_buffer(page.length(), const_cast(page.c_str()), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(R, "Content-Type", "text/html");
promise_.set_value(std::move(R));
}
stop();
}
HttpQuerySend::HttpQuerySend(std::string prefix, td::BufferSlice data, td::Promise promise)
: HttpQueryCommon(prefix, std::move(promise)), data_(std::move(data)) {
}
HttpQuerySend::HttpQuerySend(std::map opts, std::string prefix,
td::Promise promise)
: HttpQueryCommon(prefix, std::move(promise)) {
auto it = opts.find("filedata");
if (it != opts.end()) {
data_ = td::BufferSlice{it->second};
} else {
error_ = td::Status::Error("no file data");
return;
}
}
void HttpQuerySend::start_up() {
if (error_.is_error()) {
abort_query(std::move(error_));
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &HttpQuerySend::abort_query, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &HttpQuerySend::got_result, R.move_as_ok());
}
});
auto query =
ton::serialize_tl_object(ton::create_tl_object(std::move(data_)), true);
td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
std::move(query), std::move(P));
}
void HttpQuerySend::got_result(td::BufferSlice data) {
auto F = ton::fetch_tl_object(std::move(data), true);
if (F.is_error()) {
abort_query(F.move_as_error());
} else {
status_ = F.move_as_ok()->status_;
}
finish_query();
}
void HttpQuerySend::finish_query() {
if (promise_) {
auto page = [&]() -> std::string {
HttpAnswer A{"send", prefix_};
if (status_ >= 0) {
A << HttpAnswer::Notification{"success"};
} else {
A << HttpAnswer::Error{td::Status::Error(status_, "failed")};
}
return A.finish();
}();
auto R = MHD_create_response_from_buffer(page.length(), const_cast(page.c_str()), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(R, "Content-Type", "text/html");
promise_.set_value(std::move(R));
}
stop();
}
HttpQueryRunMethod::HttpQueryRunMethod(ton::BlockIdExt block_id, block::StdAddress addr, std::string method_name,
std::vector params, std::string prefix,
td::Promise promise)
: HttpQueryCommon(std::move(prefix), std::move(promise))
, block_id_(block_id)
, addr_(addr)
, method_name_(std::move(method_name))
, params_(std::move(params)) {
}
HttpQueryRunMethod::HttpQueryRunMethod(std::map opts, std::string prefix,
td::Promise promise)
: HttpQueryCommon(std::move(prefix), std::move(promise)) {
auto R = parse_block_id(opts, true);
if (R.is_ok()) {
block_id_ = R.move_as_ok();
if (!block_id_.is_valid()) {
block_id_.id.workchain = ton::masterchainId;
block_id_.id.shard = ton::shardIdAll;
block_id_.id.seqno = static_cast(0xffffffff);
block_id_.root_hash.set_zero();
block_id_.file_hash.set_zero();
}
} else {
error_ = R.move_as_error();
return;
}
auto R2 = parse_account_addr(opts);
if (R2.is_ok()) {
addr_ = R2.move_as_ok();
} else {
error_ = R2.move_as_error();
return;
}
auto it = opts.find("method");
if (it == opts.end()) {
error_ = td::Status::Error("no method");
return;
} else {
method_name_ = it->second;
}
it = opts.find("params");
if (it != opts.end()) {
auto R3 = vm::parse_stack_entries(it->second);
if (R3.is_error()) {
error_ = R3.move_as_error();
return;
}
params_ = R3.move_as_ok();
}
}
void HttpQueryRunMethod::start_up_query() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &HttpQueryRunMethod::abort_query, R.move_as_error_prefix("litequery failed: "));
} else {
td::actor::send_closure(SelfId, &HttpQueryRunMethod::got_account, R.move_as_ok());
}
});
auto a = ton::create_tl_object(addr_.workchain, addr_.addr);
auto query = ton::serialize_tl_object(ton::create_tl_object(
ton::create_tl_lite_block_id(block_id_), std::move(a)),
true);
td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
std::move(query), std::move(P));
}
void HttpQueryRunMethod::got_account(td::BufferSlice data) {
auto F = ton::fetch_tl_object(std::move(data), true);
if (F.is_error()) {
abort_query(F.move_as_error());
return;
}
auto f = F.move_as_ok();
data_ = std::move(f->state_);
proof_ = std::move(f->proof_);
shard_proof_ = std::move(f->shard_proof_);
block_id_ = ton::create_block_id(f->id_);
res_block_id_ = ton::create_block_id(f->shardblk_);
finish_query();
}
void HttpQueryRunMethod::finish_query() {
if (promise_) {
auto page = [&]() -> std::string {
HttpAnswer A{"account", prefix_};
A.set_account_id(addr_);
A.set_block_id(res_block_id_);
block::AccountState account_state;
account_state.blk = block_id_;
account_state.shard_blk = res_block_id_;
account_state.shard_proof = std::move(shard_proof_);
account_state.proof = std::move(proof_);
account_state.state = std::move(data_);
auto r_info = account_state.validate(block_id_, addr_);
if (r_info.is_error()) {
A.abort(r_info.move_as_error());
return A.finish();
}
auto info = r_info.move_as_ok();
if (info.root.is_null()) {
A.abort(PSTRING() << "account state of " << addr_ << " is empty (cannot run method `" << method_name_ << "`)");
return A.finish();
}
block::gen::Account::Record_account acc;
block::gen::AccountStorage::Record store;
block::CurrencyCollection balance;
if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) &&
balance.validate_unpack(store.balance))) {
A.abort("error unpacking account state");
return A.finish();
}
int tag = block::gen::t_AccountState.get_tag(*store.state);
switch (tag) {
case block::gen::AccountState::account_uninit:
A.abort(PSTRING() << "account " << addr_ << " not initialized yet (cannot run any methods)");
return A.finish();
case block::gen::AccountState::account_frozen:
A.abort(PSTRING() << "account " << addr_ << " frozen (cannot run any methods)");
return A.finish();
}
CHECK(store.state.write().fetch_ulong(1) == 1); // account_init$1 _:StateInit = AccountState;
block::gen::StateInit::Record state_init;
CHECK(tlb::csr_unpack(store.state, state_init));
auto code = state_init.code->prefetch_ref();
auto data = state_init.data->prefetch_ref();
auto stack = td::make_ref(std::move(params_));
td::int64 method_id = (td::crc16(td::Slice{method_name_}) & 0xffff) | 0x10000;
stack.write().push_smallint(method_id);
long long gas_limit = vm::GasLimits::infty;
// OstreamLogger ostream_logger(ctx.error_stream);
// auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr);
vm::GasLimits gas{gas_limit};
LOG(DEBUG) << "creating VM";
vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()};
vm.set_c7(prepare_vm_c7(info.gen_utime, info.gen_lt, acc.addr, balance)); // tuple with SmartContractInfo
// vm.incr_stack_trace(1); // enable stack dump after each step
int exit_code = ~vm.run();
if (exit_code != 0) {
A.abort(PSTRING() << "VM terminated with error code " << exit_code);
return A.finish();
}
stack = vm.get_stack_ref();
{
std::ostringstream os;
os << "result: ";
stack->dump(os, 3);
A << HttpAnswer::CodeBlock{os.str()};
}
return A.finish();
}();
auto R = MHD_create_response_from_buffer(page.length(), const_cast(page.c_str()), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(R, "Content-Type", "text/html");
promise_.set_value(std::move(R));
}
stop();
}
HttpQueryStatus::HttpQueryStatus(std::string prefix, td::Promise promise)
: HttpQueryCommon(std::move(prefix), std::move(promise)) {
}
HttpQueryStatus::HttpQueryStatus(std::map opts, std::string prefix,
td::Promise promise)
: HttpQueryCommon(std::move(prefix), std::move(promise)) {
}
void HttpQueryStatus::start_up() {
if (error_.is_error()) {
abort_query(std::move(error_));
return;
}
auto P =
td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &HttpQueryStatus::abort_query, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &HttpQueryStatus::got_results, R.move_as_ok());
}
});
td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::get_results, 60, std::move(P));
}
void HttpQueryStatus::got_results(CoreActorInterface::RemoteNodeStatusList results) {
results_ = std::move(results);
finish_query();
}
void HttpQueryStatus::finish_query() {
if (promise_) {
auto page = [&]() -> std::string {
std::map> m;
HttpAnswer A{"status", prefix_};
A << "\n"
<< "
\n"
<< "ip | ";
for (auto &x : results_.results) {
A << "" << static_cast(x->ts_.at_unix()) << " | ";
}
A << "
\n";
for (td::uint32 i = 0; i < results_.ips.size(); i++) {
A << "";
if (results_.ips[i].is_valid()) {
A << "" << results_.ips[i] << " | ";
} else {
A << "hidden | ";
}
td::uint32 j = 0;
for (auto &X : results_.results) {
if (!X->values_[i].is_valid()) {
A << "FAIL | ";
} else {
if (m[j].count(X->values_[i].id.seqno) == 0) {
m[j].insert(X->values_[i].id.seqno);
A << "values_[i]} << "\">" << X->values_[i].id.seqno
<< " | ";
} else {
A << "" << X->values_[i].id.seqno << " | ";
}
}
j++;
}
A << "
\n";
}
A << "
";
return A.finish();
}();
auto R = MHD_create_response_from_buffer(page.length(), const_cast(page.c_str()), MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(R, "Content-Type", "text/html");
promise_.set_value(std::move(R));
}
stop();
}