mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated vm (breaking compatibility)
- updated vm - new actor scheduler - updated tonlib - updated DNS smartcontract
This commit is contained in:
parent
9e4816e7f6
commit
e27fb1e09c
100 changed files with 3692 additions and 1299 deletions
|
@ -35,6 +35,7 @@
|
|||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/PathView.h"
|
||||
#include "td/utils/tests.h"
|
||||
|
@ -70,7 +71,7 @@ TEST(Tonlib, Text) {
|
|||
auto cs = vm::load_cell_slice(cb.finalize());
|
||||
auto cs2 = cs;
|
||||
cs.print_rec(std::cerr);
|
||||
CHECK(block::gen::t_Text.validate_exact(cs2));
|
||||
CHECK(block::gen::t_Text.validate_exact_upto(1024, cs2));
|
||||
auto got_str = vm::CellText::load(cs).move_as_ok();
|
||||
ASSERT_EQ(str, got_str);
|
||||
}
|
||||
|
@ -506,12 +507,32 @@ TEST(Tonlib, KeysApi) {
|
|||
sync_send(client, make_object<tonlib_api::deleteKey>(
|
||||
make_object<tonlib_api::key>(new_imported_key->public_key_, new_imported_key->secret_.copy())))
|
||||
.move_as_ok();
|
||||
td::Ed25519::PrivateKey pkey(exported_raw_key->data_.copy());
|
||||
auto raw_imported_key = sync_send(client, make_object<tonlib_api::importUnencryptedKey>(new_local_password.copy(),
|
||||
std::move(exported_raw_key)))
|
||||
.move_as_ok();
|
||||
|
||||
CHECK(raw_imported_key->public_key_ == key->public_key_);
|
||||
CHECK(raw_imported_key->secret_ != key->secret_);
|
||||
|
||||
auto other_public_key = td::Ed25519::generate_private_key().move_as_ok().get_public_key().move_as_ok();
|
||||
std::string text = "hello world";
|
||||
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_Data>> elements;
|
||||
elements.push_back(make_object<tonlib_api::msg_dataEncryptedText>(
|
||||
SimpleEncryptionV2::encrypt_data(text, other_public_key, pkey).move_as_ok().as_slice().str()));
|
||||
|
||||
auto decrypted =
|
||||
sync_send(client, make_object<tonlib_api::msg_decrypt>(
|
||||
make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(key->public_key_, raw_imported_key->secret_.copy()),
|
||||
new_local_password.copy()),
|
||||
make_object<tonlib_api::msg_dataArray>(std::move(elements))))
|
||||
.move_as_ok();
|
||||
|
||||
downcast_call(*decrypted->elements_[0],
|
||||
td::overloaded([](auto &) { UNREACHABLE(); },
|
||||
[&](tonlib_api::msg_dataDecryptedText &decrypted) { CHECK(decrypted.text_ == text); }));
|
||||
}
|
||||
|
||||
TEST(Tonlib, ConfigCache) {
|
||||
|
|
|
@ -234,7 +234,7 @@ td::Result<QueryId> create_send_grams_query(Client& client, const Wallet& source
|
|||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message>> msgs;
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (encrypted) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(std::move(message));
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(std::move(message));
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(std::move(message));
|
||||
}
|
||||
|
@ -310,6 +310,13 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transactions>> get_transaction
|
|||
return std::move(got_transactions);
|
||||
}
|
||||
|
||||
std::string read_text(tonlib_api::msg_Data& data) {
|
||||
std::string text;
|
||||
downcast_call(data, td::overloaded([](auto& other) {}, [&](tonlib_api::msg_dataText& data) { text = data.text_; },
|
||||
[&](tonlib_api::msg_dataDecryptedText& data) { text = data.text_; }));
|
||||
return text;
|
||||
}
|
||||
|
||||
td::Status transfer_grams(Client& client, const Wallet& wallet, std::string address, td::int64 amount,
|
||||
bool fast = false) {
|
||||
auto src_state = get_account_state(client, wallet.address);
|
||||
|
@ -320,7 +327,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
bool encrypt = true;
|
||||
auto r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
|
||||
if (r_query_id.is_error()) {
|
||||
LOG(INFO) << "Send query WITHOUT message encryption";
|
||||
LOG(INFO) << "Send query WITHOUT message encryption " << r_query_id.error();
|
||||
encrypt = false;
|
||||
r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
|
||||
} else {
|
||||
|
@ -363,7 +370,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
const auto& txn = tr->transactions_[0];
|
||||
CHECK(txn->in_msg_->body_hash_ == query_info.body_hash);
|
||||
ASSERT_EQ(1u, txn->out_msgs_.size());
|
||||
ASSERT_EQ(message, txn->out_msgs_[0]->message_);
|
||||
ASSERT_EQ(message, read_text(*txn->out_msgs_[0]->msg_data_));
|
||||
lt = txn->out_msgs_[0]->created_lt_;
|
||||
auto fee_difference = fees.first.sum() - txn->fee_;
|
||||
first_fee = txn->fee_;
|
||||
|
@ -389,7 +396,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
}
|
||||
ASSERT_EQ(new_src_state.address, txn->in_msg_->source_);
|
||||
if (!encrypt) {
|
||||
ASSERT_EQ(message, txn->in_msg_->message_);
|
||||
ASSERT_EQ(message, read_text(*txn->in_msg_->msg_data_));
|
||||
}
|
||||
auto fee_difference = fees.second.sum() - txn->fee_;
|
||||
auto desc = PSTRING() << fee_difference << " storage:[" << fees.second.storage_fee << " vs " << txn->storage_fee_
|
||||
|
@ -550,19 +557,11 @@ void test_multisig(Client& client, const Wallet& giver_wallet) {
|
|||
void dns_resolve(Client& client, const Wallet& dns, std::string name) {
|
||||
using namespace ton::tonlib_api;
|
||||
auto address = dns.get_address();
|
||||
while (true) {
|
||||
auto resolved =
|
||||
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 0)).move_as_ok();
|
||||
CHECK(resolved->entries_.size() == 1);
|
||||
LOG(INFO) << to_string(resolved);
|
||||
if (resolved->entries_[0]->category_ == -1) {
|
||||
auto entry = ton::move_tl_object_as<dns_entryDataNextResolver>(resolved->entries_[0]->entry_);
|
||||
address = std::move(entry->resolver_);
|
||||
continue;
|
||||
}
|
||||
LOG(INFO) << "OK";
|
||||
break;
|
||||
}
|
||||
auto resolved =
|
||||
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 4)).move_as_ok();
|
||||
CHECK(resolved->entries_.size() == 1);
|
||||
LOG(INFO) << to_string(resolved);
|
||||
LOG(INFO) << "OK";
|
||||
}
|
||||
|
||||
void test_dns(Client& client, const Wallet& giver_wallet) {
|
||||
|
@ -580,10 +579,10 @@ void test_dns(Client& client, const Wallet& giver_wallet) {
|
|||
make_object<dns_entry>("A", -1, make_object<dns_entryDataNextResolver>(A_B.get_address()))));
|
||||
auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok();
|
||||
actions.push_back(make_object<dns_actionSet>(
|
||||
make_object<dns_entry>("B.A", -1, make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
|
||||
make_object<dns_entry>("B", -1, make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
|
||||
auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok();
|
||||
actions.push_back(
|
||||
make_object<dns_actionSet>(make_object<dns_entry>("C.B.A", 1, make_object<dns_entryDataText>("Hello dns"))));
|
||||
make_object<dns_actionSet>(make_object<dns_entry>("C", 1, make_object<dns_entryDataText>("Hello dns"))));
|
||||
auto init_A_B_C = create_update_dns_query(client, A_B_C, std::move(actions)).move_as_ok();
|
||||
|
||||
LOG(INFO) << "Send dns init queries";
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "KeyValue.h"
|
||||
|
||||
#include "td/utils/filesystem.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
|
|
@ -63,6 +63,24 @@ struct GetAccountState {
|
|||
td::optional<ton::BlockIdExt> block_id;
|
||||
using ReturnType = td::unique_ptr<AccountState>;
|
||||
};
|
||||
|
||||
struct RemoteRunSmcMethod {
|
||||
block::StdAddress address;
|
||||
td::optional<ton::BlockIdExt> block_id;
|
||||
ton::SmartContract::Args args;
|
||||
bool need_result{false};
|
||||
|
||||
using ReturnType = RemoteRunSmcMethodReturnType;
|
||||
};
|
||||
|
||||
struct RemoteRunSmcMethodReturnType {
|
||||
ton::SmartContract::State smc_state;
|
||||
ton::BlockIdExt block_id;
|
||||
// result
|
||||
// c7
|
||||
// libs
|
||||
};
|
||||
|
||||
struct GetPrivateKey {
|
||||
KeyStorage::InputKey input_key;
|
||||
using ReturnType = KeyStorage::PrivateKey;
|
||||
|
@ -120,6 +138,16 @@ static block::AccountState create_account_state(ton::tl_object_ptr<ton::lite_api
|
|||
res.state = std::move(from->state_);
|
||||
return res;
|
||||
}
|
||||
static block::AccountState create_account_state(ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult>& from) {
|
||||
block::AccountState res;
|
||||
res.blk = ton::create_block_id(from->id_);
|
||||
res.shard_blk = ton::create_block_id(from->shardblk_);
|
||||
res.shard_proof = std::move(from->shard_proof_);
|
||||
res.proof = std::move(from->proof_);
|
||||
res.state = std::move(from->state_proof_);
|
||||
res.is_virtualized = from->mode_ > 0;
|
||||
return res;
|
||||
}
|
||||
struct RawAccountState {
|
||||
td::int64 balance = -1;
|
||||
|
||||
|
@ -373,7 +401,6 @@ class AccountState {
|
|||
if (o_revision) {
|
||||
wallet_type_ = WalletType::WalletV3;
|
||||
wallet_revision_ = o_revision.value();
|
||||
LOG(ERROR) << "!!!" << wallet_revision_;
|
||||
set_new_state({ton::WalletV3::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)});
|
||||
return wallet_type_;
|
||||
}
|
||||
|
@ -381,7 +408,6 @@ class AccountState {
|
|||
if (o_revision) {
|
||||
wallet_type_ = WalletType::HighloadWalletV2;
|
||||
wallet_revision_ = o_revision.value();
|
||||
LOG(ERROR) << "!!!" << wallet_revision_;
|
||||
set_new_state(
|
||||
{ton::HighloadWalletV2::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)});
|
||||
return wallet_type_;
|
||||
|
@ -390,7 +416,6 @@ class AccountState {
|
|||
if (o_revision) {
|
||||
wallet_type_ = WalletType::ManualDns;
|
||||
wallet_revision_ = o_revision.value();
|
||||
LOG(ERROR) << "!!!" << wallet_revision_;
|
||||
auto dns = ton::ManualDns::create(key, wallet_id_, wallet_revision_);
|
||||
set_new_state(dns->get_state());
|
||||
return wallet_type_;
|
||||
|
@ -841,6 +866,119 @@ class GetTransactionHistory : public td::actor::Actor {
|
|||
}
|
||||
};
|
||||
|
||||
class RemoteRunSmcMethod : public td::actor::Actor {
|
||||
public:
|
||||
RemoteRunSmcMethod(ExtClientRef ext_client_ref, int_api::RemoteRunSmcMethod query, td::actor::ActorShared<> parent,
|
||||
td::Promise<int_api::RemoteRunSmcMethod::ReturnType>&& promise)
|
||||
: query_(std::move(query)), promise_(std::move(promise)), parent_(std::move(parent)) {
|
||||
client_.set_client(ext_client_ref);
|
||||
}
|
||||
|
||||
private:
|
||||
int_api::RemoteRunSmcMethod query_;
|
||||
td::Promise<int_api::RemoteRunSmcMethod::ReturnType> promise_;
|
||||
td::actor::ActorShared<> parent_;
|
||||
ExtClient client_;
|
||||
|
||||
void with_run_method_result(
|
||||
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult>> r_run_method_result) {
|
||||
check(do_with_run_method_result(std::move(r_run_method_result)));
|
||||
}
|
||||
|
||||
td::Status do_with_run_method_result(
|
||||
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult>> r_run_method_result) {
|
||||
TRY_RESULT(run_method_result, std::move(r_run_method_result));
|
||||
TRY_RESULT_PREFIX(state, TRY_VM(do_with_run_method_result(std::move(run_method_result))),
|
||||
TonlibError::ValidateAccountState());
|
||||
promise_.set_value(std::move(state));
|
||||
stop();
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Result<int_api::RemoteRunSmcMethod::ReturnType> do_with_run_method_result(
|
||||
ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult> run_method_result) {
|
||||
auto account_state = create_account_state(run_method_result);
|
||||
TRY_RESULT(info, account_state.validate(query_.block_id.value(), query_.address));
|
||||
auto serialized_state = account_state.state.clone();
|
||||
int_api::RemoteRunSmcMethod::ReturnType res;
|
||||
res.block_id = query_.block_id.value();
|
||||
auto cell = info.root;
|
||||
if (cell.is_null()) {
|
||||
return res;
|
||||
}
|
||||
block::gen::Account::Record_account account;
|
||||
if (!tlb::unpack_cell(cell, account)) {
|
||||
return td::Status::Error("Failed to unpack Account");
|
||||
}
|
||||
|
||||
block::gen::AccountStorage::Record storage;
|
||||
if (!tlb::csr_unpack(account.storage, storage)) {
|
||||
return td::Status::Error("Failed to unpack AccountStorage");
|
||||
}
|
||||
auto state_tag = block::gen::t_AccountState.get_tag(*storage.state);
|
||||
if (state_tag < 0) {
|
||||
return td::Status::Error("Failed to parse AccountState tag");
|
||||
}
|
||||
if (state_tag != block::gen::AccountState::account_active) {
|
||||
return td::Status::Error("Account is not active");
|
||||
}
|
||||
block::gen::AccountState::Record_account_active state;
|
||||
if (!tlb::csr_unpack(storage.state, state)) {
|
||||
return td::Status::Error("Failed to parse AccountState");
|
||||
}
|
||||
block::gen::StateInit::Record state_init;
|
||||
if (!tlb::csr_unpack(state.x, state_init)) {
|
||||
return td::Status::Error("Failed to parse StateInit");
|
||||
}
|
||||
state_init.code->prefetch_maybe_ref(res.smc_state.code);
|
||||
state_init.data->prefetch_maybe_ref(res.smc_state.data);
|
||||
return res;
|
||||
}
|
||||
|
||||
void with_last_block(td::Result<LastBlockState> r_last_block) {
|
||||
check(do_with_last_block(std::move(r_last_block)));
|
||||
}
|
||||
|
||||
td::Status with_block_id() {
|
||||
TRY_RESULT(method_id, query_.args.get_method_id());
|
||||
TRY_RESULT(serialized_stack, query_.args.get_serialized_stack());
|
||||
client_.send_query(
|
||||
//liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult;
|
||||
ton::lite_api::liteServer_runSmcMethod(
|
||||
0x1f, ton::create_tl_lite_block_id(query_.block_id.value()),
|
||||
ton::create_tl_object<ton::lite_api::liteServer_accountId>(query_.address.workchain, query_.address.addr),
|
||||
method_id, std::move(serialized_stack)),
|
||||
[self = this](auto r_state) { self->with_run_method_result(std::move(r_state)); },
|
||||
query_.block_id.value().id.seqno);
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status do_with_last_block(td::Result<LastBlockState> r_last_block) {
|
||||
TRY_RESULT(last_block, std::move(r_last_block));
|
||||
query_.block_id = std::move(last_block.last_block_id);
|
||||
with_block_id();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
if (query_.block_id) {
|
||||
check(with_block_id());
|
||||
} else {
|
||||
client_.with_last_block(
|
||||
[self = this](td::Result<LastBlockState> r_last_block) { self->with_last_block(std::move(r_last_block)); });
|
||||
}
|
||||
}
|
||||
|
||||
void check(td::Status status) {
|
||||
if (status.is_error()) {
|
||||
promise_.set_error(std::move(status));
|
||||
stop();
|
||||
}
|
||||
}
|
||||
void hangup() override {
|
||||
check(TonlibError::Cancelled());
|
||||
}
|
||||
};
|
||||
|
||||
class GetRawAccountState : public td::actor::Actor {
|
||||
public:
|
||||
GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::optional<ton::BlockIdExt> block_id,
|
||||
|
@ -882,8 +1020,8 @@ class GetRawAccountState : public td::actor::Actor {
|
|||
res.block_id = block_id_.value();
|
||||
res.info = std::move(info);
|
||||
auto cell = res.info.root;
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Account.print_ref(outp, cell);
|
||||
//std::ostringstream outp;
|
||||
//block::gen::t_Account.print_ref(outp, cell);
|
||||
//LOG(INFO) << outp.str();
|
||||
if (cell.is_null()) {
|
||||
return res;
|
||||
|
@ -1693,6 +1831,50 @@ struct ToRawTransactions {
|
|||
return td::Status::Error("Failed to unpack Message");
|
||||
}
|
||||
|
||||
td::Ref<vm::CellSlice> body;
|
||||
if (message.body->prefetch_long(1) == 0) {
|
||||
body = std::move(message.body);
|
||||
body.write().advance(1);
|
||||
} else {
|
||||
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
|
||||
}
|
||||
auto body_cell = vm::CellBuilder().append_cellslice(*body).finalize();
|
||||
auto body_hash = body_cell->get_hash().as_slice().str();
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (body->size() >= 32 && static_cast<td::uint32>(body->prefetch_long(32)) <= 1) {
|
||||
auto type = body.write().fetch_long(32);
|
||||
td::Status status;
|
||||
|
||||
auto r_body_message = vm::CellString::load(body.write());
|
||||
LOG_IF(WARNING, r_body_message.is_error()) << "Failed to parse a message: " << r_body_message.error();
|
||||
|
||||
if (r_body_message.is_ok()) {
|
||||
if (type == 0) {
|
||||
LOG(ERROR) << "OK " << r_body_message.ok();
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(r_body_message.move_as_ok());
|
||||
} else {
|
||||
LOG(ERROR) << "TRY DECRYPT";
|
||||
auto encrypted_message = r_body_message.move_as_ok();
|
||||
auto r_decrypted_message = [&]() -> td::Result<std::string> {
|
||||
if (!private_key_) {
|
||||
return TonlibError::EmptyField("private_key");
|
||||
}
|
||||
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(encrypted_message, private_key_.value()));
|
||||
return decrypted.as_slice().str();
|
||||
}();
|
||||
if (r_decrypted_message.is_ok()) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(r_decrypted_message.move_as_ok());
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(encrypted_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!data) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)));
|
||||
}
|
||||
|
||||
auto tag = block::gen::CommonMsgInfo().get_tag(*message.info);
|
||||
if (tag < 0) {
|
||||
return td::Status::Error("Failed to read CommonMsgInfo tag");
|
||||
|
@ -1710,41 +1892,10 @@ struct ToRawTransactions {
|
|||
TRY_RESULT(fwd_fee, to_balance(msg_info.fwd_fee));
|
||||
TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee));
|
||||
auto created_lt = static_cast<td::int64>(msg_info.created_lt);
|
||||
td::Ref<vm::CellSlice> body;
|
||||
if (message.body->prefetch_long(1) == 0) {
|
||||
body = std::move(message.body);
|
||||
body.write().advance(1);
|
||||
} else {
|
||||
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
|
||||
}
|
||||
auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str();
|
||||
std::string body_message;
|
||||
bool is_encrypted = false;
|
||||
if (body->size() >= 32 && body->prefetch_long(32) <= 1) {
|
||||
auto type = body.write().fetch_long(32);
|
||||
auto r_body_message = vm::CellString::load(body.write());
|
||||
if (type == 1) {
|
||||
LOG(ERROR) << "TRY DECRYPT";
|
||||
r_body_message = [&]() -> td::Result<std::string> {
|
||||
TRY_RESULT(message, std::move(r_body_message));
|
||||
if (!private_key_) {
|
||||
return TonlibError::EmptyField("private_key");
|
||||
}
|
||||
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(message, private_key_.value()));
|
||||
is_encrypted = true;
|
||||
return decrypted.as_slice().str();
|
||||
}();
|
||||
}
|
||||
if (r_body_message.is_ok()) {
|
||||
body_message = r_body_message.move_as_ok();
|
||||
} else {
|
||||
LOG(WARNING) << "Failed to parse a message: " << r_body_message.error();
|
||||
}
|
||||
}
|
||||
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance, fwd_fee,
|
||||
ihr_fee, created_lt, std::move(body_hash),
|
||||
std::move(body_message), is_encrypted);
|
||||
std::move(data));
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_in_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
|
||||
|
@ -1752,16 +1903,8 @@ struct ToRawTransactions {
|
|||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
|
||||
}
|
||||
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
||||
td::Ref<vm::CellSlice> body;
|
||||
if (message.body->prefetch_long(1) == 0) {
|
||||
body = std::move(message.body);
|
||||
body.write().advance(1);
|
||||
} else {
|
||||
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
|
||||
}
|
||||
auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str();
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0, 0, 0, 0, std::move(body_hash),
|
||||
"", false);
|
||||
std::move(data));
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_out_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
|
||||
|
@ -1769,7 +1912,8 @@ struct ToRawTransactions {
|
|||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
|
||||
}
|
||||
TRY_RESULT(src, to_std_address(msg_info.src));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, "", "", false);
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, std::move(body_hash),
|
||||
std::move(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2027,8 +2171,12 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
struct Action {
|
||||
block::StdAddress destination;
|
||||
td::int64 amount;
|
||||
|
||||
bool is_encrypted{false};
|
||||
bool should_encrypt;
|
||||
std::string message;
|
||||
|
||||
td::Ref<vm::Cell> body;
|
||||
};
|
||||
bool allow_send_to_uninited_{false};
|
||||
std::vector<Action> actions_;
|
||||
|
@ -2064,27 +2212,36 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
res.amount = message.amount_;
|
||||
auto status =
|
||||
downcast_call2<td::Status>(*message.data_, td::overloaded(
|
||||
[&](tonlib_api::msg_dataText& text) {
|
||||
// Use this limit as a preventive check
|
||||
if (text.text_.size() > ton::Wallet::max_message_size) {
|
||||
return TonlibError::MessageTooLong();
|
||||
}
|
||||
res.message = text.text_;
|
||||
res.should_encrypt = false;
|
||||
[&](tonlib_api::msg_dataRaw& text) {
|
||||
TRY_RESULT(body, vm::std_boc_deserialize(text.body_));
|
||||
res.body = std::move(body);
|
||||
return td::Status::OK();
|
||||
},
|
||||
[&](tonlib_api::msg_dataEncryptedText& text) {
|
||||
// Use this limit as a preventive check
|
||||
if (text.text_.size() > ton::Wallet::max_message_size) {
|
||||
return TonlibError::MessageTooLong();
|
||||
}
|
||||
[&](tonlib_api::msg_dataText& text) {
|
||||
res.message = text.text_;
|
||||
res.should_encrypt = false;
|
||||
res.is_encrypted = false;
|
||||
return td::Status::OK();
|
||||
},
|
||||
[&](tonlib_api::msg_dataDecryptedText& text) {
|
||||
res.message = text.text_;
|
||||
if (!has_private_key_) {
|
||||
return TonlibError::EmptyField("input_key");
|
||||
}
|
||||
res.should_encrypt = true;
|
||||
res.is_encrypted = true;
|
||||
return td::Status::OK();
|
||||
},
|
||||
[&](tonlib_api::msg_dataEncryptedText& text) {
|
||||
res.message = text.text_;
|
||||
res.should_encrypt = false;
|
||||
res.is_encrypted = true;
|
||||
return td::Status::OK();
|
||||
}));
|
||||
// Use this limit as a preventive check
|
||||
if (res.message.size() > ton::Wallet::max_message_size) {
|
||||
return TonlibError::MessageTooLong();
|
||||
}
|
||||
TRY_STATUS(std::move(status));
|
||||
return res;
|
||||
}
|
||||
|
@ -2301,7 +2458,9 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
if (action.amount == source_->get_balance()) {
|
||||
gift.gramms = -1;
|
||||
}
|
||||
if (action.should_encrypt) {
|
||||
if (action.body.not_null()) {
|
||||
gift.body = action.body;
|
||||
} else if (action.should_encrypt) {
|
||||
LOG(ERROR) << "TRY ENCRYPT";
|
||||
if (!private_key_) {
|
||||
return TonlibError::EmptyField("private_key");
|
||||
|
@ -2311,7 +2470,8 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
}
|
||||
auto wallet = destination->get_wallet();
|
||||
TRY_RESULT_PREFIX(public_key, wallet->get_public_key(),
|
||||
TonlibError::AccountActionUnsupported("Get public key (in destination)"));
|
||||
TonlibError::AccountActionUnsupported(PSLICE() << "Get public key (in destination) : "
|
||||
<< destination->get_wallet_type()));
|
||||
TRY_RESULT_PREFIX(encrypted_message,
|
||||
SimpleEncryptionV2::encrypt_data(action.message, public_key, private_key_.value()),
|
||||
TonlibError::Internal());
|
||||
|
@ -2319,7 +2479,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
gift.is_encrypted = true;
|
||||
} else {
|
||||
gift.message = action.message;
|
||||
gift.is_encrypted = false;
|
||||
gift.is_encrypted = action.is_encrypted;
|
||||
}
|
||||
i++;
|
||||
gifts.push_back(gift);
|
||||
|
@ -2349,7 +2509,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
|
||||
if (source_->get_wallet_type() == AccountState::Giver) {
|
||||
valid_until = 0;
|
||||
private_key_ = td::Ed25519::PrivateKey(td::SecureString(std::string('\0', 32)));
|
||||
private_key_ = td::Ed25519::PrivateKey(td::SecureString(std::string(32, '\0')));
|
||||
}
|
||||
|
||||
return with_wallet(*source_->get_wallet());
|
||||
|
@ -2387,6 +2547,40 @@ td::Status TonlibClient::do_request(tonlib_api::createQuery& request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::msg_decrypt& request,
|
||||
td::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise) {
|
||||
if (!request.input_key_) {
|
||||
return TonlibError::EmptyField("input_key");
|
||||
}
|
||||
if (!request.data_) {
|
||||
return TonlibError::EmptyField("data");
|
||||
}
|
||||
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
|
||||
make_request(
|
||||
int_api::GetPrivateKey{std::move(input_key)},
|
||||
promise.wrap([elements = std::move(request.data_)](auto key) mutable {
|
||||
auto private_key = td::Ed25519::PrivateKey(std::move(key.private_key));
|
||||
elements->elements_ = td::transform(std::move(elements->elements_), [&private_key](auto msg) {
|
||||
if (!msg) {
|
||||
return std::move(msg);
|
||||
}
|
||||
using ReturnType = tonlib_api::object_ptr<tonlib_api::msg_Data>;
|
||||
return downcast_call2<ReturnType>(
|
||||
*msg, td::overloaded([&msg](auto&) { return std::move(msg); },
|
||||
[&msg, &private_key](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType {
|
||||
auto r_decrypted = SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key);
|
||||
if (r_decrypted.is_error()) {
|
||||
return std::move(msg);
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(
|
||||
r_decrypted.move_as_ok().as_slice().str());
|
||||
}));
|
||||
});
|
||||
return std::move(elements);
|
||||
}));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::raw_createQuery& request,
|
||||
td::Promise<object_ptr<tonlib_api::query_info>>&& promise) {
|
||||
if (!request.destination_) {
|
||||
|
@ -2698,19 +2892,32 @@ td::Result<tonlib_api::object_ptr<tonlib_api::dns_EntryData>> to_tonlib_api(
|
|||
}
|
||||
|
||||
void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl,
|
||||
td::optional<ton::BlockIdExt> block_id, td::unique_ptr<AccountState> smc,
|
||||
td::optional<ton::BlockIdExt> block_id, DnsFinishData dns_finish_data,
|
||||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
|
||||
if (smc->get_wallet_type() != AccountState::WalletType::ManualDns) {
|
||||
return promise.set_error(TonlibError::AccountTypeUnexpected("ManualDns"));
|
||||
}
|
||||
block_id = smc->get_block_id();
|
||||
auto dns = ton::ManualDns::create(smc->get_smc_state());
|
||||
block_id = dns_finish_data.block_id;
|
||||
// TODO: check if the smartcontract supports Dns interface
|
||||
// TODO: should we use some DnsInterface instead of ManualDns?
|
||||
auto dns = ton::ManualDns::create(dns_finish_data.smc_state);
|
||||
TRY_RESULT_PROMISE(promise, entries, dns->resolve(name, category));
|
||||
|
||||
if (entries.size() == 1 && entries[0].category == -1 && entries[0].name != name && ttl > 0 &&
|
||||
entries[0].data.type == ton::ManualDns::EntryData::Type::NextResolver) {
|
||||
td::Slice got_name = entries[0].name;
|
||||
if (got_name.size() >= name.size()) {
|
||||
TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is too long"));
|
||||
}
|
||||
auto dot_position = name.size() - got_name.size() - 1;
|
||||
auto suffix = name.substr(dot_position + 1);
|
||||
auto prefix = name.substr(0, dot_position);
|
||||
if (name[dot_position] != '.') {
|
||||
TRY_STATUS_PROMISE(promise, td::Status::Error("next resolver error: domain split not at a component boundary "));
|
||||
}
|
||||
if (suffix != got_name) {
|
||||
TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is not a suffix of the query"));
|
||||
}
|
||||
|
||||
auto address = entries[0].data.data.get<ton::ManualDns::EntryDataNextResolver>().resolver;
|
||||
return do_dns_request(name, category, ttl - 1, std::move(block_id), address, std::move(promise));
|
||||
return do_dns_request(prefix, category, ttl - 1, std::move(block_id), address, std::move(promise));
|
||||
}
|
||||
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::dns_entry>> api_entries;
|
||||
|
@ -2726,9 +2933,29 @@ void TonlibClient::do_dns_request(std::string name, td::int32 category, td::int3
|
|||
td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
|
||||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
|
||||
auto block_id_copy = block_id.copy();
|
||||
make_request(int_api::GetAccountState{address, std::move(block_id_copy)},
|
||||
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl,
|
||||
std::move(block_id)));
|
||||
td::Promise<DnsFinishData> new_promise =
|
||||
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id));
|
||||
|
||||
if (0) {
|
||||
make_request(int_api::GetAccountState{address, std::move(block_id_copy)},
|
||||
new_promise.wrap([](auto&& account_state) {
|
||||
return DnsFinishData{account_state->get_block_id(), account_state->get_smc_state()};
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TRY_RESULT_PROMISE(promise, args, ton::DnsInterface::resolve_args(name, category));
|
||||
int_api::RemoteRunSmcMethod query;
|
||||
query.address = std::move(address);
|
||||
query.args = std::move(args);
|
||||
query.block_id = std::move(block_id_copy);
|
||||
query.need_result = false;
|
||||
|
||||
make_request(std::move(query), new_promise.wrap([](auto&& run_method) {
|
||||
return DnsFinishData{run_method.block_id, run_method.smc_state};
|
||||
}));
|
||||
;
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
|
||||
|
@ -3015,6 +3242,14 @@ td::Status TonlibClient::do_request(int_api::GetAccountState request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(int_api::RemoteRunSmcMethod request,
|
||||
td::Promise<int_api::RemoteRunSmcMethod::ReturnType>&& promise) {
|
||||
auto actor_id = actor_id_++;
|
||||
actors_[actor_id] = td::actor::create_actor<RemoteRunSmcMethod>(
|
||||
"RemoteRunSmcMethod", client_.get_client(), std::move(request), actor_shared(this, actor_id), std::move(promise));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&& promise) {
|
||||
TRY_RESULT(pk, key_storage_.load_private_key(std::move(request.input_key)));
|
||||
promise.set_value(std::move(pk));
|
||||
|
|
|
@ -42,6 +42,9 @@ struct GetAccountState;
|
|||
struct GetPrivateKey;
|
||||
struct GetDnsResolver;
|
||||
struct SendMessage;
|
||||
struct RemoteRunSmcMethod;
|
||||
struct RemoteRunSmcMethodReturnType;
|
||||
|
||||
inline std::string to_string(const int_api::SendMessage&) {
|
||||
return "Send message";
|
||||
}
|
||||
|
@ -278,6 +281,8 @@ class TonlibClient : public td::actor::Actor {
|
|||
|
||||
td::Status do_request(tonlib_api::createQuery& request, td::Promise<object_ptr<tonlib_api::query_info>>&& promise);
|
||||
|
||||
td::Status do_request(tonlib_api::msg_decrypt& request, td::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise);
|
||||
|
||||
td::int64 next_smc_id_{0};
|
||||
std::map<td::int64, td::unique_ptr<AccountState>> smcs_;
|
||||
|
||||
|
@ -299,13 +304,18 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
|
||||
block::StdAddress address, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
struct DnsFinishData {
|
||||
ton::BlockIdExt block_id;
|
||||
ton::SmartContract::State smc_state;
|
||||
};
|
||||
void finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
|
||||
td::unique_ptr<AccountState> smc,
|
||||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
DnsFinishData dns_finish_data, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
|
||||
td::Status do_request(int_api::GetAccountState request, td::Promise<td::unique_ptr<AccountState>>&&);
|
||||
td::Status do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&&);
|
||||
td::Status do_request(int_api::GetDnsResolver request, td::Promise<block::StdAddress>&&);
|
||||
td::Status do_request(int_api::RemoteRunSmcMethod request,
|
||||
td::Promise<int_api::RemoteRunSmcMethodReturnType>&& promise);
|
||||
td::Status do_request(int_api::SendMessage request, td::Promise<td::Unit>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::liteServer_getInfo& request,
|
||||
|
|
|
@ -345,10 +345,14 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::TerminalIO::out()
|
||||
<< "gethistory <key_id> - get history fo simple wallet with requested key (last 10 transactions)\n";
|
||||
td::TerminalIO::out() << "init <key_id> - init simple wallet with requested key\n";
|
||||
td::TerminalIO::out() << "transfer[f] <from_key_id> <to_key_id> <amount> - transfer <amount> of grams from "
|
||||
"<from_key_id> to <to_key_id>.\n"
|
||||
<< "\t<from_key_id> could also be 'giver'\n"
|
||||
<< "\t<to_key_id> could also be 'giver' or smartcontract address\n";
|
||||
td::TerminalIO::out() << "transfer[f][F][e][k][c] <from_key_id> (<to_key_id> <value> <message>|<file_name>) - "
|
||||
"make transfer from <from_key_id>\n"
|
||||
<< "\t 'f' modifier - allow send to uninited account\n"
|
||||
<< "\t 'F' modifier - read list of messages from <file_name> (in same format <to_key_id> "
|
||||
"<value> <message>, one per line)\n"
|
||||
<< "\t 'e' modifier - encrypt all messages\n"
|
||||
<< "\t 'k' modifier - use fake key\n"
|
||||
<< "\t 'c' modifier - just esmitate fees\n";
|
||||
} else if (cmd == "genkey") {
|
||||
generate_key();
|
||||
} else if (cmd == "exit" || cmd == "quit") {
|
||||
|
@ -445,15 +449,6 @@ class TonlibCli : public td::actor::Actor {
|
|||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
if (resolved->entries_[0]->name_ == name) {
|
||||
td::TerminalIO::out() << "Done\n";
|
||||
for (auto& entry : resolved->entries_) {
|
||||
td::TerminalIO::out() << " " << entry->name_ << " " << entry->category_ << " "
|
||||
<< tonlib::to_dns_entry_data(*entry->entry_).move_as_ok() << "\n";
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
if (resolved->entries_[0]->entry_->get_id() == tonlib_api::dns_entryDataNextResolver::ID && ttl != 0) {
|
||||
td::TerminalIO::out() << "Redirect resolver\n";
|
||||
auto entry = tonlib_api::move_object_as<tonlib_api::dns_entryDataNextResolver>(resolved->entries_[0]->entry_);
|
||||
|
@ -461,7 +456,12 @@ class TonlibCli : public td::actor::Actor {
|
|||
promise.send_closure(actor_id(this), &TonlibCli::do_dns_resolve, name, category, 0));
|
||||
return;
|
||||
}
|
||||
promise.set_error(td::Status::Error("Failed to resolve"));
|
||||
td::TerminalIO::out() << "Done\n";
|
||||
for (auto& entry : resolved->entries_) {
|
||||
td::TerminalIO::out() << " " << entry->name_ << " " << entry->category_ << " "
|
||||
<< tonlib::to_dns_entry_data(*entry->entry_).move_as_ok() << "\n";
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void dns_resolve(td::ConstParser& parser, td::Promise<td::Unit> promise) {
|
||||
|
@ -531,7 +531,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
: nullptr;
|
||||
send_query(tonlib_api::make_object<tonlib_api::createQuery>(std::move(key), std::move(address.address), 60,
|
||||
std::move(action)),
|
||||
promise.send_closure(actor_id(this), &TonlibCli::transfer2));
|
||||
promise.send_closure(actor_id(this), &TonlibCli::transfer2, false));
|
||||
}
|
||||
|
||||
void remote_time(td::Promise<td::Unit> promise) {
|
||||
|
@ -1389,13 +1389,21 @@ class TonlibCli : public td::actor::Actor {
|
|||
} else {
|
||||
sb << " From " << t->in_msg_->source_;
|
||||
}
|
||||
if (!t->in_msg_->message_.empty()) {
|
||||
sb << " ";
|
||||
if (t->in_msg_->is_message_encrypted_) {
|
||||
sb << "e";
|
||||
auto print_msg_data = [](td::StringBuilder& sb,
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data>& msg_data) {
|
||||
if (!msg_data) {
|
||||
return;
|
||||
}
|
||||
sb << "msg{" << t->in_msg_->message_ << "}";
|
||||
}
|
||||
sb << " ";
|
||||
downcast_call(*msg_data,
|
||||
td::overloaded([&](tonlib_api::msg_dataRaw& raw) { sb << "<unknown message>"; },
|
||||
[&](tonlib_api::msg_dataText& raw) { sb << "{" << raw.text_ << "}"; },
|
||||
[&](tonlib_api::msg_dataEncryptedText& raw) { sb << "<encrypted>"; },
|
||||
[&](tonlib_api::msg_dataDecryptedText& raw) {
|
||||
sb << "decrypted{" << raw.text_ << "}";
|
||||
}));
|
||||
};
|
||||
print_msg_data(sb, t->in_msg_->msg_data_);
|
||||
for (auto& ot : t->out_msgs_) {
|
||||
sb << "\n\t";
|
||||
if (ot->destination_.empty()) {
|
||||
|
@ -1404,13 +1412,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
sb << " To " << ot->destination_;
|
||||
}
|
||||
sb << " " << Grams{td::uint64(ot->value_)};
|
||||
if (!ot->message_.empty()) {
|
||||
sb << " ";
|
||||
if (ot->is_message_encrypted_) {
|
||||
sb << "e";
|
||||
}
|
||||
sb << "msg{" << ot->message_ << "}";
|
||||
}
|
||||
print_msg_data(sb, ot->msg_data_);
|
||||
}
|
||||
sb << "\n";
|
||||
}
|
||||
|
@ -1423,6 +1425,8 @@ class TonlibCli : public td::actor::Actor {
|
|||
bool from_file = false;
|
||||
bool force = false;
|
||||
bool use_encryption = false;
|
||||
bool use_fake_key = false;
|
||||
bool estimate_fees = false;
|
||||
if (cmd != "init") {
|
||||
td::ConstParser cmd_parser(cmd);
|
||||
cmd_parser.advance(td::Slice("transfer").size());
|
||||
|
@ -1435,6 +1439,10 @@ class TonlibCli : public td::actor::Actor {
|
|||
force = true;
|
||||
} else if (c == 'e') {
|
||||
use_encryption = true;
|
||||
} else if (c == 'k') {
|
||||
use_fake_key = true;
|
||||
} else if (c == 'c') {
|
||||
estimate_fees = true;
|
||||
} else {
|
||||
cmd_promise.set_error(td::Status::Error(PSLICE() << "Unknown suffix '" << c << "'"));
|
||||
return;
|
||||
|
@ -1464,7 +1472,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
|
||||
if (use_encryption) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(message.str());
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(message.str());
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(message.str());
|
||||
}
|
||||
|
@ -1495,25 +1503,38 @@ class TonlibCli : public td::actor::Actor {
|
|||
|
||||
td::Slice password; // empty by default
|
||||
using tonlib_api::make_object;
|
||||
auto key = !from_address.secret.empty()
|
||||
? make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(from_address.public_key, from_address.secret.copy()),
|
||||
td::SecureString(password))
|
||||
: nullptr;
|
||||
tonlib_api::object_ptr<tonlib_api::InputKey> key =
|
||||
!from_address.secret.empty()
|
||||
? make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(from_address.public_key, from_address.secret.copy()),
|
||||
td::SecureString(password))
|
||||
: nullptr;
|
||||
if (use_fake_key) {
|
||||
key = make_object<tonlib_api::inputKeyFake>();
|
||||
}
|
||||
|
||||
bool allow_send_to_uninited = force;
|
||||
|
||||
send_query(make_object<tonlib_api::createQuery>(
|
||||
std::move(key), std::move(from_address.address), 60,
|
||||
make_object<tonlib_api::actionMsg>(std::move(messages), allow_send_to_uninited)),
|
||||
cmd_promise.send_closure(actor_id(this), &TonlibCli::transfer2));
|
||||
cmd_promise.send_closure(actor_id(this), &TonlibCli::transfer2, estimate_fees));
|
||||
}
|
||||
|
||||
void transfer2(td::Result<tonlib_api::object_ptr<tonlib_api::query_info>> r_info, td::Promise<td::Unit> cmd_promise) {
|
||||
send_query(tonlib_api::make_object<tonlib_api::query_send>(r_info.ok()->id_), cmd_promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Transfer sent!\n";
|
||||
return td::Unit();
|
||||
}));
|
||||
void transfer2(bool estimate_fees, td::Result<tonlib_api::object_ptr<tonlib_api::query_info>> r_info,
|
||||
td::Promise<td::Unit> cmd_promise) {
|
||||
if (estimate_fees) {
|
||||
send_query(tonlib_api::make_object<tonlib_api::query_estimateFees>(r_info.ok()->id_, true),
|
||||
cmd_promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Extimated fees: " << to_string(info);
|
||||
return td::Unit();
|
||||
}));
|
||||
} else {
|
||||
send_query(tonlib_api::make_object<tonlib_api::query_send>(r_info.ok()->id_), cmd_promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Transfer sent: " << to_string(info);
|
||||
return td::Unit();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void get_hints(td::Slice prefix) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue