mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
tonlib updated
- updated tonlib - added documentation - speed up full node synchronization
This commit is contained in:
parent
07b26e2259
commit
ac3eb1a7b8
30 changed files with 1351 additions and 160 deletions
|
@ -14,10 +14,12 @@ set(TONLIB_SOURCE
|
|||
tonlib/KeyStorage.cpp
|
||||
tonlib/LastBlock.cpp
|
||||
tonlib/LastBlockStorage.cpp
|
||||
tonlib/Logging.cpp
|
||||
tonlib/TestGiver.cpp
|
||||
tonlib/TestWallet.cpp
|
||||
tonlib/TonlibClient.cpp
|
||||
tonlib/utils.cpp
|
||||
tonlib/Wallet.cpp
|
||||
|
||||
tonlib/Client.h
|
||||
tonlib/Config.h
|
||||
|
@ -28,11 +30,13 @@ set(TONLIB_SOURCE
|
|||
tonlib/KeyStorage.h
|
||||
tonlib/LastBlock.h
|
||||
tonlib/LastBlockStorage.h
|
||||
tonlib/Logging.h
|
||||
tonlib/TestGiver.h
|
||||
tonlib/TestWallet.h
|
||||
tonlib/TonlibCallback.h
|
||||
tonlib/TonlibClient.h
|
||||
tonlib/utils.h
|
||||
tonlib/Wallet.h
|
||||
|
||||
tonlib/keys/bip39.cpp
|
||||
tonlib/keys/DecryptedKey.cpp
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "tonlib/utils.h"
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/TestWallet.h"
|
||||
#include "tonlib/Wallet.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/TonlibClient.h"
|
||||
#include "tonlib/Client.h"
|
||||
|
@ -116,6 +117,37 @@ TEST(Tonlib, TestWallet) {
|
|||
CHECK(vm::std_boc_deserialize(new_wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> get_wallet_source() {
|
||||
return fift::compile_asm(load_source("smartcont/wallet-code.fif"), "", false).move_as_ok();
|
||||
}
|
||||
|
||||
TEST(Tonlib, Wallet) {
|
||||
LOG(ERROR) << td::base64_encode(std_boc_serialize(get_wallet_source()).move_as_ok());
|
||||
CHECK(get_wallet_source()->get_hash() == Wallet::get_init_code()->get_hash());
|
||||
// TODO: fix ater new-wallet supports new type of wallet
|
||||
//auto fift_output = fift::mem_run_fift(load_source("smartcont/new-wallet.fif"), {"aba", "0"}).move_as_ok();
|
||||
|
||||
//auto new_wallet_pk = fift_output.source_lookup.read_file("new-wallet.pk").move_as_ok().data;
|
||||
//auto new_wallet_query = fift_output.source_lookup.read_file("new-wallet-query.boc").move_as_ok().data;
|
||||
//auto new_wallet_addr = fift_output.source_lookup.read_file("new-wallet.addr").move_as_ok().data;
|
||||
|
||||
//td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}};
|
||||
//auto pub_key = priv_key.get_public_key().move_as_ok();
|
||||
//auto init_state = TestWallet::get_init_state(pub_key);
|
||||
//auto init_message = TestWallet::get_init_message(priv_key);
|
||||
//auto address = GenericAccount::get_address(0, init_state);
|
||||
|
||||
//CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));
|
||||
|
||||
//td::Ref<vm::Cell> res = GenericAccount::create_ext_message(address, init_state, init_message);
|
||||
|
||||
//LOG(ERROR) << "-------";
|
||||
//vm::load_cell_slice(res).print_rec(std::cerr);
|
||||
//LOG(ERROR) << "-------";
|
||||
//vm::load_cell_slice(vm::std_boc_deserialize(new_wallet_query).move_as_ok()).print_rec(std::cerr);
|
||||
//CHECK(vm::std_boc_deserialize(new_wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
||||
}
|
||||
|
||||
TEST(Tonlib, TestGiver) {
|
||||
auto address =
|
||||
block::StdAddress::parse("-1:60c04141c6a7b96d68615e7a91d265ad0f3a9a922e9ae9c901d4fa83f5d3c0d0").move_as_ok();
|
||||
|
@ -346,9 +378,9 @@ TEST(Tonlib, KeysApi) {
|
|||
//importKey local_password:bytes mnemonic_password:bytes exported_key:exportedKey = Key;
|
||||
auto new_local_password = td::SecureString("new_local_password");
|
||||
// import already existed key
|
||||
sync_send(client, make_object<tonlib_api::importKey>(new_local_password.copy(), mnemonic_password.copy(),
|
||||
make_object<tonlib_api::exportedKey>(copy_word_list())))
|
||||
.ensure_error();
|
||||
//sync_send(client, make_object<tonlib_api::importKey>(new_local_password.copy(), mnemonic_password.copy(),
|
||||
//make_object<tonlib_api::exportedKey>(copy_word_list())))
|
||||
//.ensure_error();
|
||||
|
||||
{
|
||||
auto export_password = td::SecureString("export password");
|
||||
|
@ -361,7 +393,9 @@ TEST(Tonlib, KeysApi) {
|
|||
export_password.copy()))
|
||||
.move_as_ok();
|
||||
|
||||
sync_send(client, make_object<tonlib_api::deleteKey>(key->public_key_)).move_as_ok();
|
||||
sync_send(client,
|
||||
make_object<tonlib_api::deleteKey>(make_object<tonlib_api::key>(key->public_key_, key->secret_.copy())))
|
||||
.move_as_ok();
|
||||
|
||||
sync_send(client, make_object<tonlib_api::importEncryptedKey>(
|
||||
new_local_password.copy(), wrong_export_password.copy(),
|
||||
|
@ -374,10 +408,13 @@ TEST(Tonlib, KeysApi) {
|
|||
make_object<tonlib_api::exportedEncryptedKey>(exported_encrypted_key->data_.copy())))
|
||||
.move_as_ok();
|
||||
CHECK(imported_encrypted_key->public_key_ == key->public_key_);
|
||||
key = std::move(imported_encrypted_key);
|
||||
}
|
||||
|
||||
//deleteKey public_key:bytes = Ok;
|
||||
sync_send(client, make_object<tonlib_api::deleteKey>(key->public_key_)).move_as_ok();
|
||||
sync_send(client,
|
||||
make_object<tonlib_api::deleteKey>(make_object<tonlib_api::key>(key->public_key_, key->secret_.copy())))
|
||||
.move_as_ok();
|
||||
|
||||
auto err1 = sync_send(client, make_object<tonlib_api::importKey>(
|
||||
new_local_password.copy(), td::SecureString("wrong password"),
|
||||
|
@ -410,11 +447,13 @@ TEST(Tonlib, KeysApi) {
|
|||
LOG(ERROR) << to_string(exported_pem_key);
|
||||
|
||||
//importPemKey exported_key:exportedPemKey key_password:bytes = Key;
|
||||
sync_send(client, make_object<tonlib_api::importPemKey>(
|
||||
new_local_password.copy(), pem_password.copy(),
|
||||
make_object<tonlib_api::exportedPemKey>(exported_pem_key->pem_.copy())))
|
||||
.ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::deleteKey>(key->public_key_)).move_as_ok();
|
||||
//sync_send(client, make_object<tonlib_api::importPemKey>(
|
||||
//new_local_password.copy(), pem_password.copy(),
|
||||
//make_object<tonlib_api::exportedPemKey>(exported_pem_key->pem_.copy())))
|
||||
//.ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::deleteKey>(
|
||||
make_object<tonlib_api::key>(imported_key->public_key_, imported_key->secret_.copy())))
|
||||
.move_as_ok();
|
||||
sync_send(client, make_object<tonlib_api::importPemKey>(
|
||||
new_local_password.copy(), td::SecureString("wrong pem password"),
|
||||
make_object<tonlib_api::exportedPemKey>(exported_pem_key->pem_.copy())))
|
||||
|
|
|
@ -28,7 +28,7 @@ td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref
|
|||
.finalize();
|
||||
}
|
||||
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) {
|
||||
return block::StdAddress(workchain_id, init_state->get_hash().bits(), false);
|
||||
return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/);
|
||||
}
|
||||
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body) {
|
||||
|
|
|
@ -24,14 +24,23 @@
|
|||
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
namespace tonlib {
|
||||
std::string to_file_name(td::Slice public_key) {
|
||||
return td::buffer_to_hex(public_key);
|
||||
std::string to_file_name_old(const KeyStorage::Key &key) {
|
||||
return td::buffer_to_hex(key.public_key);
|
||||
}
|
||||
|
||||
std::string KeyStorage::to_file_path(td::Slice public_key) {
|
||||
return directory_ + TD_DIR_SLASH + to_file_name(public_key);
|
||||
std::string KeyStorage::to_file_path_old(const Key &key) {
|
||||
return directory_ + TD_DIR_SLASH + to_file_name_old(key);
|
||||
}
|
||||
|
||||
std::string to_file_name(const KeyStorage::Key &key) {
|
||||
return td::buffer_to_hex(td::sha512(key.secret.as_slice()).substr(0, 32));
|
||||
}
|
||||
|
||||
std::string KeyStorage::to_file_path(const Key &key) {
|
||||
return directory_ + TD_DIR_SLASH + to_file_name(key);
|
||||
}
|
||||
td::Status KeyStorage::set_directory(std::string directory) {
|
||||
TRY_RESULT(path, td::realpath(directory));
|
||||
|
@ -52,8 +61,8 @@ td::Result<KeyStorage::Key> KeyStorage::save_key(const DecryptedKey &decrypted_k
|
|||
|
||||
auto size = encrypted_key.encrypted_data.size();
|
||||
|
||||
LOG(ERROR) << "SAVE " << to_file_name(res.public_key);
|
||||
TRY_RESULT(to_file, td::FileFd::open(to_file_path(res.public_key), td::FileFd::CreateNew | td::FileFd::Write));
|
||||
LOG(ERROR) << "SAVE " << to_file_name(res);
|
||||
TRY_RESULT(to_file, td::FileFd::open(to_file_path(res), td::FileFd::CreateNew | td::FileFd::Write));
|
||||
TRY_RESULT(written, to_file.write(encrypted_key.encrypted_data));
|
||||
if (written != static_cast<size_t>(size)) {
|
||||
return td::Status::Error(PSLICE() << "Failed to write file: written " << written << " bytes instead of " << size);
|
||||
|
@ -74,7 +83,16 @@ td::Result<KeyStorage::Key> KeyStorage::create_new_key(td::Slice local_password,
|
|||
}
|
||||
|
||||
td::Result<DecryptedKey> KeyStorage::export_decrypted_key(InputKey input_key) {
|
||||
TRY_RESULT(encrypted_data, td::read_file_secure(to_file_path(input_key.key.public_key)));
|
||||
auto r_encrypted_data = td::read_file_secure(to_file_path(input_key.key));
|
||||
if (r_encrypted_data.is_error()) {
|
||||
r_encrypted_data = td::read_file_secure(to_file_path_old(input_key.key));
|
||||
if (r_encrypted_data.is_ok()) {
|
||||
LOG(WARNING) << "Restore private from deprecated location " << to_file_path_old(input_key.key) << " --> "
|
||||
<< to_file_path(input_key.key);
|
||||
td::rename(to_file_path_old(input_key.key), to_file_path(input_key.key)).ignore();
|
||||
}
|
||||
}
|
||||
TRY_RESULT(encrypted_data, std::move(r_encrypted_data));
|
||||
EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)),
|
||||
std::move(input_key.key.secret)};
|
||||
return encrypted_key.decrypt(std::move(input_key.local_password));
|
||||
|
@ -94,8 +112,8 @@ td::Result<KeyStorage::PrivateKey> KeyStorage::load_private_key(InputKey input_k
|
|||
return std::move(private_key);
|
||||
}
|
||||
|
||||
td::Status KeyStorage::delete_key(td::Slice public_key) {
|
||||
return td::unlink(to_file_path(public_key));
|
||||
td::Status KeyStorage::delete_key(const Key &key) {
|
||||
return td::unlink(to_file_path(key));
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password,
|
||||
|
@ -122,6 +140,7 @@ td::Result<KeyStorage::Key> KeyStorage::change_local_password(InputKey input_key
|
|||
Key res;
|
||||
res.public_key = std::move(input_key.key.public_key);
|
||||
res.secret = std::move(new_secret);
|
||||
TRY_STATUS(td::copy_file(to_file_path(input_key.key), to_file_path(res)));
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ class KeyStorage {
|
|||
td::Result<ExportedEncryptedKey> export_encrypted_key(InputKey input_key, td::Slice key_password);
|
||||
td::Result<Key> change_local_password(InputKey input_key, td::Slice new_local_password);
|
||||
|
||||
td::Status delete_key(td::Slice public_key);
|
||||
td::Status delete_key(const Key& key);
|
||||
|
||||
td::Result<Key> import_key(td::Slice local_password, td::Slice mnemonic_password, ExportedKey exported_key);
|
||||
td::Result<Key> import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key);
|
||||
|
@ -72,6 +72,7 @@ class KeyStorage {
|
|||
td::Result<Key> save_key(const DecryptedKey& mnemonic, td::Slice local_password);
|
||||
td::Result<DecryptedKey> export_decrypted_key(InputKey input_key);
|
||||
|
||||
std::string to_file_path(td::Slice public_key);
|
||||
std::string to_file_path(const Key& key);
|
||||
std::string to_file_path_old(const Key& key);
|
||||
};
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -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-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "LastBlockStorage.h"
|
||||
|
||||
#include "td/utils/as.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-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "tonlib/LastBlock.h"
|
||||
|
|
137
tonlib/tonlib/Logging.cpp
Normal file
137
tonlib/tonlib/Logging.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
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-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "Logging.h"
|
||||
|
||||
#include "auto/tl/tonlib_api.h"
|
||||
|
||||
#include "td/utils/FileLog.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
static std::mutex logging_mutex;
|
||||
static td::FileLog file_log;
|
||||
static td::TsLog ts_log(&file_log);
|
||||
static td::NullLog null_log;
|
||||
|
||||
td::int32 VERBOSITY_NAME(abc) = VERBOSITY_NAME(DEBUG);
|
||||
td::int32 VERBOSITY_NAME(bcd) = VERBOSITY_NAME(DEBUG);
|
||||
#define ADD_TAG(tag) \
|
||||
{ #tag, &VERBOSITY_NAME(tag) }
|
||||
static const std::map<td::Slice, int *> log_tags{ADD_TAG(abc), ADD_TAG(bcd)};
|
||||
#undef ADD_TAG
|
||||
|
||||
td::Status Logging::set_current_stream(tonlib_api::object_ptr<tonlib_api::LogStream> stream) {
|
||||
if (stream == nullptr) {
|
||||
return td::Status::Error("Log stream must not be empty");
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(logging_mutex);
|
||||
switch (stream->get_id()) {
|
||||
case tonlib_api::logStreamDefault::ID:
|
||||
td::log_interface = td::default_log_interface;
|
||||
return td::Status::OK();
|
||||
case tonlib_api::logStreamFile::ID: {
|
||||
auto file_stream = tonlib_api::move_object_as<tonlib_api::logStreamFile>(stream);
|
||||
auto max_log_file_size = file_stream->max_file_size_;
|
||||
if (max_log_file_size <= 0) {
|
||||
return td::Status::Error("Max log file size should be positive");
|
||||
}
|
||||
|
||||
TRY_STATUS(file_log.init(file_stream->path_, max_log_file_size));
|
||||
std::atomic_thread_fence(std::memory_order_release); // better than nothing
|
||||
td::log_interface = &ts_log;
|
||||
return td::Status::OK();
|
||||
}
|
||||
case tonlib_api::logStreamEmpty::ID:
|
||||
td::log_interface = &null_log;
|
||||
return td::Status::OK();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::LogStream>> Logging::get_current_stream() {
|
||||
std::lock_guard<std::mutex> lock(logging_mutex);
|
||||
if (td::log_interface == td::default_log_interface) {
|
||||
return tonlib_api::make_object<tonlib_api::logStreamDefault>();
|
||||
}
|
||||
if (td::log_interface == &null_log) {
|
||||
return tonlib_api::make_object<tonlib_api::logStreamEmpty>();
|
||||
}
|
||||
if (td::log_interface == &ts_log) {
|
||||
return tonlib_api::make_object<tonlib_api::logStreamFile>(file_log.get_path().str(),
|
||||
file_log.get_rotate_threshold());
|
||||
}
|
||||
return td::Status::Error("Log stream is unrecognized");
|
||||
}
|
||||
|
||||
td::Status Logging::set_verbosity_level(int new_verbosity_level) {
|
||||
std::lock_guard<std::mutex> lock(logging_mutex);
|
||||
if (0 <= new_verbosity_level && new_verbosity_level <= VERBOSITY_NAME(NEVER)) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + new_verbosity_level);
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
return td::Status::Error("Wrong new verbosity level specified");
|
||||
}
|
||||
|
||||
int Logging::get_verbosity_level() {
|
||||
std::lock_guard<std::mutex> lock(logging_mutex);
|
||||
return GET_VERBOSITY_LEVEL();
|
||||
}
|
||||
|
||||
td::vector<td::string> Logging::get_tags() {
|
||||
return transform(log_tags, [](auto &tag) { return tag.first.str(); });
|
||||
}
|
||||
|
||||
td::Status Logging::set_tag_verbosity_level(td::Slice tag, int new_verbosity_level) {
|
||||
auto it = log_tags.find(tag);
|
||||
if (it == log_tags.end()) {
|
||||
return td::Status::Error("Log tag is not found");
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(logging_mutex);
|
||||
*it->second = td::clamp(new_verbosity_level, 1, VERBOSITY_NAME(NEVER));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<int> Logging::get_tag_verbosity_level(td::Slice tag) {
|
||||
auto it = log_tags.find(tag);
|
||||
if (it == log_tags.end()) {
|
||||
return td::Status::Error("Log tag is not found");
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(logging_mutex);
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
void Logging::add_message(int log_verbosity_level, td::Slice message) {
|
||||
int VERBOSITY_NAME(client) = td::clamp(log_verbosity_level, 0, VERBOSITY_NAME(NEVER));
|
||||
VLOG(client) << message;
|
||||
}
|
||||
|
||||
} // namespace tonlib
|
49
tonlib/tonlib/Logging.h
Normal file
49
tonlib/tonlib/Logging.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "auto/tl/tonlib_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace tonlib {
|
||||
namespace tonlib_api = ton::tonlib_api;
|
||||
|
||||
class Logging {
|
||||
public:
|
||||
static td::Status set_current_stream(tonlib_api::object_ptr<tonlib_api::LogStream> stream);
|
||||
|
||||
static td::Result<tonlib_api::object_ptr<tonlib_api::LogStream>> get_current_stream();
|
||||
|
||||
static td::Status set_verbosity_level(int new_verbosity_level);
|
||||
|
||||
static int get_verbosity_level();
|
||||
|
||||
static std::vector<std::string> get_tags();
|
||||
|
||||
static td::Status set_tag_verbosity_level(td::Slice tag, int new_verbosity_level);
|
||||
|
||||
static td::Result<int> get_tag_verbosity_level(td::Slice tag);
|
||||
|
||||
static void add_message(int log_verbosity_level, td::Slice message);
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
|
@ -34,7 +34,7 @@ vm::CellHash TestGiver::get_init_code_hash() {
|
|||
|
||||
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) {
|
||||
CHECK(message.size() <= 128);
|
||||
CHECK(message.size() <= 124);
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
|
@ -45,7 +45,7 @@ td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr
|
|||
.store_int256(dest_addr, 256);
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
|
||||
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize();
|
||||
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize();
|
||||
return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
|
||||
}
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -40,7 +40,7 @@ td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr
|
|||
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) {
|
||||
CHECK(message.size() <= 128);
|
||||
CHECK(message.size() <= 124);
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
|
@ -48,7 +48,7 @@ td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey&
|
|||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize();
|
||||
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize();
|
||||
auto message_outer = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
|
||||
std::string seq_no(4, 0);
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
#include "tonlib/ExtClientOutbound.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/LastBlock.h"
|
||||
#include "tonlib/Logging.h"
|
||||
#include "tonlib/TestWallet.h"
|
||||
#include "tonlib/Wallet.h"
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/utils.h"
|
||||
#include "tonlib/keys/Mnemonic.h"
|
||||
|
@ -412,8 +414,17 @@ bool TonlibClient::is_static_request(td::int32 id) {
|
|||
case tonlib_api::runTests::ID:
|
||||
case tonlib_api::raw_getAccountAddress::ID:
|
||||
case tonlib_api::testWallet_getAccountAddress::ID:
|
||||
case tonlib_api::wallet_getAccountAddress::ID:
|
||||
case tonlib_api::testGiver_getAccountAddress::ID:
|
||||
case tonlib_api::getBip39Hints::ID:
|
||||
case tonlib_api::setLogStream::ID:
|
||||
case tonlib_api::getLogStream::ID:
|
||||
case tonlib_api::setLogVerbosityLevel::ID:
|
||||
case tonlib_api::getLogVerbosityLevel::ID:
|
||||
case tonlib_api::getLogTags::ID:
|
||||
case tonlib_api::setLogTagVerbosityLevel::ID:
|
||||
case tonlib_api::getLogTagVerbosityLevel::ID:
|
||||
case tonlib_api::addLogMessage::ID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -449,6 +460,12 @@ td::Result<block::StdAddress> get_account_address(const tonlib_api::testWallet_i
|
|||
return GenericAccount::get_address(0 /*zerochain*/, TestWallet::get_init_state(key));
|
||||
}
|
||||
|
||||
td::Result<block::StdAddress> get_account_address(const tonlib_api::wallet_initialAccountState& test_wallet_state) {
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(test_wallet_state.public_key_));
|
||||
auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key));
|
||||
return GenericAccount::get_address(0 /*zerochain*/, Wallet::get_init_state(key));
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::raw_getAccountAddress& request) {
|
||||
auto r_account_address = get_account_address(*request.initital_account_state_);
|
||||
|
@ -465,6 +482,14 @@ tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
|||
}
|
||||
return tonlib_api::make_object<tonlib_api::accountAddress>(r_account_address.ok().rserialize());
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::wallet_getAccountAddress& request) {
|
||||
auto r_account_address = get_account_address(*request.initital_account_state_);
|
||||
if (r_account_address.is_error()) {
|
||||
return status_to_tonlib_api(r_account_address.error());
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::accountAddress>(r_account_address.ok().rserialize());
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::testGiver_getAccountAddress& request) {
|
||||
return tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize());
|
||||
|
@ -601,6 +626,10 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
|
|||
if (body->size() % 8 == 0) {
|
||||
body_message = std::string(body->size() / 8, 0);
|
||||
body->prefetch_bytes(td::MutableSlice(body_message).ubegin(), body->size() / 8);
|
||||
if (body_message.size() >= 4 && body_message[0] == 0 && body_message[1] == 0 && body_message[2] == 0 &&
|
||||
body_message[3] == 0) {
|
||||
body_message = body_message.substr(4);
|
||||
}
|
||||
}
|
||||
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance,
|
||||
|
@ -714,6 +743,21 @@ td::Result<tonlib_api::object_ptr<tonlib_api::testWallet_accountState>> to_testW
|
|||
raw_state.balance, static_cast<td::uint32>(seqno), to_transaction_id(raw_state.info), raw_state.sync_utime);
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::wallet_accountState>> to_wallet_accountState(
|
||||
RawAccountState&& raw_state) {
|
||||
if (raw_state.data.is_null()) {
|
||||
return td::Status::Error(400, "Not a Wallet");
|
||||
}
|
||||
auto ref = raw_state.data->prefetch_ref();
|
||||
auto cs = vm::load_cell_slice(std::move(ref));
|
||||
auto seqno = cs.fetch_ulong(32);
|
||||
if (seqno == cs.fetch_ulong_eof) {
|
||||
return td::Status::Error("Failed to parse seq_no");
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::wallet_accountState>(
|
||||
raw_state.balance, static_cast<td::uint32>(seqno), to_transaction_id(raw_state.info), raw_state.sync_utime);
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::testGiver_accountState>> to_testGiver_accountState(
|
||||
RawAccountState&& raw_state) {
|
||||
if (raw_state.data.is_null()) {
|
||||
|
@ -742,6 +786,10 @@ td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> to_generic_
|
|||
TRY_RESULT(test_wallet, to_testWallet_accountState(std::move(raw_state)));
|
||||
return tonlib_api::make_object<tonlib_api::generic_accountStateTestWallet>(std::move(test_wallet));
|
||||
}
|
||||
if (code_hash == Wallet::get_init_code_hash()) {
|
||||
TRY_RESULT(wallet, to_wallet_accountState(std::move(raw_state)));
|
||||
return tonlib_api::make_object<tonlib_api::generic_accountStateWallet>(std::move(wallet));
|
||||
}
|
||||
if (code_hash == TestGiver::get_init_code_hash()) {
|
||||
TRY_RESULT(test_wallet, to_testGiver_accountState(std::move(raw_state)));
|
||||
return tonlib_api::make_object<tonlib_api::generic_accountStateTestGiver>(std::move(test_wallet));
|
||||
|
@ -858,7 +906,7 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ
|
|||
if (!request.private_key_) {
|
||||
return td::Status::Error(400, "Field private_key must not be empty");
|
||||
}
|
||||
if (request.message_.size() > 128) {
|
||||
if (request.message_.size() > 124) {
|
||||
return td::Status::Error(400, "Message is too long");
|
||||
}
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||
|
@ -896,13 +944,79 @@ td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& requ
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
// Wallet
|
||||
td::Status TonlibClient::do_request(const tonlib_api::wallet_init& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
if (!request.private_key_) {
|
||||
return td::Status::Error(400, "Field private_key must not be empty");
|
||||
}
|
||||
TRY_RESULT(input_key, from_tonlib(*request.private_key_));
|
||||
auto init_state = Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()));
|
||||
auto address = GenericAccount::get_address(0 /*zerochain*/, init_state);
|
||||
TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key)));
|
||||
auto init_message = Wallet::get_init_message(td::Ed25519::PrivateKey(std::move(private_key.private_key)));
|
||||
return do_request(
|
||||
tonlib_api::raw_sendMessage(tonlib_api::make_object<tonlib_api::accountAddress>(address.rserialize()),
|
||||
vm::std_boc_serialize(init_state).move_as_ok().as_slice().str(),
|
||||
vm::std_boc_serialize(init_message).move_as_ok().as_slice().str()),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::wallet_sendGrams& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
if (!request.destination_) {
|
||||
return td::Status::Error(400, "Field destination must not be empty");
|
||||
}
|
||||
if (!request.private_key_) {
|
||||
return td::Status::Error(400, "Field private_key must not be empty");
|
||||
}
|
||||
if (request.message_.size() > 124) {
|
||||
return td::Status::Error(400, "Message is too long");
|
||||
}
|
||||
TRY_RESULT(valid_until, td::narrow_cast_safe<td::uint32>(request.valid_until_));
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||
account_address.bounceable = false;
|
||||
TRY_RESULT(input_key, from_tonlib(*request.private_key_));
|
||||
auto address = GenericAccount::get_address(
|
||||
0 /*zerochain*/, Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy())));
|
||||
TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key)));
|
||||
return do_request(
|
||||
tonlib_api::raw_sendMessage(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(address.rserialize()), "",
|
||||
vm::std_boc_serialize(Wallet::make_a_gift_message(td::Ed25519::PrivateKey(std::move(private_key.private_key)),
|
||||
request.seqno_, valid_until, request.amount_,
|
||||
request.message_, account_address))
|
||||
.move_as_ok()
|
||||
.as_slice()
|
||||
.str()),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::wallet_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::wallet_accountState>>&& promise) {
|
||||
if (!request.account_address_) {
|
||||
return td::Status::Error(400, "Field account_address must not be empty");
|
||||
}
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_));
|
||||
td::actor::create_actor<GetRawAccountState>(
|
||||
"GetAccountState", client_.get_client(), std::move(account_address),
|
||||
[promise = std::move(promise)](td::Result<RawAccountState> r_state) mutable {
|
||||
if (r_state.is_error()) {
|
||||
return promise.set_error(r_state.move_as_error());
|
||||
}
|
||||
promise.set_result(to_wallet_accountState(r_state.move_as_ok()));
|
||||
})
|
||||
.release();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
// TestGiver
|
||||
td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
if (!request.destination_) {
|
||||
return td::Status::Error(400, "Field destination must not be empty");
|
||||
}
|
||||
if (request.message_.size() > 128) {
|
||||
if (request.message_.size() > 124) {
|
||||
return td::Status::Error(400, "Message is too long");
|
||||
}
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||
|
@ -949,61 +1063,219 @@ td::Status TonlibClient::do_request(const tonlib_api::generic_getAccountState& r
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
class TonlibQueryActor : public td::actor::Actor {
|
||||
public:
|
||||
TonlibQueryActor(td::actor::ActorShared<TonlibClient> client) : client_(std::move(client)) {
|
||||
}
|
||||
template <class QueryT>
|
||||
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
|
||||
td::actor::send_lambda(client_,
|
||||
[self = client_.get(), query = std::move(query), promise = std::move(promise)]() mutable {
|
||||
auto status = self.get_actor_unsafe().do_request(query, std::move(promise));
|
||||
if (status.is_error()) {
|
||||
promise.set_error(std::move(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<TonlibClient> client_;
|
||||
};
|
||||
|
||||
class GenericSendGrams : public TonlibQueryActor {
|
||||
public:
|
||||
GenericSendGrams(td::actor::ActorShared<TonlibClient> client, tonlib_api::generic_sendGrams send_grams,
|
||||
td::Promise<tonlib_api::object_ptr<tonlib_api::ok>>&& promise)
|
||||
: TonlibQueryActor(std::move(client)), send_grams_(std::move(send_grams)), promise_(std::move(promise)) {
|
||||
timeout_ = td::Timestamp::in(15);
|
||||
}
|
||||
|
||||
private:
|
||||
tonlib_api::generic_sendGrams send_grams_;
|
||||
td::Promise<tonlib_api::object_ptr<tonlib_api::ok>> promise_;
|
||||
|
||||
enum class SourceAction { Wait, Init, WaitInited, Ok } source_action_ = SourceAction::Wait;
|
||||
tonlib_api::object_ptr<tonlib_api::generic_AccountState> source_state_;
|
||||
block::StdAddress source_address_;
|
||||
td::Timestamp source_next_get_state_;
|
||||
td::Timestamp timeout_;
|
||||
bool has_source_state_query_{false};
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::generic_AccountState> destination_state_;
|
||||
bool is_destination_bounce_{false};
|
||||
|
||||
void check(td::Status status) {
|
||||
if (status.is_error()) {
|
||||
LOG(ERROR) << status;
|
||||
promise_.set_error(std::move(status));
|
||||
return stop();
|
||||
}
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
check(do_start_up());
|
||||
}
|
||||
|
||||
td::Status do_start_up() {
|
||||
if (!send_grams_.destination_) {
|
||||
return td::Status::Error(400, "Field destination must not be empty");
|
||||
}
|
||||
TRY_RESULT(destination_address, block::StdAddress::parse(send_grams_.destination_->account_address_));
|
||||
is_destination_bounce_ = destination_address.bounceable;
|
||||
|
||||
if (!send_grams_.source_) {
|
||||
return td::Status::Error(400, "Field source must not be empty");
|
||||
}
|
||||
TRY_RESULT(source_address, block::StdAddress::parse(send_grams_.source_->account_address_));
|
||||
source_address_ = std::move(source_address);
|
||||
|
||||
send_query(tonlib_api::generic_getAccountState(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(send_grams_.source_->account_address_)),
|
||||
[actor_id = actor_id(this)](auto r_res) {
|
||||
send_closure(actor_id, &GenericSendGrams::on_source_state, std::move(r_res));
|
||||
});
|
||||
send_query(tonlib_api::generic_getAccountState(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(send_grams_.destination_->account_address_)),
|
||||
[actor_id = actor_id(this)](auto r_res) {
|
||||
send_closure(actor_id, &GenericSendGrams::on_destination_state, std::move(r_res));
|
||||
});
|
||||
return do_loop();
|
||||
}
|
||||
|
||||
static tonlib_api::object_ptr<tonlib_api::key> clone(const tonlib_api::object_ptr<tonlib_api::key>& ptr) {
|
||||
if (!ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::key>(ptr->public_key_, ptr->secret_.copy());
|
||||
}
|
||||
|
||||
static tonlib_api::object_ptr<tonlib_api::inputKey> clone(const tonlib_api::object_ptr<tonlib_api::inputKey>& ptr) {
|
||||
if (!ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::inputKey>(clone(ptr->key_), ptr->local_password_.copy());
|
||||
}
|
||||
|
||||
void on_source_state(td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> r_state) {
|
||||
check(do_on_source_state(std::move(r_state)));
|
||||
}
|
||||
|
||||
td::Status do_on_source_state(td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> r_state) {
|
||||
has_source_state_query_ = false;
|
||||
TRY_RESULT(state, std::move(r_state));
|
||||
source_state_ = std::move(state);
|
||||
if (source_action_ == SourceAction::Wait) {
|
||||
source_action_ = SourceAction::Ok;
|
||||
if (false && source_state_->get_id() == tonlib_api::generic_accountStateUninited::ID &&
|
||||
send_grams_.private_key_ && send_grams_.private_key_->key_) {
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(send_grams_.private_key_->key_->public_key_));
|
||||
auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key));
|
||||
auto addr = GenericAccount::get_address(0 /*zerochain*/, TestWallet::get_init_state(key));
|
||||
if (addr.addr == source_address_.addr) {
|
||||
source_action_ = SourceAction::Init;
|
||||
send_query(tonlib_api::testWallet_init(clone(send_grams_.private_key_)),
|
||||
[actor_id = actor_id(this)](auto r_res) {
|
||||
send_closure(actor_id, &GenericSendGrams::on_source_init, std::move(r_res));
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (source_action_ == SourceAction::WaitInited) {
|
||||
if (source_state_->get_id() != tonlib_api::generic_accountStateUninited::ID) {
|
||||
source_action_ = SourceAction::Ok;
|
||||
}
|
||||
}
|
||||
return do_loop();
|
||||
}
|
||||
|
||||
void on_source_init(td::Result<tonlib_api::object_ptr<tonlib_api::ok>> r_ok) {
|
||||
do_on_source_init(std::move(r_ok));
|
||||
}
|
||||
|
||||
td::Status do_on_source_init(td::Result<tonlib_api::object_ptr<tonlib_api::ok>> r_ok) {
|
||||
TRY_RESULT(ok, std::move(r_ok));
|
||||
source_action_ = SourceAction::WaitInited;
|
||||
return do_loop();
|
||||
}
|
||||
|
||||
void on_destination_state(td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> r_state) {
|
||||
check(do_on_destination_state(std::move(r_state)));
|
||||
}
|
||||
|
||||
td::Status do_on_destination_state(td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> r_state) {
|
||||
TRY_RESULT(state, std::move(r_state));
|
||||
destination_state_ = std::move(state);
|
||||
if (destination_state_->get_id() == tonlib_api::generic_accountStateUninited::ID) {
|
||||
//return td::Status::Error("Transfer to uninited wallet");
|
||||
}
|
||||
return do_loop();
|
||||
}
|
||||
|
||||
void alarm() override {
|
||||
check(do_loop());
|
||||
}
|
||||
td::Status do_loop() {
|
||||
if (timeout_.is_in_past()) {
|
||||
return td::Status::Error("Timeout");
|
||||
}
|
||||
alarm_timestamp().relax(timeout_);
|
||||
if (source_action_ == SourceAction::WaitInited && !has_source_state_query_) {
|
||||
if (source_next_get_state_.is_in_past()) {
|
||||
source_next_get_state_ = td::Timestamp::in(1);
|
||||
has_source_state_query_ = true;
|
||||
send_query(tonlib_api::generic_getAccountState(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(send_grams_.source_->account_address_)),
|
||||
[actor_id = actor_id(this)](auto r_res) {
|
||||
send_closure(actor_id, &GenericSendGrams::on_source_state, std::move(r_res));
|
||||
});
|
||||
} else {
|
||||
alarm_timestamp().relax(source_next_get_state_);
|
||||
}
|
||||
}
|
||||
if (source_action_ != SourceAction::Ok || !destination_state_) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
downcast_call(*source_state_,
|
||||
td::overloaded(
|
||||
[&](tonlib_api::generic_accountStateTestGiver& test_giver_state) {
|
||||
send_query(tonlib_api::testGiver_sendGrams(
|
||||
std::move(send_grams_.destination_), test_giver_state.account_state_->seqno_,
|
||||
send_grams_.amount_, std::move(send_grams_.message_)),
|
||||
std::move(promise_));
|
||||
stop();
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) {
|
||||
send_query(tonlib_api::testWallet_sendGrams(
|
||||
std::move(send_grams_.private_key_), std::move(send_grams_.destination_),
|
||||
test_wallet_state.account_state_->seqno_, send_grams_.amount_,
|
||||
std::move(send_grams_.message_)),
|
||||
std::move(promise_));
|
||||
stop();
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateWallet& test_wallet_state) {
|
||||
send_query(tonlib_api::wallet_sendGrams(
|
||||
std::move(send_grams_.private_key_), std::move(send_grams_.destination_),
|
||||
test_wallet_state.account_state_->seqno_, std::numeric_limits<td::uint32>::max(),
|
||||
send_grams_.amount_, std::move(send_grams_.message_)),
|
||||
std::move(promise_));
|
||||
stop();
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateUninited&) {
|
||||
promise_.set_error(td::Status::Error(400, "Account is not inited"));
|
||||
stop();
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateRaw&) {
|
||||
promise_.set_error(td::Status::Error(400, "Unknown account type"));
|
||||
stop();
|
||||
}));
|
||||
return td::Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.source_->account_address_));
|
||||
LOG(INFO) << "Send " << request.amount_ << " nanograms from " << account_address.rserialize();
|
||||
td::actor::create_actor<GetRawAccountState>(
|
||||
"GetAccountState", client_.get_client(), std::move(account_address),
|
||||
[promise = std::move(promise), self = this, actor_id = td::actor::actor_id(),
|
||||
private_key = std::move(request.private_key_), destination = std::move(request.destination_),
|
||||
amount = request.amount_, message = std::move(request.message_)](td::Result<RawAccountState> r_state) mutable {
|
||||
if (r_state.is_error()) {
|
||||
return promise.set_error(r_state.move_as_error());
|
||||
}
|
||||
auto rr_state = to_generic_accountState(r_state.move_as_ok());
|
||||
if (rr_state.is_error()) {
|
||||
return promise.set_error(rr_state.move_as_error());
|
||||
}
|
||||
auto state = rr_state.move_as_ok();
|
||||
|
||||
downcast_call(*state, td::overloaded(
|
||||
[&](tonlib_api::generic_accountStateTestGiver& test_giver_state) {
|
||||
send_lambda(actor_id,
|
||||
[promise = std::move(promise), self,
|
||||
query = tonlib_api::testGiver_sendGrams(
|
||||
std::move(destination), test_giver_state.account_state_->seqno_,
|
||||
amount, std::move(message))]() mutable {
|
||||
LOG(INFO) << "Send " << to_string(query);
|
||||
auto status = self->do_request(query, std::move(promise));
|
||||
if (status.is_error()) {
|
||||
CHECK(promise);
|
||||
promise.set_error(std::move(status));
|
||||
}
|
||||
});
|
||||
return;
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) {
|
||||
send_lambda(actor_id, [promise = std::move(promise), self,
|
||||
query = tonlib_api::testWallet_sendGrams(
|
||||
std::move(private_key), std::move(destination),
|
||||
test_wallet_state.account_state_->seqno_, amount,
|
||||
std::move(message))]() mutable {
|
||||
auto status = self->do_request(query, std::move(promise));
|
||||
if (status.is_error()) {
|
||||
CHECK(promise);
|
||||
promise.set_error(std::move(status));
|
||||
}
|
||||
});
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateUninited&) {
|
||||
promise.set_error(td::Status::Error(400, "Account is not inited"));
|
||||
},
|
||||
[&](tonlib_api::generic_accountStateRaw&) {
|
||||
promise.set_error(td::Status::Error(400, "Unknown account type"));
|
||||
}));
|
||||
})
|
||||
.release();
|
||||
auto id = actor_id_++;
|
||||
actors_[id] = td::actor::create_actor<GenericSendGrams>("GenericSendGrams", actor_shared(this, id),
|
||||
std::move(request), std::move(promise));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -1029,8 +1301,14 @@ td::Status TonlibClient::do_request(const tonlib_api::exportKey& request,
|
|||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::deleteKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(request.public_key_));
|
||||
TRY_STATUS(key_storage_.delete_key(key_bytes.key));
|
||||
if (!request.key_) {
|
||||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(request.key_->public_key_));
|
||||
KeyStorage::Key key;
|
||||
key.public_key = td::SecureString(key_bytes.key);
|
||||
key.secret = std::move(request.key_->secret_);
|
||||
TRY_STATUS(key_storage_.delete_key(key));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -1141,4 +1419,59 @@ td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryError& re
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(tonlib_api::setLogStream& request) {
|
||||
auto result = Logging::set_current_stream(std::move(request.log_stream_));
|
||||
if (result.is_ok()) {
|
||||
return tonlib_api::make_object<tonlib_api::ok>();
|
||||
} else {
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, result.message().str());
|
||||
}
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const tonlib_api::getLogStream& request) {
|
||||
auto result = Logging::get_current_stream();
|
||||
if (result.is_ok()) {
|
||||
return result.move_as_ok();
|
||||
} else {
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, result.error().message().str());
|
||||
}
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::setLogVerbosityLevel& request) {
|
||||
auto result = Logging::set_verbosity_level(static_cast<int>(request.new_verbosity_level_));
|
||||
if (result.is_ok()) {
|
||||
return tonlib_api::make_object<tonlib_api::ok>();
|
||||
} else {
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, result.message().str());
|
||||
}
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::setLogTagVerbosityLevel& request) {
|
||||
auto result = Logging::set_tag_verbosity_level(request.tag_, static_cast<int>(request.new_verbosity_level_));
|
||||
if (result.is_ok()) {
|
||||
return tonlib_api::make_object<tonlib_api::ok>();
|
||||
} else {
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, result.message().str());
|
||||
}
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::getLogVerbosityLevel& request) {
|
||||
return tonlib_api::make_object<tonlib_api::logVerbosityLevel>(Logging::get_verbosity_level());
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(
|
||||
const tonlib_api::getLogTagVerbosityLevel& request) {
|
||||
auto result = Logging::get_tag_verbosity_level(request.tag_);
|
||||
if (result.is_ok()) {
|
||||
return tonlib_api::make_object<tonlib_api::logVerbosityLevel>(result.ok());
|
||||
} else {
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, result.error().message().str());
|
||||
}
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const tonlib_api::getLogTags& request) {
|
||||
return tonlib_api::make_object<tonlib_api::logTags>(Logging::get_tags());
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const tonlib_api::addLogMessage& request) {
|
||||
Logging::add_message(request.verbosity_level_, request.text_);
|
||||
return tonlib_api::make_object<tonlib_api::ok>();
|
||||
}
|
||||
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace tonlib {
|
||||
class TonlibClient : public td::actor::Actor {
|
||||
public:
|
||||
|
@ -58,6 +60,9 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::actor::ActorOwn<LastBlock> raw_last_block_;
|
||||
ExtClient client_;
|
||||
|
||||
std::map<td::int64, td::actor::ActorOwn<>> actors_;
|
||||
td::int64 actor_id_{1};
|
||||
|
||||
ExtClientRef get_client_ref();
|
||||
void init_ext_client();
|
||||
void init_last_block();
|
||||
|
@ -65,12 +70,17 @@ class TonlibClient : public td::actor::Actor {
|
|||
bool is_closing_{false};
|
||||
td::uint32 ref_cnt_{1};
|
||||
void hangup_shared() override {
|
||||
ref_cnt_--;
|
||||
auto it = actors_.find(get_link_token());
|
||||
if (it != actors_.end()) {
|
||||
actors_.erase(it);
|
||||
} else {
|
||||
ref_cnt_--;
|
||||
}
|
||||
try_stop();
|
||||
}
|
||||
void hangup() override;
|
||||
void try_stop() {
|
||||
if (is_closing_ && ref_cnt_ == 0) {
|
||||
if (is_closing_ && ref_cnt_ == 0 && actors_.empty()) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +96,19 @@ class TonlibClient : public td::actor::Actor {
|
|||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::runTests& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::raw_getAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::testWallet_getAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::wallet_getAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::testGiver_getAccountAddress& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(tonlib_api::getBip39Hints& request);
|
||||
|
||||
static object_ptr<tonlib_api::Object> do_static_request(tonlib_api::setLogStream& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::getLogStream& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::setLogVerbosityLevel& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::setLogTagVerbosityLevel& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::getLogVerbosityLevel& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::getLogTagVerbosityLevel& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::getLogTags& request);
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::addLogMessage& request);
|
||||
|
||||
template <class T, class P>
|
||||
td::Status do_request(const T& request, P&& promise) {
|
||||
return td::Status::Error(400, "Function is unsupported");
|
||||
|
@ -112,6 +133,11 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Status do_request(tonlib_api::testWallet_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::testWallet_accountState>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::wallet_init& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(const tonlib_api::wallet_sendGrams& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(tonlib_api::wallet_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::wallet_accountState>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::testGiver_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::testGiver_accountState>>&& promise);
|
||||
td::Status do_request(const tonlib_api::testGiver_sendGrams& request,
|
||||
|
@ -145,5 +171,7 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
|
||||
void proxy_request(td::int64 query_id, std::string data);
|
||||
|
||||
friend class TonlibQueryActor;
|
||||
};
|
||||
} // namespace tonlib
|
||||
|
|
86
tonlib/tonlib/Wallet.cpp
Normal file
86
tonlib/tonlib/Wallet.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "tonlib/Wallet.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) {
|
||||
auto code = get_init_code();
|
||||
auto data = get_init_data(public_key);
|
||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) {
|
||||
td::uint32 seqno = 0;
|
||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max();
|
||||
auto signature =
|
||||
private_key
|
||||
.sign(vm::CellBuilder().store_long(seqno, 32).store_long(valid_until, 32).finalize()->get_hash().as_slice())
|
||||
.move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).store_long(seqno, 32).store_long(valid_until, 32).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) {
|
||||
CHECK(message.size() <= 124);
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
cb.append_cellslice(binary_bitstring_to_cellslice("b{010000100}").move_as_ok())
|
||||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4).store_bytes(message).finalize();
|
||||
auto message_outer = vm::CellBuilder()
|
||||
.store_long(seqno, 32)
|
||||
.store_long(valid_until, 32)
|
||||
.store_long(1, 8)
|
||||
.store_ref(message_inner)
|
||||
.finalize();
|
||||
std::string seq_no(4, 0);
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_code() {
|
||||
static auto res = [] {
|
||||
auto serialized_code = td::base64_decode(
|
||||
"te6ccgEEBgEAAAAAaAABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQCA8oMI1xgg0x/TH/gjErnyY+1E0NMf0//"
|
||||
"RUTG68qED+QFUEEL5EPKi+AACkyDXSpbTB9QC+wDo0aTIyx/L/8ntVAAE0DAAEaCZL9qJoa4WPw==")
|
||||
.move_as_ok();
|
||||
return vm::std_boc_deserialize(serialized_code).move_as_ok();
|
||||
}();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash Wallet::get_init_code_hash() {
|
||||
return get_init_code()->get_hash();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) {
|
||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||
}
|
||||
} // namespace tonlib
|
38
tonlib/tonlib/Wallet.h
Normal file
38
tonlib/tonlib/Wallet.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block.h"
|
||||
|
||||
namespace tonlib {
|
||||
class Wallet {
|
||||
public:
|
||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key);
|
||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key);
|
||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address);
|
||||
|
||||
static td::Ref<vm::Cell> get_init_code();
|
||||
static vm::CellHash get_init_code_hash();
|
||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key);
|
||||
};
|
||||
} // namespace tonlib
|
|
@ -27,6 +27,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
std::string config;
|
||||
std::string key_dir{"."};
|
||||
bool use_callbacks_for_network{false};
|
||||
bool use_simple_wallet{false};
|
||||
};
|
||||
TonlibCli(Options options) : options_(std::move(options)) {
|
||||
}
|
||||
|
@ -281,7 +282,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
info.public_key = key->public_key_;
|
||||
info.secret = std::move(key->secret_);
|
||||
keys_.push_back(std::move(info));
|
||||
export_key(info.public_key, keys_.size() - 1, std::move(password));
|
||||
//export_key(key->public_key_, keys_.size() - 1, std::move(password));
|
||||
store_keys();
|
||||
});
|
||||
}
|
||||
|
@ -388,8 +389,11 @@ class TonlibCli : public td::actor::Actor {
|
|||
auto r_key_i = to_key_i(key);
|
||||
using tonlib_api::make_object;
|
||||
if (r_key_i.is_ok()) {
|
||||
auto obj = tonlib::TonlibClient::static_request(make_object<tonlib_api::testWallet_getAccountAddress>(
|
||||
make_object<tonlib_api::testWallet_initialAccountState>(keys_[r_key_i.ok()].public_key)));
|
||||
auto obj = options_.use_simple_wallet
|
||||
? tonlib::TonlibClient::static_request(make_object<tonlib_api::testWallet_getAccountAddress>(
|
||||
make_object<tonlib_api::testWallet_initialAccountState>(keys_[r_key_i.ok()].public_key)))
|
||||
: tonlib::TonlibClient::static_request(make_object<tonlib_api::wallet_getAccountAddress>(
|
||||
make_object<tonlib_api::wallet_initialAccountState>(keys_[r_key_i.ok()].public_key)));
|
||||
if (obj->get_id() != tonlib_api::error::ID) {
|
||||
Address res;
|
||||
res.address = ton::move_tl_object_as<tonlib_api::accountAddress>(obj);
|
||||
|
@ -476,12 +480,19 @@ class TonlibCli : public td::actor::Actor {
|
|||
using tonlib_api::make_object;
|
||||
send_query(make_object<tonlib_api::importKey>(td::SecureString(password), td::SecureString(),
|
||||
make_object<tonlib_api::exportedKey>(std::move(words))),
|
||||
[](auto r_res) {
|
||||
[this, password = td::SecureString(password)](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't import key " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
auto key = r_res.move_as_ok();
|
||||
LOG(ERROR) << to_string(key);
|
||||
KeyInfo info;
|
||||
info.public_key = key->public_key_;
|
||||
info.secret = std::move(key->secret_);
|
||||
keys_.push_back(std::move(info));
|
||||
export_key(key->public_key_, keys_.size() - 1, std::move(password));
|
||||
store_keys();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -618,7 +629,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
std::move(to.address), grams, message.str()),
|
||||
[](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";
|
||||
td::TerminalIO::out() << "Can't transfer: " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
|
@ -648,16 +659,29 @@ class TonlibCli : public td::actor::Actor {
|
|||
|
||||
void init_simple_wallet(std::string key, size_t key_i, td::Slice password) {
|
||||
using tonlib_api::make_object;
|
||||
send_query(make_object<tonlib_api::testWallet_init>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(keys_[key_i].public_key, keys_[key_i].secret.copy()),
|
||||
td::SecureString(password))),
|
||||
[key = std::move(key)](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't init wallet with key: [" << key << "] " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
});
|
||||
if (options_.use_simple_wallet) {
|
||||
send_query(make_object<tonlib_api::testWallet_init>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(keys_[key_i].public_key, keys_[key_i].secret.copy()),
|
||||
td::SecureString(password))),
|
||||
[key = std::move(key)](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't init wallet with key: [" << key << "] " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
});
|
||||
} else {
|
||||
send_query(make_object<tonlib_api::wallet_init>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(keys_[key_i].public_key, keys_[key_i].secret.copy()),
|
||||
td::SecureString(password))),
|
||||
[key = std::move(key)](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't init wallet with key: [" << key << "] " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void get_hints(td::Slice prefix) {
|
||||
|
@ -705,10 +729,14 @@ int main(int argc, char* argv[]) {
|
|||
options.config = std::move(data);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('c', "use_callbacks_for_network (for debug)", "do not use this", [&]() {
|
||||
p.add_option('c', "use-callbacks-for-network", "do not use this", [&]() {
|
||||
options.use_callbacks_for_network = true;
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('S', "use-simple-wallet", "do not use this", [&]() {
|
||||
options.use_simple_wallet = true;
|
||||
return td::Status::OK();
|
||||
});
|
||||
|
||||
auto S = p.run(argc, argv);
|
||||
if (S.is_error()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue