1
0
Fork 0
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:
ton 2020-02-28 14:28:47 +04:00
parent 9e4816e7f6
commit e27fb1e09c
100 changed files with 3692 additions and 1299 deletions

View file

@ -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) {

View file

@ -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";

View file

@ -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"

View file

@ -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"

View file

@ -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));

View file

@ -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,

View file

@ -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) {