mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
156
tonlib/CMakeLists.txt
Normal file
156
tonlib/CMakeLists.txt
Normal file
|
@ -0,0 +1,156 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
set(TONLIB_SOURCE
|
||||
tonlib/Client.cpp
|
||||
tonlib/Config.cpp
|
||||
tonlib/ExtClient.cpp
|
||||
tonlib/ExtClientLazy.cpp
|
||||
tonlib/GenericAccount.cpp
|
||||
tonlib/KeyStorage.cpp
|
||||
tonlib/LastBlock.cpp
|
||||
tonlib/TestGiver.cpp
|
||||
tonlib/TestWallet.cpp
|
||||
tonlib/TonlibClient.cpp
|
||||
tonlib/utils.cpp
|
||||
|
||||
tonlib/Client.h
|
||||
tonlib/Config.h
|
||||
tonlib/ExtClient.h
|
||||
tonlib/ExtClientLazy.h
|
||||
tonlib/GenericAccount.h
|
||||
tonlib/KeyStorage.h
|
||||
tonlib/LastBlock.h
|
||||
tonlib/TestGiver.h
|
||||
tonlib/TestWallet.h
|
||||
tonlib/TonlibCallback.h
|
||||
tonlib/TonlibClient.h
|
||||
tonlib/utils.h
|
||||
|
||||
tonlib/keys/bip39.cpp
|
||||
tonlib/keys/DecryptedKey.cpp
|
||||
tonlib/keys/EncryptedKey.cpp
|
||||
tonlib/keys/Mnemonic.cpp
|
||||
tonlib/keys/SimpleEncryption.cpp
|
||||
tonlib/keys/bip39.h
|
||||
tonlib/keys/DecryptedKey.h
|
||||
tonlib/keys/EncryptedKey.h
|
||||
tonlib/keys/Mnemonic.h
|
||||
tonlib/keys/SimpleEncryption.h
|
||||
)
|
||||
|
||||
set(TONLIB_OFFLINE_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test/offline.cpp PARENT_SCOPE)
|
||||
set(TONLIB_ONLINE_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test/online.cpp PARENT_SCOPE)
|
||||
|
||||
add_library(tonlib STATIC ${TONLIB_SOURCE})
|
||||
|
||||
target_include_directories(tonlib PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
target_link_libraries(tonlib PRIVATE tdactor adnllite tl_lite_api tl-lite-utils ton_crypto ton_block)
|
||||
target_link_libraries(tonlib PUBLIC tdutils tl_tonlib_api)
|
||||
|
||||
if (TONLIB_ENABLE_JNI AND NOT ANDROID) # jni is available by default on Android
|
||||
if (NOT JNI_FOUND)
|
||||
find_package(JNI REQUIRED)
|
||||
endif()
|
||||
message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}")
|
||||
target_include_directories(tonlib PUBLIC ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
|
||||
target_link_libraries(tonlib PUBLIC ${JAVA_JVM_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
if (TD_ENABLE_JNI)
|
||||
#FIXME
|
||||
#add_dependencies(tonlib tonlib_generate_java_api)
|
||||
endif()
|
||||
endif()
|
||||
add_library(tonlibjson_private STATIC tonlib/ClientJson.cpp tonlib/ClientJson.h)
|
||||
target_include_directories(tonlibjson_private PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${TL_TD_AUTO_INCLUDES}>)
|
||||
target_link_libraries(tonlibjson_private PUBLIC tonlib PRIVATE tl_tonlib_api_json)
|
||||
|
||||
set(TONLIB_JSON_HEADERS tonlib/tonlib_client_json.h)
|
||||
set(TONLIB_JSON_SOURCE tonlib/tonlib_client_json.cpp)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
add_library(tonlibjson SHARED ${TONLIB_JSON_SOURCE} ${TONLIB_JSON_HEADERS})
|
||||
target_link_libraries(tonlibjson PRIVATE tonlibjson_private)
|
||||
generate_export_header(tonlibjson EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/tonlib/tonlibjson_export.h)
|
||||
target_include_directories(tonlibjson PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
if (APPLE)
|
||||
set_target_properties(tonlibjson PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/tonlibclientjson_export_list")
|
||||
endif()
|
||||
|
||||
add_library(tonlibjson_static STATIC ${TONLIB_JSON_SOURCE} ${TONLIB_JSON_HEADERS})
|
||||
target_link_libraries(tonlibjson_static PRIVATE tonlibjson_private)
|
||||
target_compile_definitions(tonlibjson_static PUBLIC TONLIBJSON_STATIC_DEFINE)
|
||||
target_include_directories(tonlibjson_static PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
|
||||
add_library(TonlibJson INTERFACE)
|
||||
target_link_libraries(TonlibJson INTERFACE tonlibjson)
|
||||
|
||||
add_library(Tonlib::TonlibJson ALIAS TonlibJson)
|
||||
|
||||
add_library(Tonlib INTERFACE)
|
||||
target_link_libraries(Tonlib INTERFACE tonlib)
|
||||
|
||||
add_library(Tonlib::Tonlib ALIAS Tonlib)
|
||||
|
||||
install(TARGETS tonlibjson TonlibJson EXPORT Tonlib
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
INCLUDES DESTINATION include
|
||||
)
|
||||
|
||||
if (NOT TON_USE_ABSEIL)
|
||||
install(TARGETS tdnet keys crc32c tdactor adnllite tl_api tl-utils tl_lite_api tl-lite-utils ton_crypto ton_block tdutils tl_tonlib_api tonlib Tonlib EXPORT Tonlib
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
INCLUDES DESTINATION include
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/tonlib/Client.h DESTINATION include/tonlib/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tl/generate/auto/tl/tonlib_api.h DESTINATION include/auto/tl/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tl/tl/TlObject.h DESTINATION include/tl/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/int_types.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/Slice-decl.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/Slice.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/common.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/unique_ptr.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/check.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/SharedSlice.h DESTINATION include/td/utils/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../tdutils/td/utils/port/platform.h DESTINATION include/td/utils/port)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/../tdutils/td/utils/config.h DESTINATION include/td/utils/)
|
||||
endif()
|
||||
|
||||
install(FILES ${TONLIB_JSON_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/tonlib/tonlibjson_export.h DESTINATION include/tonlib/)
|
||||
|
||||
install(EXPORT Tonlib
|
||||
FILE TonlibTargets.cmake
|
||||
NAMESPACE Tonlib::
|
||||
DESTINATION lib/cmake/Tonlib
|
||||
)
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file("TonlibConfigVersion.cmake"
|
||||
VERSION ${TON_VERSION}
|
||||
COMPATIBILITY ExactVersion
|
||||
)
|
||||
install(FILES "TonlibConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/TonlibConfigVersion.cmake"
|
||||
DESTINATION lib/cmake/Tonlib
|
||||
)
|
||||
|
||||
# Add SOVERSION to shared libraries
|
||||
set_property(TARGET tonlibjson PROPERTY SOVERSION ${TON_VERSION})
|
414
tonlib/test/offline.cpp
Normal file
414
tonlib/test/offline.cpp
Normal file
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
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 "fift/Fift.h"
|
||||
#include "fift/words.h"
|
||||
#include "fift/utils.h"
|
||||
|
||||
#include "block/block.h"
|
||||
#include "block/block-auto.h"
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
|
||||
#include "tonlib/utils.h"
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/TestWallet.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/TonlibClient.h"
|
||||
#include "tonlib/Client.h"
|
||||
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "auto/tl/tonlib_api_json.h"
|
||||
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/PathView.h"
|
||||
#include "td/utils/tests.h"
|
||||
|
||||
// KeyManager
|
||||
#include "tonlib/keys/bip39.h"
|
||||
#include "tonlib/keys/DecryptedKey.h"
|
||||
#include "tonlib/keys/EncryptedKey.h"
|
||||
#include "tonlib/keys/Mnemonic.h"
|
||||
#include "tonlib/keys/SimpleEncryption.h"
|
||||
|
||||
using namespace tonlib;
|
||||
|
||||
std::string current_dir() {
|
||||
return td::PathView(td::realpath(__FILE__).move_as_ok()).parent_dir().str();
|
||||
}
|
||||
|
||||
std::string load_source(std::string name) {
|
||||
return td::read_file_str(current_dir() + "../../crypto/" + name).move_as_ok();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> get_test_wallet_source() {
|
||||
std::string code = R"ABCD(
|
||||
SETCP0 DUP IFNOTRET INC 32 THROWIF // return if recv_internal, fail unless recv_external
|
||||
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt
|
||||
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk
|
||||
s1 s2 XCPU // sign cs cnt pubk cnt' cnt
|
||||
EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
s2 PUSH HASHSU // sign cs cnt pubk hash
|
||||
s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk
|
||||
CHKSIGNU // pubk cs cnt ?
|
||||
34 THROWIFNOT // signature mismatch
|
||||
ACCEPT
|
||||
SWAP 32 LDU NIP
|
||||
DUP SREFS IF:<{
|
||||
8 LDU LDREF // pubk cnt mode msg cs
|
||||
s0 s2 XCHG SENDRAWMSG // pubk cnt cs ; ( message sent )
|
||||
}>
|
||||
ENDS
|
||||
INC NEWC 32 STU 256 STU ENDC c4 POPCTR
|
||||
)ABCD";
|
||||
return fift::compile_asm(code).move_as_ok();
|
||||
}
|
||||
|
||||
TEST(Tonlib, TestWallet) {
|
||||
CHECK(get_test_wallet_source()->get_hash() == TestWallet::get_init_code()->get_hash());
|
||||
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();
|
||||
LOG(ERROR) << address.bounceable;
|
||||
auto fift_output = fift::mem_run_fift(load_source("smartcont/testgiver.fif"),
|
||||
{"aba", address.rserialize(), "0", "6.666", "wallet-query"})
|
||||
.move_as_ok();
|
||||
LOG(ERROR) << fift_output.output;
|
||||
|
||||
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
|
||||
|
||||
auto res = GenericAccount::create_ext_message(TestGiver::address(), {},
|
||||
TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, address));
|
||||
vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr);
|
||||
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
||||
}
|
||||
|
||||
TEST(Tonlib, Address) {
|
||||
auto a = block::StdAddress::parse("-1:538fa7cc24ff8eaa101d84a5f1ab7e832fe1d84b309cdfef4ee94373aac80f7d").move_as_ok();
|
||||
auto b = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
|
||||
auto c = block::StdAddress::parse("Ef9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX").move_as_ok();
|
||||
CHECK(a == b);
|
||||
CHECK(a == c);
|
||||
CHECK(block::StdAddress::parse("Ef9Tj6fMJp-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX").is_error());
|
||||
CHECK(block::StdAddress::parse("Ef9Tj6fMJp+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").is_error());
|
||||
CHECK(block::StdAddress::parse(a.rserialize()).move_as_ok() == a);
|
||||
}
|
||||
|
||||
static auto sync_send = [](auto &client, auto query) {
|
||||
using ReturnTypePtr = typename std::decay_t<decltype(*query)>::ReturnType;
|
||||
using ReturnType = typename ReturnTypePtr::element_type;
|
||||
client.send({1, std::move(query)});
|
||||
while (true) {
|
||||
auto response = client.receive(100);
|
||||
if (response.object) {
|
||||
CHECK(response.id == 1);
|
||||
if (response.object->get_id() == tonlib_api::error::ID) {
|
||||
auto error = tonlib_api::move_object_as<tonlib_api::error>(response.object);
|
||||
return td::Result<ReturnTypePtr>(td::Status::Error(error->code_, error->message_));
|
||||
}
|
||||
return td::Result<ReturnTypePtr>(tonlib_api::move_object_as<ReturnType>(response.object));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Tonlib, InitClose) {
|
||||
using tonlib_api::make_object;
|
||||
{
|
||||
Client client;
|
||||
sync_send(client, make_object<tonlib_api::close>()).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "."))).ensure_error();
|
||||
}
|
||||
{
|
||||
Client client;
|
||||
sync_send(client, make_object<tonlib_api::init>(nullptr)).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("fdajkfldsjkafld", ".")))
|
||||
.ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "fdhskfds"))).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "."))).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "."))).ensure_error();
|
||||
|
||||
td::Slice bad_config = R"abc(
|
||||
{
|
||||
"@type": "config.global",
|
||||
"liteclients": [ ]
|
||||
}
|
||||
)abc";
|
||||
|
||||
sync_send(client, make_object<tonlib_api::options_setConfig>(bad_config.str())).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::testGiver_getAccountState>()).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::close>()).ensure();
|
||||
sync_send(client, make_object<tonlib_api::close>()).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "."))).ensure_error();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Tonlib, SimpleEncryption) {
|
||||
std::string secret = "secret";
|
||||
{
|
||||
std::string data = "some private data";
|
||||
std::string wrong_secret = "wrong secret";
|
||||
auto encrypted_data = SimpleEncryption::encrypt_data(data, secret);
|
||||
LOG(ERROR) << encrypted_data.size();
|
||||
auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, secret).move_as_ok();
|
||||
CHECK(data == decrypted_data);
|
||||
SimpleEncryption::decrypt_data(encrypted_data, wrong_secret).ensure_error();
|
||||
SimpleEncryption::decrypt_data("", secret).ensure_error();
|
||||
SimpleEncryption::decrypt_data(std::string(32, 'a'), secret).ensure_error();
|
||||
SimpleEncryption::decrypt_data(std::string(33, 'a'), secret).ensure_error();
|
||||
SimpleEncryption::decrypt_data(std::string(64, 'a'), secret).ensure_error();
|
||||
SimpleEncryption::decrypt_data(std::string(128, 'a'), secret).ensure_error();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 255; i++) {
|
||||
auto data = td::rand_string('a', 'z', static_cast<int>(i));
|
||||
auto encrypted_data = SimpleEncryption::encrypt_data(data, secret);
|
||||
auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, secret).move_as_ok();
|
||||
CHECK(data == decrypted_data);
|
||||
}
|
||||
}
|
||||
|
||||
class MnemonicBench : public td::Benchmark {
|
||||
public:
|
||||
std::string get_description() const override {
|
||||
return "mnemonic is_password_seed";
|
||||
}
|
||||
void start_up() override {
|
||||
Mnemonic::Options options;
|
||||
options.password = td::SecureString("qwerty");
|
||||
mnemonic_ = Mnemonic::create_new(std::move(options)).move_as_ok();
|
||||
}
|
||||
void run(int n) override {
|
||||
int x = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
x += mnemonic_.value().is_password_seed();
|
||||
}
|
||||
td::do_not_optimize_away(x);
|
||||
}
|
||||
|
||||
td::optional<Mnemonic> mnemonic_;
|
||||
};
|
||||
|
||||
TEST(Tonlib, Mnemonic) {
|
||||
td::bench(MnemonicBench());
|
||||
//for (int i = 0; i < 20; i++) {
|
||||
//td::PerfWarningTimer perf("Mnemonic::create", 0.01);
|
||||
//Mnemonic::Options options;
|
||||
//options.password = td::SecureString("qwerty");
|
||||
//Mnemonic::create_new(std::move(options)).move_as_ok();
|
||||
//}
|
||||
// FIXME
|
||||
//auto tmp = std::vector<td::SecureString>{"hello", "world"};
|
||||
//CHECK(tmp[0].as_slice() == "hello");
|
||||
auto a = Mnemonic::create(td::SecureString(" Hello, . $^\n# World! "), td::SecureString("cucumber")).move_as_ok();
|
||||
auto get_word_list = [] {
|
||||
std::vector<td::SecureString> words;
|
||||
words.emplace_back("hello");
|
||||
words.emplace_back("world");
|
||||
return words;
|
||||
};
|
||||
auto b = Mnemonic::create(get_word_list(), td::SecureString("cucumber")).move_as_ok();
|
||||
CHECK(a.get_words() == b.get_words());
|
||||
CHECK(a.get_words() == get_word_list());
|
||||
|
||||
Mnemonic::Options options;
|
||||
options.password = td::SecureString("qwerty");
|
||||
auto password = options.password.copy();
|
||||
auto c = Mnemonic::create_new(std::move(options)).move_as_ok();
|
||||
auto d = Mnemonic::create(c.get_words(), std::move(password)).move_as_ok();
|
||||
CHECK(c.to_private_key().as_octet_string() == d.to_private_key().as_octet_string());
|
||||
}
|
||||
|
||||
TEST(Tonlib, Keys) {
|
||||
auto a = Mnemonic::create(td::SecureString(" Hello, . $^\n# World! "), td::SecureString("cucumber")).move_as_ok();
|
||||
DecryptedKey decrypted_key(std::move(a));
|
||||
EncryptedKey encrypted_key = decrypted_key.encrypt("qwerty");
|
||||
auto other_decrypted_key = encrypted_key.decrypt("qwerty").move_as_ok();
|
||||
encrypted_key.decrypt("abcde").ensure_error();
|
||||
CHECK(decrypted_key.mnemonic_words == other_decrypted_key.mnemonic_words);
|
||||
CHECK(decrypted_key.private_key.as_octet_string() == other_decrypted_key.private_key.as_octet_string());
|
||||
}
|
||||
|
||||
TEST(Tonlib, KeysApi) {
|
||||
using tonlib_api::make_object;
|
||||
Client client;
|
||||
|
||||
// init
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "."))).ensure();
|
||||
auto local_password = td::SecureString("local password");
|
||||
auto mnemonic_password = td::SecureString("mnemonic password");
|
||||
{
|
||||
auto key = sync_send(client, make_object<tonlib_api::createNewKey>(local_password.copy(), td::SecureString{}))
|
||||
.move_as_ok();
|
||||
}
|
||||
|
||||
//createNewKey local_password:bytes mnemonic_password:bytes = Key;
|
||||
auto key = sync_send(client, make_object<tonlib_api::createNewKey>(local_password.copy(), mnemonic_password.copy()))
|
||||
.move_as_ok();
|
||||
|
||||
sync_send(client, make_object<tonlib_api::exportKey>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, key->secret_.copy()),
|
||||
td::SecureString("wrong password"))))
|
||||
.ensure_error();
|
||||
|
||||
//exportKey input_key:inputKey = ExportedKey;
|
||||
auto exported_key =
|
||||
sync_send(client,
|
||||
make_object<tonlib_api::exportKey>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, key->secret_.copy()), local_password.copy())))
|
||||
.move_as_ok();
|
||||
LOG(ERROR) << to_string(exported_key);
|
||||
auto copy_word_list = [&] {
|
||||
std::vector<td::SecureString> word_list_copy;
|
||||
for (auto &w : exported_key->word_list_) {
|
||||
word_list_copy.push_back(w.copy());
|
||||
}
|
||||
return word_list_copy;
|
||||
};
|
||||
|
||||
//changeLocalPassword input_key:inputKey new_local_password:bytes = Key;
|
||||
auto new_key =
|
||||
sync_send(client,
|
||||
make_object<tonlib_api::changeLocalPassword>(
|
||||
make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, key->secret_.copy()), local_password.copy()),
|
||||
td::SecureString("tmp local password")))
|
||||
.move_as_ok();
|
||||
sync_send(client,
|
||||
make_object<tonlib_api::exportKey>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, new_key->secret_.copy()), local_password.copy())))
|
||||
.ensure_error();
|
||||
|
||||
auto exported_key2 = sync_send(client, make_object<tonlib_api::exportKey>(make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, new_key->secret_.copy()),
|
||||
td::SecureString("tmp local password"))))
|
||||
.move_as_ok();
|
||||
CHECK(exported_key2->word_list_ == exported_key->word_list_);
|
||||
|
||||
//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();
|
||||
|
||||
{
|
||||
auto export_password = td::SecureString("export password");
|
||||
auto wrong_export_password = td::SecureString("wrong_export password");
|
||||
auto exported_encrypted_key =
|
||||
sync_send(client, make_object<tonlib_api::exportEncryptedKey>(
|
||||
make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, new_key->secret_.copy()),
|
||||
td::SecureString("tmp local password")),
|
||||
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::importEncryptedKey>(
|
||||
new_local_password.copy(), wrong_export_password.copy(),
|
||||
make_object<tonlib_api::exportedEncryptedKey>(exported_encrypted_key->data_.copy())))
|
||||
.ensure_error();
|
||||
|
||||
auto imported_encrypted_key =
|
||||
sync_send(client, make_object<tonlib_api::importEncryptedKey>(
|
||||
new_local_password.copy(), export_password.copy(),
|
||||
make_object<tonlib_api::exportedEncryptedKey>(exported_encrypted_key->data_.copy())))
|
||||
.move_as_ok();
|
||||
CHECK(imported_encrypted_key->public_key_ == key->public_key_);
|
||||
}
|
||||
|
||||
//deleteKey public_key:bytes = Ok;
|
||||
sync_send(client, make_object<tonlib_api::deleteKey>(key->public_key_)).move_as_ok();
|
||||
|
||||
auto err1 = sync_send(client, make_object<tonlib_api::importKey>(
|
||||
new_local_password.copy(), td::SecureString("wrong password"),
|
||||
make_object<tonlib_api::exportedKey>(copy_word_list())))
|
||||
.move_as_error();
|
||||
auto err2 =
|
||||
sync_send(client, make_object<tonlib_api::importKey>(new_local_password.copy(), td::SecureString(),
|
||||
make_object<tonlib_api::exportedKey>(copy_word_list())))
|
||||
.move_as_error();
|
||||
LOG(INFO) << err1 << " | " << err2;
|
||||
auto imported_key =
|
||||
sync_send(client, make_object<tonlib_api::importKey>(new_local_password.copy(), mnemonic_password.copy(),
|
||||
make_object<tonlib_api::exportedKey>(copy_word_list())))
|
||||
.move_as_ok();
|
||||
CHECK(imported_key->public_key_ == key->public_key_);
|
||||
CHECK(imported_key->secret_ != key->secret_);
|
||||
|
||||
//exportPemKey input_key:inputKey key_password:bytes = ExportedPemKey;
|
||||
auto pem_password = td::SecureString("pem password");
|
||||
auto r_exported_pem_key = sync_send(
|
||||
client,
|
||||
make_object<tonlib_api::exportPemKey>(
|
||||
make_object<tonlib_api::inputKey>(
|
||||
make_object<tonlib_api::key>(key->public_key_, imported_key->secret_.copy()), new_local_password.copy()),
|
||||
pem_password.copy()));
|
||||
if (r_exported_pem_key.is_error() && r_exported_pem_key.error().message() == "Not supported") {
|
||||
return;
|
||||
}
|
||||
auto exported_pem_key = r_exported_pem_key.move_as_ok();
|
||||
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(), td::SecureString("wrong pem password"),
|
||||
make_object<tonlib_api::exportedPemKey>(exported_pem_key->pem_.copy())))
|
||||
.ensure_error();
|
||||
|
||||
auto new_imported_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())))
|
||||
.move_as_ok();
|
||||
CHECK(new_imported_key->public_key_ == key->public_key_);
|
||||
CHECK(new_imported_key->secret_ != key->secret_);
|
||||
}
|
336
tonlib/test/online.cpp
Normal file
336
tonlib/test/online.cpp
Normal file
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl/adnl-ext-client.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "auto/tl/tonlib_api_json.h"
|
||||
#include "tl/tl_json.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "block/block.h"
|
||||
#include "block/block-auto.h"
|
||||
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/TestWallet.h"
|
||||
#include "tonlib/LastBlock.h"
|
||||
#include "tonlib/ExtClient.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "tonlib/TonlibCallback.h"
|
||||
#include "tonlib/Client.h"
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
|
||||
#include "td/utils/Container.h"
|
||||
#include "td/utils/OptionsParser.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/tests.h"
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "td/utils/MpscPollableQueue.h"
|
||||
|
||||
#include "td/utils/port/signals.h"
|
||||
|
||||
using namespace tonlib;
|
||||
|
||||
auto sync_send = [](auto& client, auto query) {
|
||||
using ReturnTypePtr = typename std::decay_t<decltype(*query)>::ReturnType;
|
||||
using ReturnType = typename ReturnTypePtr::element_type;
|
||||
client.send({1, std::move(query)});
|
||||
while (true) {
|
||||
auto response = client.receive(100);
|
||||
if (response.object) {
|
||||
CHECK(response.id == 1);
|
||||
if (response.object->get_id() == tonlib_api::error::ID) {
|
||||
auto error = tonlib_api::move_object_as<tonlib_api::error>(response.object);
|
||||
return td::Result<ReturnTypePtr>(td::Status::Error(error->code_, error->message_));
|
||||
}
|
||||
return td::Result<ReturnTypePtr>(tonlib_api::move_object_as<ReturnType>(response.object));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Key {
|
||||
std::string public_key;
|
||||
td::SecureString secret;
|
||||
tonlib_api::object_ptr<tonlib_api::inputKey> get_input_key() const {
|
||||
return tonlib_api::make_object<tonlib_api::inputKey>(
|
||||
tonlib_api::make_object<tonlib_api::key>(public_key, secret.copy()), td::SecureString("local"));
|
||||
}
|
||||
};
|
||||
struct Wallet {
|
||||
std::string address;
|
||||
Key key;
|
||||
};
|
||||
|
||||
std::string test_giver_address(Client& client) {
|
||||
using tonlib_api::make_object;
|
||||
return sync_send(client, make_object<tonlib_api::testGiver_getAccountAddress>()).move_as_ok()->account_address_;
|
||||
}
|
||||
|
||||
td::int64 get_balance(Client& client, std::string address) {
|
||||
auto generic_state = sync_send(client, tonlib_api::make_object<tonlib_api::generic_getAccountState>(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(address)))
|
||||
.move_as_ok();
|
||||
td::int64 res = 0;
|
||||
tonlib_api::downcast_call(*generic_state, [&](auto& state) { res = state.account_state_->balance_; });
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_inited(Client& client, std::string address) {
|
||||
auto generic_state = sync_send(client, tonlib_api::make_object<tonlib_api::generic_getAccountState>(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(address)))
|
||||
.move_as_ok();
|
||||
return generic_state->get_id() != tonlib_api::generic_accountStateUninited::ID;
|
||||
}
|
||||
|
||||
void transfer_grams(Client& client, std::string from, std::string to, td::int64 amount,
|
||||
tonlib_api::object_ptr<tonlib_api::inputKey> input_key) {
|
||||
auto balance = get_balance(client, to);
|
||||
sync_send(client, tonlib_api::make_object<tonlib_api::generic_sendGrams>(
|
||||
std::move(input_key), tonlib_api::make_object<tonlib_api::accountAddress>(from),
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(to), amount))
|
||||
.ensure();
|
||||
while (balance == get_balance(client, to)) {
|
||||
client.receive(1);
|
||||
}
|
||||
}
|
||||
Wallet create_empty_wallet(Client& client) {
|
||||
using tonlib_api::make_object;
|
||||
auto key =
|
||||
sync_send(client, make_object<tonlib_api::createNewKey>(td::SecureString("local"), td::SecureString("mnemonic")))
|
||||
.move_as_ok();
|
||||
Wallet wallet{"", {key->public_key_, std::move(key->secret_)}};
|
||||
|
||||
auto account_address =
|
||||
sync_send(client, make_object<tonlib_api::testWallet_getAccountAddress>(
|
||||
make_object<tonlib_api::testWallet_initialAccountState>(wallet.key.public_key)))
|
||||
.move_as_ok();
|
||||
|
||||
wallet.address = account_address->account_address_;
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Wallet create_wallet(Client& client) {
|
||||
using tonlib_api::make_object;
|
||||
auto wallet = create_empty_wallet(client);
|
||||
|
||||
transfer_grams(client, test_giver_address(client), wallet.address, 6000000000, {});
|
||||
sync_send(client, make_object<tonlib_api::testWallet_init>(wallet.key.get_input_key())).ensure();
|
||||
while (!is_inited(client, wallet.address)) {
|
||||
client.receive(1);
|
||||
}
|
||||
LOG(ERROR) << get_balance(client, wallet.address);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
std::string get_test_giver_address(Client& client) {
|
||||
return sync_send(client, tonlib_api::make_object<tonlib_api::testGiver_getAccountAddress>())
|
||||
.move_as_ok()
|
||||
->account_address_;
|
||||
}
|
||||
|
||||
void dump_transaction_history(Client& client, std::string address) {
|
||||
using tonlib_api::make_object;
|
||||
auto state = sync_send(client, make_object<tonlib_api::testGiver_getAccountState>()).move_as_ok();
|
||||
auto tid = std::move(state->last_transaction_id_);
|
||||
int cnt = 0;
|
||||
while (tid->lt_ != 0) {
|
||||
auto lt = tid->lt_;
|
||||
auto got_transactions = sync_send(client, make_object<tonlib_api::raw_getTransactions>(
|
||||
make_object<tonlib_api::accountAddress>(address), std::move(tid)))
|
||||
.move_as_ok();
|
||||
CHECK(got_transactions->transactions_.size() > 0);
|
||||
CHECK(got_transactions->transactions_[0]->previous_transaction_id_->lt_ < lt);
|
||||
for (auto& txn : got_transactions->transactions_) {
|
||||
LOG(ERROR) << to_string(txn);
|
||||
cnt++;
|
||||
}
|
||||
tid = std::move(got_transactions->transactions_.back()->previous_transaction_id_);
|
||||
}
|
||||
LOG(ERROR) << cnt;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
td::set_default_failure_signal_handler();
|
||||
using tonlib_api::make_object;
|
||||
|
||||
td::OptionsParser p;
|
||||
std::string global_config_str;
|
||||
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
|
||||
TRY_RESULT(str, td::read_file_str(fname.str()));
|
||||
global_config_str = std::move(str);
|
||||
LOG(ERROR) << global_config_str;
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.run(argc, argv).ensure();
|
||||
|
||||
Client client;
|
||||
{
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(global_config_str, "."))).ensure();
|
||||
}
|
||||
dump_transaction_history(client, get_test_giver_address(client));
|
||||
auto wallet_a = create_wallet(client);
|
||||
auto wallet_b = create_empty_wallet(client);
|
||||
transfer_grams(client, wallet_a.address, wallet_b.address, 3000000000, wallet_a.key.get_input_key());
|
||||
auto a = get_balance(client, wallet_a.address);
|
||||
auto b = get_balance(client, wallet_b.address);
|
||||
LOG(ERROR) << a << " " << b;
|
||||
return 0;
|
||||
{
|
||||
// init
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(global_config_str, "."))).ensure();
|
||||
|
||||
auto key = sync_send(client,
|
||||
make_object<tonlib_api::createNewKey>(td::SecureString("local"), td::SecureString("mnemonic")))
|
||||
.move_as_ok();
|
||||
|
||||
auto create_input_key = [&] {
|
||||
return make_object<tonlib_api::inputKey>(make_object<tonlib_api::key>(key->public_key_, key->secret_.copy()),
|
||||
td::SecureString("local"));
|
||||
};
|
||||
|
||||
auto public_key_raw = key->public_key_;
|
||||
td::Ed25519::PublicKey public_key_std(td::SecureString{public_key_raw});
|
||||
|
||||
sync_send(client, make_object<tonlib_api::options_setConfig>(global_config_str)).ensure();
|
||||
|
||||
auto wallet_addr = GenericAccount::get_address(0, TestWallet::get_init_state(public_key_std));
|
||||
{
|
||||
auto account_address =
|
||||
sync_send(client, make_object<tonlib_api::testWallet_getAccountAddress>(
|
||||
make_object<tonlib_api::testWallet_initialAccountState>(public_key_raw)))
|
||||
.move_as_ok();
|
||||
ASSERT_EQ(wallet_addr.rserialize(), account_address->account_address_);
|
||||
}
|
||||
|
||||
std::string test_giver_address;
|
||||
{
|
||||
auto account_address = sync_send(client, make_object<tonlib_api::testGiver_getAccountAddress>()).move_as_ok();
|
||||
test_giver_address = account_address->account_address_;
|
||||
ASSERT_EQ(TestGiver::address().rserialize(), test_giver_address);
|
||||
}
|
||||
|
||||
{
|
||||
auto account_address =
|
||||
sync_send(
|
||||
client,
|
||||
make_object<tonlib_api::raw_getAccountAddress>(make_object<tonlib_api::raw_initialAccountState>(
|
||||
vm::std_boc_serialize(TestWallet::get_init_code()).move_as_ok().as_slice().str(),
|
||||
vm::std_boc_serialize(TestWallet::get_init_data(public_key_std)).move_as_ok().as_slice().str())))
|
||||
.move_as_ok();
|
||||
ASSERT_EQ(wallet_addr.rserialize(), account_address->account_address_);
|
||||
}
|
||||
|
||||
{
|
||||
auto state = sync_send(client, make_object<tonlib_api::raw_getAccountState>(
|
||||
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize())))
|
||||
.move_as_ok();
|
||||
LOG(ERROR) << to_string(state);
|
||||
}
|
||||
|
||||
td::int32 seqno = 0;
|
||||
{
|
||||
auto state = sync_send(client, make_object<tonlib_api::testGiver_getAccountState>()).move_as_ok();
|
||||
LOG(ERROR) << to_string(state);
|
||||
seqno = state->seqno_;
|
||||
}
|
||||
|
||||
{
|
||||
sync_send(client, make_object<tonlib_api::testGiver_sendGrams>(
|
||||
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()), seqno,
|
||||
1000000000ll * 6666 / 1000))
|
||||
.ensure();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto state = sync_send(client, make_object<tonlib_api::testGiver_getAccountState>()).move_as_ok();
|
||||
if (state->seqno_ > seqno) {
|
||||
break;
|
||||
}
|
||||
client.receive(1);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto state = sync_send(client, make_object<tonlib_api::raw_getAccountState>(
|
||||
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize())))
|
||||
.move_as_ok();
|
||||
td::int64 grams_count = state->balance_;
|
||||
if (grams_count > 0) {
|
||||
LOG(ERROR) << "GOT " << grams_count;
|
||||
break;
|
||||
}
|
||||
client.receive(1);
|
||||
}
|
||||
|
||||
{ sync_send(client, make_object<tonlib_api::testWallet_init>(create_input_key())).ensure(); }
|
||||
|
||||
while (true) {
|
||||
auto r_state = sync_send(client, make_object<tonlib_api::testWallet_getAccountState>(
|
||||
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize())));
|
||||
if (r_state.is_ok()) {
|
||||
LOG(ERROR) << to_string(r_state.ok());
|
||||
break;
|
||||
}
|
||||
client.receive(1);
|
||||
}
|
||||
|
||||
{
|
||||
sync_send(client, make_object<tonlib_api::generic_sendGrams>(
|
||||
create_input_key(), make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()),
|
||||
make_object<tonlib_api::accountAddress>(test_giver_address), 1000000000ll * 3333 / 1000))
|
||||
.ensure();
|
||||
}
|
||||
while (true) {
|
||||
auto generic_state = sync_send(client, make_object<tonlib_api::generic_getAccountState>(
|
||||
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize())))
|
||||
.move_as_ok();
|
||||
if (generic_state->get_id() == tonlib_api::generic_accountStateTestWallet::ID) {
|
||||
auto state = tonlib_api::move_object_as<tonlib_api::generic_accountStateTestWallet>(generic_state);
|
||||
if (state->account_state_->balance_ < 5617007000) {
|
||||
LOG(ERROR) << to_string(state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
client.receive(1);
|
||||
}
|
||||
{
|
||||
auto generic_state = sync_send(client, make_object<tonlib_api::generic_getAccountState>(
|
||||
make_object<tonlib_api::accountAddress>(test_giver_address)))
|
||||
.move_as_ok();
|
||||
CHECK(generic_state->get_id() == tonlib_api::generic_accountStateTestGiver::ID);
|
||||
LOG(ERROR) << to_string(generic_state);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
158
tonlib/tonlib/Client.cpp
Normal file
158
tonlib/tonlib/Client.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
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 "Client.h"
|
||||
|
||||
#include "tonlib/TonlibClient.h"
|
||||
#include "tonlib/TonlibCallback.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/MpscPollableQueue.h"
|
||||
|
||||
int VERBOSITY_NAME(tonlib_requests) = VERBOSITY_NAME(DEBUG);
|
||||
|
||||
namespace tonlib {
|
||||
class Client::Impl final {
|
||||
public:
|
||||
using OutputQueue = td::MpscPollableQueue<Client::Response>;
|
||||
Impl() {
|
||||
output_queue_ = std::make_shared<OutputQueue>();
|
||||
output_queue_->init();
|
||||
|
||||
class Callback : public TonlibCallback {
|
||||
public:
|
||||
explicit Callback(std::shared_ptr<OutputQueue> output_queue) : output_queue_(std::move(output_queue)) {
|
||||
}
|
||||
void on_result(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::Object> result) override {
|
||||
output_queue_->writer_put({id, std::move(result)});
|
||||
}
|
||||
void on_error(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::error> error) override {
|
||||
output_queue_->writer_put({id, std::move(error)});
|
||||
}
|
||||
Callback(const Callback&) = delete;
|
||||
Callback& operator=(const Callback&) = delete;
|
||||
Callback(Callback&&) = delete;
|
||||
Callback& operator=(Callback&&) = delete;
|
||||
~Callback() override {
|
||||
output_queue_->writer_put({0, nullptr});
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<OutputQueue> output_queue_;
|
||||
};
|
||||
|
||||
scheduler_.run_in_context(
|
||||
[&] { tonlib_ = td::actor::create_actor<TonlibClient>("Tonlib", td::make_unique<Callback>(output_queue_)); });
|
||||
|
||||
scheduler_thread_ = td::thread([&] { scheduler_.run(); });
|
||||
}
|
||||
|
||||
void send(Client::Request request) {
|
||||
if (request.id == 0 || request.function == nullptr) {
|
||||
LOG(ERROR) << "Drop wrong request " << request.id;
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler_.run_in_context_external(
|
||||
[&] { send_closure(tonlib_, &TonlibClient::request, request.id, std::move(request.function)); });
|
||||
}
|
||||
|
||||
Client::Response receive(double timeout) {
|
||||
VLOG(tonlib_requests) << "Begin to wait for updates with timeout " << timeout;
|
||||
auto is_locked = receive_lock_.exchange(true);
|
||||
CHECK(!is_locked);
|
||||
auto response = receive_unlocked(timeout);
|
||||
is_locked = receive_lock_.exchange(false);
|
||||
CHECK(is_locked);
|
||||
VLOG(tonlib_requests) << "End to wait for updates, returning object " << response.id << ' '
|
||||
<< response.object.get();
|
||||
return response;
|
||||
}
|
||||
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
Impl(Impl&&) = delete;
|
||||
Impl& operator=(Impl&&) = delete;
|
||||
~Impl() {
|
||||
LOG(ERROR) << "~Impl";
|
||||
scheduler_.run_in_context_external([&] { tonlib_.reset(); });
|
||||
LOG(ERROR) << "Wait till closed";
|
||||
while (!is_closed_) {
|
||||
receive(10);
|
||||
}
|
||||
LOG(ERROR) << "Stop";
|
||||
scheduler_.run_in_context_external([] { td::actor::SchedulerContext::get()->stop(); });
|
||||
LOG(ERROR) << "join";
|
||||
scheduler_thread_.join();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<OutputQueue> output_queue_;
|
||||
int output_queue_ready_cnt_{0};
|
||||
std::atomic<bool> receive_lock_{false};
|
||||
bool is_closed_{false};
|
||||
|
||||
td::actor::Scheduler scheduler_{{0}};
|
||||
td::thread scheduler_thread_;
|
||||
td::actor::ActorOwn<TonlibClient> tonlib_;
|
||||
|
||||
Client::Response receive_unlocked(double timeout) {
|
||||
if (output_queue_ready_cnt_ == 0) {
|
||||
output_queue_ready_cnt_ = output_queue_->reader_wait_nonblock();
|
||||
}
|
||||
if (output_queue_ready_cnt_ > 0) {
|
||||
output_queue_ready_cnt_--;
|
||||
auto res = output_queue_->reader_get_unsafe();
|
||||
if (res.object == nullptr && res.id == 0) {
|
||||
is_closed_ = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
if (timeout != 0) {
|
||||
output_queue_->reader_get_event_fd().wait(static_cast<int>(timeout * 1000));
|
||||
return receive_unlocked(0);
|
||||
}
|
||||
return {0, nullptr};
|
||||
}
|
||||
};
|
||||
|
||||
Client::Client() : impl_(std::make_unique<Impl>()) {
|
||||
// At least it should be enough for everybody who uses TDLib
|
||||
// FIXME
|
||||
//td::init_openssl_threads();
|
||||
}
|
||||
|
||||
void Client::send(Request&& request) {
|
||||
impl_->send(std::move(request));
|
||||
}
|
||||
|
||||
Client::Response Client::receive(double timeout) {
|
||||
return impl_->receive(timeout);
|
||||
}
|
||||
|
||||
Client::Response Client::execute(Request&& request) {
|
||||
Response response;
|
||||
response.id = request.id;
|
||||
response.object = TonlibClient::static_request(std::move(request.function));
|
||||
return response;
|
||||
}
|
||||
|
||||
Client::~Client() = default;
|
||||
Client::Client(Client&& other) = default;
|
||||
Client& Client::operator=(Client&& other) = default;
|
||||
} // namespace tonlib
|
52
tonlib/tonlib/Client.h
Normal file
52
tonlib/tonlib/Client.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
namespace tonlib_api = ton::tonlib_api;
|
||||
|
||||
namespace tonlib {
|
||||
class Client final {
|
||||
public:
|
||||
Client();
|
||||
struct Request {
|
||||
std::uint64_t id;
|
||||
tonlib_api::object_ptr<tonlib_api::Function> function;
|
||||
};
|
||||
|
||||
void send(Request&& request);
|
||||
|
||||
struct Response {
|
||||
std::uint64_t id;
|
||||
tonlib_api::object_ptr<tonlib_api::Object> object;
|
||||
};
|
||||
|
||||
Response receive(double timeout);
|
||||
|
||||
static Response execute(Request&& request);
|
||||
|
||||
~Client();
|
||||
Client(Client&& other);
|
||||
Client& operator=(Client&& other);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
} // namespace tonlib
|
18
tonlib/tonlib/ClientActor.cpp
Normal file
18
tonlib/tonlib/ClientActor.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
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
|
||||
*/
|
41
tonlib/tonlib/ClientActor.h
Normal file
41
tonlib/tonlib/ClientActor.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
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/TonlibCallback.h"
|
||||
#include "tonlib/TonlibClient.h"
|
||||
#include "auto/tl/tonlib_api.h"
|
||||
|
||||
namespace tonlinb {
|
||||
class ClientActor : public td::actor::Actor {
|
||||
public:
|
||||
explicit ClientActor(td::unique_ptr<TonlibCallback> callback);
|
||||
void request(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Function> request);
|
||||
static tonlib_api::object_ptr<tonlib_api::Object> execute(tonlib_api::object_ptr<tonlib_api::Function> request);
|
||||
~ClientActor();
|
||||
ClientActor(ClientActor&& other);
|
||||
ClientActor& operator=(ClientActor&& other);
|
||||
|
||||
ClientActor(const ClientActor& other) = delete;
|
||||
ClientActor& operator=(const ClientActor& other) = delete;
|
||||
|
||||
private:
|
||||
td::actor::ActorOwn<TonlibClient> tonlib_;
|
||||
};
|
||||
} // namespace tonlinb
|
119
tonlib/tonlib/ClientJson.cpp
Normal file
119
tonlib/tonlib/ClientJson.cpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
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/ClientJson.h"
|
||||
|
||||
#include "auto/tl/tonlib_api_json.h"
|
||||
|
||||
#include "tl/tl_json.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/thread_local.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
static td::Result<std::pair<tonlib_api::object_ptr<tonlib_api::Function>, std::string>> to_request(td::Slice request) {
|
||||
auto request_str = request.str();
|
||||
TRY_RESULT(json_value, td::json_decode(request_str));
|
||||
if (json_value.type() != td::JsonValue::Type::Object) {
|
||||
return td::Status::Error("Expected an Object");
|
||||
}
|
||||
|
||||
std::string extra;
|
||||
if (has_json_object_field(json_value.get_object(), "@extra")) {
|
||||
extra = td::json_encode<std::string>(
|
||||
get_json_object_field(json_value.get_object(), "@extra", td::JsonValue::Type::Null).move_as_ok());
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::Function> func;
|
||||
TRY_STATUS(from_json(func, json_value));
|
||||
return std::make_pair(std::move(func), extra);
|
||||
}
|
||||
|
||||
static std::string from_response(const tonlib_api::Object &object, const td::string &extra) {
|
||||
auto str = td::json_encode<td::string>(td::ToJson(object));
|
||||
CHECK(!str.empty() && str.back() == '}');
|
||||
if (!extra.empty()) {
|
||||
str.pop_back();
|
||||
str.reserve(str.size() + 11 + extra.size());
|
||||
str += ",\"@extra\":";
|
||||
str += extra;
|
||||
str += '}';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static TD_THREAD_LOCAL std::string *current_output;
|
||||
|
||||
static td::CSlice store_string(std::string str) {
|
||||
td::init_thread_local<std::string>(current_output);
|
||||
*current_output = std::move(str);
|
||||
return *current_output;
|
||||
}
|
||||
|
||||
void ClientJson::send(td::Slice request) {
|
||||
auto r_request = to_request(request);
|
||||
if (r_request.is_error()) {
|
||||
LOG(ERROR) << "Failed to parse " << tag("request", td::format::escaped(request)) << " " << r_request.error();
|
||||
return;
|
||||
}
|
||||
|
||||
std::uint64_t extra_id = extra_id_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (!r_request.ok_ref().second.empty()) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
extra_[extra_id] = std::move(r_request.ok_ref().second);
|
||||
}
|
||||
client_.send(Client::Request{extra_id, std::move(r_request.ok_ref().first)});
|
||||
}
|
||||
|
||||
td::CSlice ClientJson::receive(double timeout) {
|
||||
auto response = client_.receive(timeout);
|
||||
if (!response.object) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string extra;
|
||||
if (response.id != 0) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
auto it = extra_.find(response.id);
|
||||
if (it != extra_.end()) {
|
||||
extra = std::move(it->second);
|
||||
extra_.erase(it);
|
||||
}
|
||||
}
|
||||
return store_string(from_response(*response.object, extra));
|
||||
}
|
||||
|
||||
td::CSlice ClientJson::execute(td::Slice request) {
|
||||
auto r_request = to_request(request);
|
||||
if (r_request.is_error()) {
|
||||
LOG(ERROR) << "Failed to parse " << tag("request", td::format::escaped(request)) << " " << r_request.error();
|
||||
return {};
|
||||
}
|
||||
|
||||
return store_string(from_response(*Client::execute(Client::Request{0, std::move(r_request.ok_ref().first)}).object,
|
||||
r_request.ok().second));
|
||||
}
|
||||
|
||||
} // namespace tonlib
|
48
tonlib/tonlib/ClientJson.h
Normal file
48
tonlib/tonlib/ClientJson.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
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/Client.h"
|
||||
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
class ClientJson final {
|
||||
public:
|
||||
void send(td::Slice request);
|
||||
|
||||
td::CSlice receive(double timeout);
|
||||
|
||||
static td::CSlice execute(td::Slice request);
|
||||
|
||||
private:
|
||||
Client client_;
|
||||
std::mutex mutex_; // for extra_
|
||||
std::unordered_map<std::int64_t, std::string> extra_;
|
||||
std::atomic<std::uint64_t> extra_id_{1};
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
70
tonlib/tonlib/Config.cpp
Normal file
70
tonlib/tonlib/Config.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
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 "Config.h"
|
||||
#include "adnl/adnl-node-id.hpp"
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::Result<Config> Config::parse(std::string str) {
|
||||
TRY_RESULT(json, td::json_decode(str));
|
||||
if (json.type() != td::JsonValue::Type::Object) {
|
||||
return td::Status::Error("Invalid config (1)");
|
||||
}
|
||||
//TRY_RESULT(main_type, td::get_json_object_string_field(json.get_object(), "@type", false));
|
||||
//if (main_type != "config.global") {
|
||||
//return td::Status::Error("Invalid config (3)");
|
||||
//}
|
||||
TRY_RESULT(lite_clients_obj,
|
||||
td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, false));
|
||||
auto &lite_clients = lite_clients_obj.get_array();
|
||||
|
||||
Config res;
|
||||
for (auto &value : lite_clients) {
|
||||
if (value.type() != td::JsonValue::Type::Object) {
|
||||
return td::Status::Error("Invalid config (2)");
|
||||
}
|
||||
auto &object = value.get_object();
|
||||
//TRY_RESULT(value_type, td::get_json_object_string_field(object, "@type", false));
|
||||
//if (value_type != "liteclient.config.global") {
|
||||
//return td::Status::Error("Invalid config (4)");
|
||||
//}
|
||||
|
||||
TRY_RESULT(ip, td::get_json_object_int_field(object, "ip", false));
|
||||
TRY_RESULT(port, td::get_json_object_int_field(object, "port", false));
|
||||
Config::LiteClient client;
|
||||
TRY_STATUS(client.address.init_host_port(td::IPAddress::ipv4_to_str(ip), port));
|
||||
|
||||
TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false));
|
||||
auto &id = id_obj.get_object();
|
||||
TRY_RESULT(id_type, td::get_json_object_string_field(id, "@type", false));
|
||||
if (id_type != "pub.ed25519") {
|
||||
return td::Status::Error("Invalid config (5)");
|
||||
}
|
||||
TRY_RESULT(key_base64, td::get_json_object_string_field(id, "key", false));
|
||||
TRY_RESULT(key, td::base64_decode(key_base64));
|
||||
if (key.size() != 32) {
|
||||
return td::Status::Error("Invalid config (6)");
|
||||
}
|
||||
|
||||
client.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
|
||||
res.lite_clients.push_back(std::move(client));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} // namespace tonlib
|
32
tonlib/tonlib/Config.h
Normal file
32
tonlib/tonlib/Config.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
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 "adnl/adnl-node-id.hpp"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
|
||||
namespace tonlib {
|
||||
struct Config {
|
||||
struct LiteClient {
|
||||
ton::adnl::AdnlNodeIdFull adnl_id;
|
||||
td::IPAddress address;
|
||||
};
|
||||
std::vector<LiteClient> lite_clients;
|
||||
static td::Result<Config> parse(std::string str);
|
||||
};
|
||||
} // namespace tonlib
|
52
tonlib/tonlib/ExtClient.cpp
Normal file
52
tonlib/tonlib/ExtClient.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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/ExtClient.h"
|
||||
|
||||
#include "tonlib/LastBlock.h"
|
||||
|
||||
namespace tonlib {
|
||||
void ExtClient::with_last_block(td::Promise<ton::BlockIdExt> promise) {
|
||||
auto query_id = last_block_queries_.create(std::move(promise));
|
||||
td::Promise<ton::BlockIdExt> P = [query_id, self = this,
|
||||
actor_id = td::actor::actor_id()](td::Result<ton::BlockIdExt> result) {
|
||||
send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable {
|
||||
self->last_block_queries_.extract(query_id).set_result(std::move(result));
|
||||
});
|
||||
};
|
||||
if (client_.last_block_actor_.empty()) {
|
||||
return P.set_error(td::Status::Error(500, "No lite clients"));
|
||||
}
|
||||
td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
|
||||
}
|
||||
|
||||
void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
|
||||
auto query_id = queries_.create(std::move(promise));
|
||||
td::Promise<td::BufferSlice> P = [query_id, self = this,
|
||||
actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) {
|
||||
send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable {
|
||||
self->queries_.extract(query_id).set_result(std::move(result));
|
||||
});
|
||||
};
|
||||
if (client_.andl_ext_client_.empty()) {
|
||||
return P.set_error(td::Status::Error(500, "No lite clients"));
|
||||
}
|
||||
td::actor::send_closure(client_.andl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
|
||||
td::Timestamp::in(10.0), std::move(P));
|
||||
}
|
||||
} // namespace tonlib
|
80
tonlib/tonlib/ExtClient.h
Normal file
80
tonlib/tonlib/ExtClient.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
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 "adnl/adnl-ext-client.h"
|
||||
#include "tl-utils/lite-utils.hpp"
|
||||
|
||||
#include "auto/tl/lite_api.h"
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/Container.h"
|
||||
|
||||
namespace tonlib {
|
||||
class LastBlock;
|
||||
struct ExtClientRef {
|
||||
td::actor::ActorId<ton::adnl::AdnlExtClient> andl_ext_client_;
|
||||
td::actor::ActorId<LastBlock> last_block_actor_;
|
||||
};
|
||||
|
||||
class ExtClient {
|
||||
public:
|
||||
ExtClient() = default;
|
||||
ExtClient(const ExtClient&) = delete;
|
||||
ExtClient(ExtClient&&) = delete;
|
||||
ExtClient& operator=(const ExtClient&) = delete;
|
||||
ExtClient& operator=(ExtClient&&) = delete;
|
||||
|
||||
void set_client(ExtClientRef client) {
|
||||
client_ = client;
|
||||
}
|
||||
ExtClientRef get_client() {
|
||||
return client_;
|
||||
}
|
||||
|
||||
void with_last_block(td::Promise<ton::BlockIdExt> promise);
|
||||
|
||||
template <class QueryT>
|
||||
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
|
||||
auto raw_query = ton::serialize_tl_object(&query, true);
|
||||
td::BufferSlice liteserver_query =
|
||||
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
|
||||
|
||||
send_raw_query(std::move(liteserver_query), [promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
promise.set_result([&]() -> td::Result<typename QueryT::ReturnType> {
|
||||
TRY_RESULT(data, std::move(R));
|
||||
auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
|
||||
if (r_error.is_ok()) {
|
||||
auto f = r_error.move_as_ok();
|
||||
return td::Status::Error(f->code_, f->message_);
|
||||
}
|
||||
return ton::fetch_result<QueryT>(std::move(data));
|
||||
}());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
ExtClientRef client_;
|
||||
td::Container<td::Promise<td::BufferSlice>> queries_;
|
||||
td::Container<td::Promise<ton::BlockIdExt>> last_block_queries_;
|
||||
|
||||
void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
};
|
||||
} // namespace tonlib
|
100
tonlib/tonlib/ExtClientLazy.cpp
Normal file
100
tonlib/tonlib/ExtClientLazy.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
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 "ExtClientLazy.h"
|
||||
namespace tonlib {
|
||||
|
||||
class ExtClientLazyImp : public ton::adnl::AdnlExtClient {
|
||||
public:
|
||||
ExtClientLazyImp(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
td::unique_ptr<ExtClientLazy::Callback> callback)
|
||||
: dst_(std::move(dst)), dst_addr_(std::move(dst_addr)), callback_(std::move(callback)) {
|
||||
}
|
||||
|
||||
void check_ready(td::Promise<td::Unit> promise) override {
|
||||
before_query();
|
||||
send_closure(client_, &ton::adnl::AdnlExtClient::check_ready, std::move(promise));
|
||||
}
|
||||
|
||||
void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
before_query();
|
||||
send_closure(client_, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void before_query() {
|
||||
if (is_closing_) {
|
||||
return;
|
||||
}
|
||||
if (!client_.empty()) {
|
||||
alarm_timestamp() = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
class Callback : public ton::adnl::AdnlExtClient::Callback {
|
||||
public:
|
||||
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
|
||||
}
|
||||
void on_ready() override {
|
||||
}
|
||||
void on_stop_ready() override {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<> parent_;
|
||||
};
|
||||
ref_cnt_++;
|
||||
client_ = ton::adnl::AdnlExtClient::create(dst_, dst_addr_, std::make_unique<Callback>(td::actor::actor_shared()));
|
||||
}
|
||||
|
||||
private:
|
||||
ton::adnl::AdnlNodeIdFull dst_;
|
||||
td::IPAddress dst_addr_;
|
||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client_;
|
||||
td::unique_ptr<ExtClientLazy::Callback> callback_;
|
||||
static constexpr double MAX_NO_QUERIES_TIMEOUT = 100;
|
||||
|
||||
bool is_closing_{false};
|
||||
td::uint32 ref_cnt_{1};
|
||||
|
||||
void alarm() override {
|
||||
client_.reset();
|
||||
}
|
||||
void hangup_shared() override {
|
||||
ref_cnt_--;
|
||||
try_stop();
|
||||
}
|
||||
void hangup() override {
|
||||
is_closing_ = true;
|
||||
ref_cnt_--;
|
||||
client_.reset();
|
||||
try_stop();
|
||||
}
|
||||
void try_stop() {
|
||||
if (is_closing_ && ref_cnt_ == 0) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> ExtClientLazy::create(ton::adnl::AdnlNodeIdFull dst,
|
||||
td::IPAddress dst_addr,
|
||||
td::unique_ptr<Callback> callback) {
|
||||
return td::actor::create_actor<ExtClientLazyImp>("ExtClientLazy", dst, dst_addr, std::move(callback));
|
||||
}
|
||||
} // namespace tonlib
|
36
tonlib/tonlib/ExtClientLazy.h
Normal file
36
tonlib/tonlib/ExtClientLazy.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 "td/actor/actor.h"
|
||||
|
||||
#include "adnl/adnl-ext-client.h"
|
||||
|
||||
namespace tonlib {
|
||||
class ExtClientLazy {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback() {
|
||||
}
|
||||
};
|
||||
static td::actor::ActorOwn<ton::adnl::AdnlExtClient> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
td::unique_ptr<Callback> callback);
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
79
tonlib/tonlib/GenericAccount.cpp
Normal file
79
tonlib/tonlib/GenericAccount.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
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/GenericAccount.h"
|
||||
#include "tonlib/utils.h"
|
||||
#include "block/block-auto.h"
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) {
|
||||
return vm::CellBuilder()
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{00110}").move_as_ok())
|
||||
.store_ref(std::move(code))
|
||||
.store_ref(std::move(data))
|
||||
.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());
|
||||
}
|
||||
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body) {
|
||||
block::gen::Message::Record message;
|
||||
/*info*/ {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
/* src */
|
||||
tlb::csr_pack(info.src, block::gen::MsgAddressExt::Record_addr_none{});
|
||||
/* dest */ {
|
||||
block::gen::MsgAddressInt::Record_addr_std dest;
|
||||
dest.anycast = vm::CellBuilder().store_zeroes(1).as_cellslice_ref();
|
||||
dest.workchain_id = address.workchain;
|
||||
dest.address = address.addr;
|
||||
|
||||
tlb::csr_pack(info.dest, dest);
|
||||
}
|
||||
/* import_fee */ {
|
||||
vm::CellBuilder cb;
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(0));
|
||||
info.import_fee = cb.as_cellslice_ref();
|
||||
}
|
||||
|
||||
tlb::csr_pack(message.info, info);
|
||||
}
|
||||
/* init */ {
|
||||
if (new_state.not_null()) {
|
||||
// Just(Left(new_state))
|
||||
message.init = vm::CellBuilder()
|
||||
.store_ones(1)
|
||||
.store_zeroes(1)
|
||||
.append_cellslice(vm::load_cell_slice(new_state))
|
||||
.as_cellslice_ref();
|
||||
} else {
|
||||
message.init = vm::CellBuilder().store_zeroes(1).as_cellslice_ref();
|
||||
CHECK(message.init.not_null());
|
||||
}
|
||||
}
|
||||
/* body */ {
|
||||
message.body = vm::CellBuilder().store_zeroes(1).append_cellslice(vm::load_cell_slice_ref(body)).as_cellslice_ref();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> res;
|
||||
tlb::type_pack_cell(res, block::gen::t_Message_Any, message);
|
||||
CHECK(res.not_null());
|
||||
|
||||
return res;
|
||||
}
|
||||
} // namespace tonlib
|
30
tonlib/tonlib/GenericAccount.h
Normal file
30
tonlib/tonlib/GenericAccount.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
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 "block/block.h"
|
||||
namespace tonlib {
|
||||
class GenericAccount {
|
||||
public:
|
||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data);
|
||||
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state);
|
||||
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body);
|
||||
};
|
||||
} // namespace tonlib
|
148
tonlib/tonlib/KeyStorage.cpp
Normal file
148
tonlib/tonlib/KeyStorage.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
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 "KeyStorage.h"
|
||||
|
||||
#include "tonlib/keys/Mnemonic.h"
|
||||
#include "tonlib/keys/DecryptedKey.h"
|
||||
#include "tonlib/keys/EncryptedKey.h"
|
||||
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
|
||||
namespace tonlib {
|
||||
std::string to_file_name(td::Slice public_key) {
|
||||
return td::buffer_to_hex(public_key);
|
||||
}
|
||||
|
||||
std::string KeyStorage::to_file_path(td::Slice public_key) {
|
||||
return directory_ + TD_DIR_SLASH + to_file_name(public_key);
|
||||
}
|
||||
td::Status KeyStorage::set_directory(std::string directory) {
|
||||
TRY_RESULT(path, td::realpath(directory));
|
||||
TRY_RESULT(stat, td::stat(path));
|
||||
if (!stat.is_dir_) {
|
||||
return td::Status::Error("not a directory");
|
||||
}
|
||||
directory_ = std::move(path);
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::save_key(const DecryptedKey &decrypted_key, td::Slice local_password) {
|
||||
auto encrypted_key = decrypted_key.encrypt(local_password);
|
||||
|
||||
Key res;
|
||||
res.public_key = encrypted_key.public_key.as_octet_string();
|
||||
res.secret = std::move(encrypted_key.secret);
|
||||
|
||||
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));
|
||||
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);
|
||||
}
|
||||
to_file.close();
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::create_new_key(td::Slice local_password, td::Slice mnemonic_password) {
|
||||
Mnemonic::Options create_options;
|
||||
create_options.password = td::SecureString(mnemonic_password);
|
||||
TRY_RESULT(mnemonic, Mnemonic::create_new(std::move(create_options)));
|
||||
|
||||
return save_key(DecryptedKey(std::move(mnemonic)), 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)));
|
||||
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));
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::ExportedKey> KeyStorage::export_key(InputKey input_key) {
|
||||
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
||||
ExportedKey exported_key;
|
||||
exported_key.mnemonic_words = std::move(decrypted_key.mnemonic_words);
|
||||
return std::move(exported_key);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::PrivateKey> KeyStorage::load_private_key(InputKey input_key) {
|
||||
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
||||
PrivateKey private_key;
|
||||
private_key.private_key = decrypted_key.private_key.as_octet_string();
|
||||
return std::move(private_key);
|
||||
}
|
||||
|
||||
td::Status KeyStorage::delete_key(td::Slice public_key) {
|
||||
return td::unlink(to_file_path(public_key));
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password,
|
||||
ExportedKey exported_key) {
|
||||
TRY_RESULT(mnemonic, Mnemonic::create(std::move(exported_key.mnemonic_words), td::SecureString(mnemonic_password)));
|
||||
if (!mnemonic.is_basic_seed()) {
|
||||
if (mnemonic_password.empty() && mnemonic.is_password_seed()) {
|
||||
return td::Status::Error("Mnemonic password is expected");
|
||||
}
|
||||
return td::Status::Error("Invalid mnemonic words or password (invalid checksum)");
|
||||
}
|
||||
return save_key(DecryptedKey(std::move(mnemonic)), local_password);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::ExportedPemKey> KeyStorage::export_pem_key(InputKey input_key, td::Slice key_password) {
|
||||
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
||||
TRY_RESULT(pem, decrypted_key.private_key.as_pem(key_password));
|
||||
return ExportedPemKey{std::move(pem)};
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::change_local_password(InputKey input_key, td::Slice new_local_password) {
|
||||
auto new_secret =
|
||||
DecryptedKey::change_local_password(input_key.key.secret, input_key.local_password, new_local_password);
|
||||
Key res;
|
||||
res.public_key = std::move(input_key.key.public_key);
|
||||
res.secret = std::move(new_secret);
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password,
|
||||
ExportedPemKey exported_key) {
|
||||
TRY_RESULT(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password));
|
||||
return save_key(DecryptedKey({}, std::move(key)), local_password);
|
||||
}
|
||||
|
||||
static std::string dummy_secret = "dummy secret of 32 bytes length!";
|
||||
td::Result<KeyStorage::ExportedEncryptedKey> KeyStorage::export_encrypted_key(InputKey input_key,
|
||||
td::Slice key_password) {
|
||||
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
||||
auto res = decrypted_key.encrypt(key_password, dummy_secret);
|
||||
return ExportedEncryptedKey{std::move(res.encrypted_data)};
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::import_encrypted_key(td::Slice local_password, td::Slice key_password,
|
||||
ExportedEncryptedKey exported_key) {
|
||||
EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()),
|
||||
td::SecureString(dummy_secret)};
|
||||
TRY_RESULT(decrypted_key, encrypted_key.decrypt(key_password, false));
|
||||
return save_key(std::move(decrypted_key), local_password);
|
||||
}
|
||||
|
||||
} // namespace tonlib
|
77
tonlib/tonlib/KeyStorage.h
Normal file
77
tonlib/tonlib/KeyStorage.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
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 "td/utils/Status.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tonlib {
|
||||
struct DecryptedKey;
|
||||
class KeyStorage {
|
||||
public:
|
||||
struct Key {
|
||||
td::SecureString public_key;
|
||||
td::SecureString secret;
|
||||
};
|
||||
struct InputKey {
|
||||
Key key;
|
||||
td::SecureString local_password;
|
||||
};
|
||||
struct ExportedKey {
|
||||
std::vector<td::SecureString> mnemonic_words;
|
||||
};
|
||||
struct ExportedPemKey {
|
||||
td::SecureString pem;
|
||||
};
|
||||
struct ExportedEncryptedKey {
|
||||
td::SecureString data;
|
||||
};
|
||||
struct PrivateKey {
|
||||
td::SecureString private_key;
|
||||
};
|
||||
|
||||
td::Status set_directory(std::string directory);
|
||||
|
||||
td::Result<Key> create_new_key(td::Slice local_password, td::Slice key_password);
|
||||
|
||||
td::Result<ExportedKey> export_key(InputKey input_key);
|
||||
td::Result<ExportedPemKey> export_pem_key(InputKey input_key, td::Slice key_password);
|
||||
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::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);
|
||||
td::Result<Key> import_encrypted_key(td::Slice local_password, td::Slice key_password,
|
||||
ExportedEncryptedKey exported_key);
|
||||
|
||||
td::Result<PrivateKey> load_private_key(InputKey input_key);
|
||||
|
||||
private:
|
||||
std::string directory_;
|
||||
|
||||
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);
|
||||
};
|
||||
} // namespace tonlib
|
86
tonlib/tonlib/LastBlock.cpp
Normal file
86
tonlib/tonlib/LastBlock.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/LastBlock.h"
|
||||
|
||||
#include "ton/lite-tl.hpp"
|
||||
|
||||
namespace tonlib {
|
||||
LastBlock::LastBlock(ExtClientRef client, td::actor::ActorShared<> parent) {
|
||||
client_.set_client(client);
|
||||
parent_ = std::move(parent);
|
||||
}
|
||||
|
||||
void LastBlock::get_last_block(td::Promise<ton::BlockIdExt> promise) {
|
||||
if (promises_.empty()) {
|
||||
do_get_last_block();
|
||||
}
|
||||
promises_.push_back(std::move(promise));
|
||||
}
|
||||
|
||||
void LastBlock::do_get_last_block() {
|
||||
client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
|
||||
[this](auto r_info) { this->on_masterchain_info(std::move(r_info)); });
|
||||
}
|
||||
void LastBlock::on_masterchain_info(
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info) {
|
||||
if (r_info.is_ok()) {
|
||||
auto info = r_info.move_as_ok();
|
||||
update_zero_state(create_zero_state_id(info->init_));
|
||||
update_mc_last_block(create_block_id(info->last_));
|
||||
}
|
||||
for (auto& promise : promises_) {
|
||||
auto copy = mc_last_block_id_;
|
||||
promise.set_value(std::move(copy));
|
||||
}
|
||||
promises_.clear();
|
||||
}
|
||||
|
||||
void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
|
||||
if (!zero_state_id.is_valid()) {
|
||||
LOG(ERROR) << "Ignore invalid zero state update";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!zero_state_id_.is_valid()) {
|
||||
LOG(INFO) << "Init zerostate: " << zero_state_id.to_str();
|
||||
zero_state_id_ = std::move(zero_state_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zero_state_id_ == zero_state_id_) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(FATAL) << "Masterchain zerostate mismatch: expected: " << zero_state_id_.to_str() << ", found "
|
||||
<< zero_state_id.to_str();
|
||||
// TODO: all other updates will be inconsitent.
|
||||
// One will have to restart ton client
|
||||
}
|
||||
|
||||
void LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
|
||||
if (!mc_block_id.is_valid()) {
|
||||
LOG(ERROR) << "Ignore invalid masterchain block";
|
||||
return;
|
||||
}
|
||||
if (!mc_last_block_id_.is_valid() || mc_last_block_id_.id.seqno < mc_block_id.id.seqno) {
|
||||
mc_last_block_id_ = mc_block_id;
|
||||
LOG(INFO) << "Update masterchain block id: " << mc_last_block_id_.to_str();
|
||||
}
|
||||
}
|
||||
} // namespace tonlib
|
47
tonlib/tonlib/LastBlock.h
Normal file
47
tonlib/tonlib/LastBlock.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
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 "td/actor/actor.h"
|
||||
|
||||
#include "tonlib/ExtClient.h"
|
||||
|
||||
namespace tonlib {
|
||||
class LastBlock : public td::actor::Actor {
|
||||
public:
|
||||
explicit LastBlock(ExtClientRef client, td::actor::ActorShared<> parent);
|
||||
|
||||
void get_last_block(td::Promise<ton::BlockIdExt> promise);
|
||||
|
||||
private:
|
||||
ExtClient client_;
|
||||
ton::ZeroStateIdExt zero_state_id_;
|
||||
ton::BlockIdExt mc_last_block_id_;
|
||||
|
||||
std::vector<td::Promise<ton::BlockIdExt>> promises_;
|
||||
|
||||
td::actor::ActorShared<> parent_;
|
||||
|
||||
void do_get_last_block();
|
||||
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
||||
|
||||
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
|
||||
|
||||
void update_mc_last_block(ton::BlockIdExt mc_block_id);
|
||||
};
|
||||
} // namespace tonlib
|
50
tonlib/tonlib/TestGiver.cpp
Normal file
50
tonlib/tonlib/TestGiver.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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/TestGiver.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace tonlib {
|
||||
const block::StdAddress& TestGiver::address() {
|
||||
static block::StdAddress res =
|
||||
block::StdAddress::parse("-1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash TestGiver::get_init_code_hash() {
|
||||
return vm::CellHash::from_slice(td::base64_decode("s7RouN9wfJ4Avx8h0uw6X3ZEJfN3MYOUmzrC8JXfMAw=").move_as_ok());
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms,
|
||||
const block::StdAddress& dest_address) {
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
cb.append_cellslice(binary_bitstring_to_cellslice("b{01}").move_as_ok())
|
||||
.store_long(dest_address.bounceable, 1)
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").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("GIFT").finalize();
|
||||
return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
|
||||
}
|
||||
} // namespace tonlib
|
29
tonlib/tonlib/TestGiver.h
Normal file
29
tonlib/tonlib/TestGiver.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
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 "block/block.h"
|
||||
namespace tonlib {
|
||||
class TestGiver {
|
||||
public:
|
||||
static const block::StdAddress& address();
|
||||
static vm::CellHash get_init_code_hash();
|
||||
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms,
|
||||
const block::StdAddress& dest_address);
|
||||
};
|
||||
} // namespace tonlib
|
74
tonlib/tonlib/TestWallet.cpp
Normal file
74
tonlib/tonlib/TestWallet.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
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/TestWallet.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> TestWallet::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> TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) {
|
||||
std::string seq_no(4, 0);
|
||||
auto signature =
|
||||
private_key.sign(vm::CellBuilder().store_bytes(seq_no).finalize()->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).store_bytes(seq_no).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::int64 gramms, const block::StdAddress& dest_address) {
|
||||
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("GIFT").finalize();
|
||||
auto message = 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->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_code() {
|
||||
static auto res = [] {
|
||||
auto serialized_code = td::base64_decode(
|
||||
"te6ccgEEAQEAAAAARAAAhP8AIN2k8mCBAgDXGCDXCx/tRNDTH9P/"
|
||||
"0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA==")
|
||||
.move_as_ok();
|
||||
return vm::std_boc_deserialize(serialized_code).move_as_ok();
|
||||
}();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash TestWallet::get_init_code_hash() {
|
||||
return get_init_code()->get_hash();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::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
|
37
tonlib/tonlib/TestWallet.h
Normal file
37
tonlib/tonlib/TestWallet.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
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 TestWallet {
|
||||
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::int64 gramms, 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
|
30
tonlib/tonlib/TonlibCallback.h
Normal file
30
tonlib/tonlib/TonlibCallback.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
namespace tonlib_api = ton::tonlib_api;
|
||||
|
||||
class TonlibCallback {
|
||||
public:
|
||||
virtual void on_result(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::Object> result) = 0;
|
||||
virtual void on_error(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::error> error) = 0;
|
||||
virtual ~TonlibCallback() = default;
|
||||
};
|
996
tonlib/tonlib/TonlibClient.cpp
Normal file
996
tonlib/tonlib/TonlibClient.cpp
Normal file
|
@ -0,0 +1,996 @@
|
|||
/*
|
||||
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 "TonlibClient.h"
|
||||
|
||||
#include "tonlib/ExtClientLazy.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/LastBlock.h"
|
||||
#include "tonlib/TestWallet.h"
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "auto/tl/tonlib_api.hpp"
|
||||
#include "block/block-auto.h"
|
||||
#include "block/check-proof.h"
|
||||
#include "ton/lite-tl.hpp"
|
||||
#include "ton/ton-shard.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
#include "td/utils/tests.h"
|
||||
#include "td/utils/port/path.h"
|
||||
|
||||
namespace ton {} // namespace ton
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
template <class F>
|
||||
auto try_f(F&& f) noexcept -> decltype(f()) {
|
||||
try {
|
||||
return f();
|
||||
} catch (vm::VmError error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm exception: " << error.get_msg());
|
||||
}
|
||||
}
|
||||
|
||||
#define TRY_VM(f) try_f([&] { return f; })
|
||||
|
||||
static block::AccountState create_account_state(ton::tl_object_ptr<ton::lite_api::liteServer_accountState> 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_);
|
||||
return res;
|
||||
}
|
||||
struct RawAccountState {
|
||||
td::int64 balance = -1;
|
||||
td::Ref<vm::CellSlice> code;
|
||||
td::Ref<vm::CellSlice> data;
|
||||
block::AccountState::Info info;
|
||||
};
|
||||
|
||||
td::Result<td::int64> to_balance_or_throw(td::Ref<vm::CellSlice> balance_ref) {
|
||||
vm::CellSlice balance_slice = *balance_ref;
|
||||
auto balance = block::tlb::t_Grams.as_integer_skip(balance_slice);
|
||||
if (balance.is_null()) {
|
||||
return td::Status::Error("Failed to unpack balance");
|
||||
}
|
||||
auto res = balance->to_long();
|
||||
if (res == td::int64(~0ULL << 63)) {
|
||||
return td::Status::Error("Failed to unpack balance (2)");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Result<td::int64> to_balance(td::Ref<vm::CellSlice> balance_ref) {
|
||||
return TRY_VM(to_balance_or_throw(std::move(balance_ref)));
|
||||
}
|
||||
|
||||
class GetTransactionHistory : public td::actor::Actor {
|
||||
public:
|
||||
GetTransactionHistory(ExtClientRef ext_client_ref, block::StdAddress address, ton::LogicalTime lt, ton::Bits256 hash,
|
||||
td::Promise<block::TransactionList::Info> promise)
|
||||
: address_(std::move(address)), lt_(std::move(lt)), hash_(std::move(hash)), promise_(std::move(promise)) {
|
||||
client_.set_client(ext_client_ref);
|
||||
}
|
||||
|
||||
private:
|
||||
block::StdAddress address_;
|
||||
ton::LogicalTime lt_;
|
||||
ton::Bits256 hash_;
|
||||
ExtClient client_;
|
||||
td::int32 count_{10};
|
||||
td::Promise<block::TransactionList::Info> promise_;
|
||||
|
||||
void check(td::Status status) {
|
||||
if (status.is_error()) {
|
||||
LOG(ERROR) << status;
|
||||
promise_.set_error(std::move(status));
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
td::Status do_with_transactions(std::vector<ton::BlockIdExt> blkids, td::BufferSlice transactions) {
|
||||
LOG(INFO) << "got up to " << count_ << " transactions for " << address_ << " from last transaction " << lt_ << ":"
|
||||
<< hash_.to_hex();
|
||||
block::TransactionList list;
|
||||
list.blkids = std::move(blkids);
|
||||
list.hash = hash_;
|
||||
list.lt = lt_;
|
||||
list.transactions_boc = std::move(transactions);
|
||||
TRY_RESULT(info, list.validate());
|
||||
if (info.transactions.size() > static_cast<size_t>(count_)) {
|
||||
LOG(WARNING) << "obtained " << info.transactions.size() << " transaction, but only " << count_
|
||||
<< " have been requested";
|
||||
}
|
||||
promise_.set_value(std::move(info));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status do_with_transactions(
|
||||
td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_transactionList>> r_transactions) {
|
||||
TRY_RESULT(transactions, std::move(r_transactions));
|
||||
std::vector<ton::BlockIdExt> blkids;
|
||||
for (auto& id : transactions->ids_) {
|
||||
blkids.push_back(ton::create_block_id(std::move(id)));
|
||||
}
|
||||
return do_with_transactions(std::move(blkids), std::move(transactions->transactions_));
|
||||
}
|
||||
|
||||
void with_transactions(
|
||||
td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_transactionList>> r_transactions) {
|
||||
check(TRY_VM(do_with_transactions(std::move(r_transactions))));
|
||||
stop();
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
client_.send_query(
|
||||
ton::lite_api::liteServer_getTransactions(
|
||||
count_, ton::create_tl_object<ton::lite_api::liteServer_accountId>(address_.workchain, address_.addr), lt_,
|
||||
hash_),
|
||||
[self = this](auto r_transactions) { self->with_transactions(std::move(r_transactions)); });
|
||||
}
|
||||
};
|
||||
|
||||
class GetRawAccountState : public td::actor::Actor {
|
||||
public:
|
||||
GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::Promise<RawAccountState>&& promise)
|
||||
: address_(std::move(address)), promise_(std::move(promise)) {
|
||||
client_.set_client(ext_client_ref);
|
||||
}
|
||||
|
||||
private:
|
||||
block::StdAddress address_;
|
||||
td::Promise<RawAccountState> promise_;
|
||||
ExtClient client_;
|
||||
ton::BlockIdExt last_block_;
|
||||
|
||||
void with_account_state(td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
|
||||
promise_.set_result(TRY_VM(do_with_account_state(std::move(r_account_state))));
|
||||
stop();
|
||||
}
|
||||
|
||||
td::Result<RawAccountState> do_with_account_state(
|
||||
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
|
||||
TRY_RESULT(raw_account_state, std::move(r_account_state));
|
||||
auto account_state = create_account_state(std::move(raw_account_state));
|
||||
TRY_RESULT(info, account_state.validate(last_block_, address_));
|
||||
auto serialized_state = account_state.state.clone();
|
||||
LOG(ERROR) << serialized_state.size();
|
||||
RawAccountState res;
|
||||
res.info = std::move(info);
|
||||
auto cell = res.info.root;
|
||||
if (cell.is_null()) {
|
||||
return res;
|
||||
}
|
||||
//block::gen::t_Account.print_ref(std::cerr, cell);
|
||||
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");
|
||||
}
|
||||
TRY_RESULT(balance, to_balance(storage.balance));
|
||||
res.balance = balance;
|
||||
auto state_tag = block::gen::t_AccountState.get_tag(*storage.state);
|
||||
if (state_tag < 0) {
|
||||
return td::Status::Error("Failed to parse AccountState tag");
|
||||
}
|
||||
// TODO: handle frozen account
|
||||
if (state_tag != block::gen::AccountState::account_active) {
|
||||
return res;
|
||||
}
|
||||
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");
|
||||
}
|
||||
res.code = std::move(state_init.code);
|
||||
res.data = std::move(state_init.data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
client_.with_last_block([self = this](td::Result<ton::BlockIdExt> r_last_block) {
|
||||
if (r_last_block.is_error()) {
|
||||
return self->check(r_last_block.move_as_error());
|
||||
}
|
||||
self->last_block_ = r_last_block.move_as_ok();
|
||||
|
||||
self->client_.send_query(
|
||||
ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_),
|
||||
ton::create_tl_object<ton::lite_api::liteServer_accountId>(
|
||||
self->address_.workchain, self->address_.addr)),
|
||||
[self](auto r_state) { self->with_account_state(std::move(r_state)); });
|
||||
});
|
||||
}
|
||||
|
||||
void check(td::Status status) {
|
||||
if (status.is_error()) {
|
||||
promise_.set_error(std::move(status));
|
||||
stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TonlibClient::TonlibClient(td::unique_ptr<TonlibCallback> callback) : callback_(std::move(callback)) {
|
||||
}
|
||||
TonlibClient::~TonlibClient() = default;
|
||||
|
||||
void TonlibClient::hangup() {
|
||||
is_closing_ = true;
|
||||
ref_cnt_--;
|
||||
raw_client_ = {};
|
||||
raw_last_block_ = {};
|
||||
try_stop();
|
||||
}
|
||||
|
||||
ExtClientRef TonlibClient::get_client_ref() {
|
||||
ExtClientRef ref;
|
||||
ref.andl_ext_client_ = raw_client_.get();
|
||||
ref.last_block_actor_ = raw_last_block_.get();
|
||||
|
||||
return ref;
|
||||
}
|
||||
void TonlibClient::init_ext_client() {
|
||||
auto lite_clients_size = config_.lite_clients.size();
|
||||
CHECK(lite_clients_size != 0);
|
||||
auto lite_client_id = td::Random::fast(0, td::narrow_cast<int>(lite_clients_size) - 1);
|
||||
auto& lite_client = config_.lite_clients[lite_client_id];
|
||||
class Callback : public ExtClientLazy::Callback {
|
||||
public:
|
||||
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<> parent_;
|
||||
};
|
||||
ref_cnt_++;
|
||||
raw_client_ = ExtClientLazy::create(lite_client.adnl_id, lite_client.address,
|
||||
td::make_unique<Callback>(td::actor::actor_shared()));
|
||||
ref_cnt_++;
|
||||
raw_last_block_ = td::actor::create_actor<LastBlock>("LastBlock", get_client_ref(), td::actor::actor_shared());
|
||||
client_.set_client(get_client_ref());
|
||||
}
|
||||
|
||||
void TonlibClient::on_result(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Object> response) {
|
||||
if (response->get_id() == tonlib_api::error::ID) {
|
||||
callback_->on_error(id, tonlib_api::move_object_as<tonlib_api::error>(response));
|
||||
return;
|
||||
}
|
||||
callback_->on_result(id, std::move(response));
|
||||
}
|
||||
void TonlibClient::request(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Function> function) {
|
||||
if (function == nullptr) {
|
||||
LOG(ERROR) << "Receive empty static request";
|
||||
return on_result(id, tonlib_api::make_object<tonlib_api::error>(400, "Request is empty"));
|
||||
}
|
||||
|
||||
if (is_static_request(function->get_id())) {
|
||||
return on_result(id, static_request(std::move(function)));
|
||||
}
|
||||
|
||||
if (state_ == State::Closed) {
|
||||
return on_result(id, tonlib_api::make_object<tonlib_api::error>(400, "tonlib is closed"));
|
||||
}
|
||||
if (state_ == State::Uninited) {
|
||||
if (!is_uninited_request(function->get_id())) {
|
||||
return on_result(id, tonlib_api::make_object<tonlib_api::error>(400, "library is not inited"));
|
||||
}
|
||||
}
|
||||
|
||||
downcast_call(*function, [this, self = this, id](auto& request) {
|
||||
using ReturnType = typename std::decay_t<decltype(request)>::ReturnType;
|
||||
td::Promise<ReturnType> promise = [actor_id = actor_id(self), id](td::Result<ReturnType> r_result) {
|
||||
tonlib_api::object_ptr<tonlib_api::Object> result;
|
||||
if (r_result.is_error()) {
|
||||
result = tonlib_api::make_object<tonlib_api::error>(r_result.error().code(), r_result.error().message().str());
|
||||
} else {
|
||||
result = r_result.move_as_ok();
|
||||
}
|
||||
|
||||
send_closure(actor_id, &TonlibClient::on_result, id, std::move(result));
|
||||
};
|
||||
auto status = this->do_request(request, std::move(promise));
|
||||
if (status.is_error()) {
|
||||
CHECK(promise);
|
||||
promise.set_error(std::move(status));
|
||||
}
|
||||
});
|
||||
}
|
||||
void TonlibClient::close() {
|
||||
stop();
|
||||
}
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::static_request(
|
||||
tonlib_api::object_ptr<tonlib_api::Function> function) {
|
||||
if (function == nullptr) {
|
||||
LOG(ERROR) << "Receive empty static request";
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, "Request is empty");
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::Object> response;
|
||||
downcast_call(*function, [&response](auto& request) { response = TonlibClient::do_static_request(request); });
|
||||
return response;
|
||||
}
|
||||
|
||||
bool TonlibClient::is_static_request(td::int32 id) {
|
||||
switch (id) {
|
||||
case tonlib_api::runTests::ID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool TonlibClient::is_uninited_request(td::int32 id) {
|
||||
switch (id) {
|
||||
case tonlib_api::init::ID:
|
||||
case tonlib_api::close::ID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::Object> TonlibClient::do_static_request(const tonlib_api::runTests& request) {
|
||||
auto& runner = td::TestsRunner::get_default();
|
||||
if (!request.dir_.empty()) {
|
||||
td::chdir(request.dir_).ignore();
|
||||
}
|
||||
runner.run_all();
|
||||
return tonlib_api::make_object<tonlib_api::ok>();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::init& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
if (state_ != State::Uninited) {
|
||||
return td::Status::Error(400, "Tonlib is already inited");
|
||||
}
|
||||
if (!request.options_) {
|
||||
return td::Status::Error(400, "Field options must not be empty");
|
||||
}
|
||||
TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_));
|
||||
if (!request.options_->config_.empty()) {
|
||||
TRY_STATUS(set_config(std::move(request.options_->config_)));
|
||||
}
|
||||
state_ = State::Running;
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::set_config(std::string config) {
|
||||
if (config.empty()) {
|
||||
return td::Status::Error("config is empty");
|
||||
}
|
||||
TRY_RESULT(new_config, Config::parse(std::move(config)));
|
||||
if (new_config.lite_clients.empty()) {
|
||||
return td::Status::Error("No lite clients in config");
|
||||
}
|
||||
config_ = std::move(new_config);
|
||||
init_ext_client();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::close& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
CHECK(state_ != State::Closed);
|
||||
state_ = State::Closed;
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Status TonlibClient::do_request(const tonlib_api::options_setConfig& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
TRY_STATUS(set_config(request.config_));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<block::StdAddress> get_account_address(const tonlib_api::raw_initialAccountState& raw_state) {
|
||||
TRY_RESULT(code, vm::std_boc_deserialize(raw_state.code_));
|
||||
TRY_RESULT(data, vm::std_boc_deserialize(raw_state.data_));
|
||||
return GenericAccount::get_address(0 /*zerochain*/, GenericAccount::get_init_state(std::move(code), std::move(data)));
|
||||
}
|
||||
|
||||
td::Result<block::StdAddress> get_account_address(const tonlib_api::testWallet_initialAccountState& test_wallet_state) {
|
||||
auto key = td::Ed25519::PublicKey(td::SecureString(test_wallet_state.public_key_));
|
||||
return GenericAccount::get_address(0 /*zerochain*/, TestWallet::get_init_state(key));
|
||||
}
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::internal_transactionId> to_transaction_id(const block::AccountState::Info& info) {
|
||||
return tonlib_api::make_object<tonlib_api::internal_transactionId>(info.last_trans_lt,
|
||||
info.last_trans_hash.as_slice().str());
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_accountState>> to_raw_accountState(RawAccountState&& raw_state) {
|
||||
std::string code;
|
||||
if (raw_state.code.not_null()) {
|
||||
code = vm::std_boc_serialize(vm::CellBuilder().append_cellslice(std::move(raw_state.code)).finalize())
|
||||
.move_as_ok()
|
||||
.as_slice()
|
||||
.str();
|
||||
}
|
||||
std::string data;
|
||||
if (raw_state.data.not_null()) {
|
||||
data = vm::std_boc_serialize(vm::CellBuilder().append_cellslice(std::move(raw_state.data)).finalize())
|
||||
.move_as_ok()
|
||||
.as_slice()
|
||||
.str();
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::raw_accountState>(raw_state.balance, std::move(code), std::move(data),
|
||||
to_transaction_id(raw_state.info));
|
||||
}
|
||||
|
||||
td::Result<std::string> to_std_address_or_throw(td::Ref<vm::CellSlice> cs) {
|
||||
auto tag = block::gen::MsgAddressInt().get_tag(*cs);
|
||||
if (tag < 0) {
|
||||
return td::Status::Error("Failed to read MsgAddressInt tag");
|
||||
}
|
||||
if (tag != block::gen::MsgAddressInt::addr_std) {
|
||||
return "";
|
||||
}
|
||||
block::gen::MsgAddressInt::Record_addr_std addr;
|
||||
if (!tlb::csr_unpack(cs, addr)) {
|
||||
return td::Status::Error("Failed to unpack MsgAddressInt");
|
||||
}
|
||||
return block::StdAddress(addr.workchain_id, addr.address).rserialize();
|
||||
}
|
||||
|
||||
td::Result<std::string> to_std_address(td::Ref<vm::CellSlice> cs) {
|
||||
return TRY_VM(to_std_address_or_throw(std::move(cs)));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_throw(td::Ref<vm::Cell> cell) {
|
||||
block::gen::Message::Record message;
|
||||
if (!tlb::type_unpack_cell(cell, block::gen::t_Message_Any, message)) {
|
||||
return td::Status::Error("Failed to unpack Message");
|
||||
}
|
||||
|
||||
auto tag = block::gen::CommonMsgInfo().get_tag(*message.info);
|
||||
if (tag < 0) {
|
||||
return td::Status::Error("Failed to read CommonMsgInfo tag");
|
||||
}
|
||||
switch (tag) {
|
||||
case block::gen::CommonMsgInfo::int_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_int_msg_info msg_info;
|
||||
if (!tlb::csr_unpack(message.info, msg_info)) {
|
||||
return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info");
|
||||
}
|
||||
TRY_RESULT(balance, to_balance(msg_info.value));
|
||||
TRY_RESULT(src, to_std_address(msg_info.src));
|
||||
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance);
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_in_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
|
||||
if (!tlb::csr_unpack(message.info, msg_info)) {
|
||||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
|
||||
}
|
||||
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0);
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_out_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
|
||||
if (!tlb::csr_unpack(message.info, msg_info)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return td::Status::Error("Unknown CommonMsgInfo tag");
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message(td::Ref<vm::Cell> cell) {
|
||||
return TRY_VM(to_raw_message_or_throw(std::move(cell)));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_transaction>> to_raw_transaction_or_throw(
|
||||
block::Transaction::Info&& info) {
|
||||
std::string data;
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::raw_message> in_msg;
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::raw_message>> out_msgs;
|
||||
td::int64 fees = 0;
|
||||
if (info.transaction.not_null()) {
|
||||
TRY_RESULT(copy_data, vm::std_boc_serialize(info.transaction));
|
||||
data = copy_data.as_slice().str();
|
||||
block::gen::Transaction::Record trans;
|
||||
if (!tlb::unpack_cell(info.transaction, trans)) {
|
||||
return td::Status::Error("Failed to unpack Transaction");
|
||||
}
|
||||
|
||||
TRY_RESULT(copy_fees, to_balance(trans.total_fees));
|
||||
fees = copy_fees;
|
||||
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Transaction.print_ref(outp, info.transaction);
|
||||
LOG(ERROR) << outp.str();
|
||||
|
||||
auto is_just = trans.r1.in_msg->prefetch_long(1);
|
||||
if (is_just == trans.r1.in_msg->fetch_long_eof) {
|
||||
return td::Status::Error("Failed to parse long");
|
||||
}
|
||||
if (is_just == 1) {
|
||||
auto msg = trans.r1.in_msg->prefetch_ref();
|
||||
TRY_RESULT(in_msg_copy, to_raw_message(trans.r1.in_msg->prefetch_ref()));
|
||||
in_msg = std::move(in_msg_copy);
|
||||
}
|
||||
|
||||
if (trans.outmsg_cnt != 0) {
|
||||
vm::Dictionary dict{trans.r1.out_msgs, 15};
|
||||
for (int x = 0; x < trans.outmsg_cnt && x < 100; x++) {
|
||||
TRY_RESULT(out_msg, to_raw_message(dict.lookup_ref(td::BitArray<15>{x})));
|
||||
out_msgs.push_back(std::move(out_msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::raw_transaction>(
|
||||
data,
|
||||
tonlib_api::make_object<tonlib_api::internal_transactionId>(info.prev_trans_lt,
|
||||
info.prev_trans_hash.as_slice().str()),
|
||||
fees, std::move(in_msg), std::move(out_msgs));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_transaction>> to_raw_transaction(block::Transaction::Info&& info) {
|
||||
return TRY_VM(to_raw_transaction_or_throw(std::move(info)));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_transactions>> to_raw_transactions(
|
||||
block::TransactionList::Info&& info) {
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::raw_transaction>> transactions;
|
||||
for (auto& transaction : info.transactions) {
|
||||
TRY_RESULT(raw_transaction, to_raw_transaction(std::move(transaction)));
|
||||
transactions.push_back(std::move(raw_transaction));
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::raw_transactions>(std::move(transactions));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::testWallet_accountState>> to_testWallet_accountState(
|
||||
RawAccountState&& raw_state) {
|
||||
if (raw_state.data.is_null()) {
|
||||
return td::Status::Error(400, "Not a TestWallet");
|
||||
}
|
||||
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::testWallet_accountState>(raw_state.balance, static_cast<td::uint32>(seqno),
|
||||
to_transaction_id(raw_state.info));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::testGiver_accountState>> to_testGiver_accountState(
|
||||
RawAccountState&& raw_state) {
|
||||
if (raw_state.data.is_null()) {
|
||||
return td::Status::Error(400, "Not a TestGiver");
|
||||
}
|
||||
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::testGiver_accountState>(raw_state.balance, static_cast<td::uint32>(seqno),
|
||||
to_transaction_id(raw_state.info));
|
||||
}
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> to_generic_accountState(
|
||||
RawAccountState&& raw_state) {
|
||||
if (raw_state.code.is_null()) {
|
||||
return tonlib_api::make_object<tonlib_api::generic_accountStateUninited>(
|
||||
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance));
|
||||
}
|
||||
|
||||
auto code_hash = raw_state.code->prefetch_ref()->get_hash();
|
||||
if (code_hash == TestWallet::get_init_code_hash()) {
|
||||
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 == 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));
|
||||
}
|
||||
TRY_RESULT(raw, to_raw_accountState(std::move(raw_state)));
|
||||
return tonlib_api::make_object<tonlib_api::generic_accountStateRaw>(std::move(raw));
|
||||
}
|
||||
|
||||
// Raw
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::raw_getAccountAddress& request,
|
||||
td::Promise<object_ptr<tonlib_api::accountAddress>>&& promise) {
|
||||
TRY_RESULT(account_address, get_account_address(*request.initital_account_state_));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::accountAddress>(account_address.rserialize()));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::raw_sendMessage& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
td::Ref<vm::Cell> init_state;
|
||||
if (!request.initial_account_state_.empty()) {
|
||||
TRY_RESULT(new_init_state, vm::std_boc_deserialize(request.initial_account_state_));
|
||||
init_state = std::move(new_init_state);
|
||||
}
|
||||
TRY_RESULT(data, vm::std_boc_deserialize(request.data_));
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||
auto message = GenericAccount::create_ext_message(account_address, std::move(init_state), std::move(data));
|
||||
client_.send_query(ton::lite_api::liteServer_sendMessage(vm::std_boc_serialize(message).move_as_ok()),
|
||||
[promise = std::move(promise)](auto r_info) mutable {
|
||||
if (r_info.is_error()) {
|
||||
promise.set_error(r_info.move_as_error());
|
||||
} else {
|
||||
auto info = r_info.move_as_ok();
|
||||
LOG(ERROR) << "info: " << to_string(info);
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
}
|
||||
});
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::raw_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::raw_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_raw_accountState(r_state.move_as_ok()));
|
||||
})
|
||||
.release();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request,
|
||||
td::Promise<object_ptr<tonlib_api::raw_transactions>>&& promise) {
|
||||
if (!request.account_address_) {
|
||||
return td::Status::Error(400, "Field account_address must not be empty");
|
||||
}
|
||||
if (!request.from_transaction_id_) {
|
||||
return td::Status::Error(400, "Field from_transaction_id must not be empty");
|
||||
}
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.account_address_->account_address_));
|
||||
auto lt = request.from_transaction_id_->lt_;
|
||||
auto hash_str = request.from_transaction_id_->hash_;
|
||||
if (hash_str.size() != 32) {
|
||||
return td::Status::Error(400, "Invalid transaction id hash size");
|
||||
}
|
||||
td::Bits256 hash;
|
||||
hash.as_slice().copy_from(hash_str);
|
||||
|
||||
td::actor::create_actor<GetTransactionHistory>(
|
||||
"GetTransactionHistory", client_.get_client(), account_address, lt, hash,
|
||||
[promise = std::move(promise)](td::Result<block::TransactionList::Info> r_info) mutable {
|
||||
if (r_info.is_error()) {
|
||||
return promise.set_error(r_info.move_as_error());
|
||||
}
|
||||
promise.set_result(to_raw_transactions(r_info.move_as_ok()));
|
||||
})
|
||||
.release();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::testGiver_getAccountAddress& request,
|
||||
td::Promise<object_ptr<tonlib_api::accountAddress>>&& promise) {
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize()));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::InputKey> from_tonlib(tonlib_api::inputKey& input_key) {
|
||||
if (!input_key.key_) {
|
||||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
|
||||
return KeyStorage::InputKey{{td::SecureString(input_key.key_->public_key_), std::move(input_key.key_->secret_)},
|
||||
std::move(input_key.local_password_)};
|
||||
}
|
||||
|
||||
// TestWallet
|
||||
td::Status TonlibClient::do_request(const tonlib_api::testWallet_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 = TestWallet::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 = TestWallet::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::testWallet_getAccountAddress& request,
|
||||
td::Promise<object_ptr<tonlib_api::accountAddress>>&& promise) {
|
||||
TRY_RESULT(account_address, get_account_address(*request.initital_account_state_));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::accountAddress>(account_address.rserialize()));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::testWallet_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");
|
||||
}
|
||||
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*/, TestWallet::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(TestWallet::make_a_gift_message(
|
||||
td::Ed25519::PrivateKey(std::move(private_key.private_key)),
|
||||
request.seqno_, request.amount_, account_address))
|
||||
.move_as_ok()
|
||||
.as_slice()
|
||||
.str()),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::testWallet_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_testWallet_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");
|
||||
}
|
||||
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||
account_address.bounceable = false;
|
||||
return do_request(
|
||||
tonlib_api::raw_sendMessage(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize()), "",
|
||||
vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, account_address))
|
||||
.move_as_ok()
|
||||
.as_slice()
|
||||
.str()),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::testGiver_accountState>>&& promise) {
|
||||
td::actor::create_actor<GetRawAccountState>(
|
||||
"GetAccountState", client_.get_client(), TestGiver::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_testGiver_accountState(r_state.move_as_ok()));
|
||||
})
|
||||
.release();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::generic_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::generic_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_generic_accountState(r_state.move_as_ok()));
|
||||
})
|
||||
.release();
|
||||
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_));
|
||||
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_](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)]() mutable {
|
||||
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)]() 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();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::createNewKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
|
||||
TRY_RESULT(key,
|
||||
key_storage_.create_new_key(std::move(request.local_password_), std::move(request.mnemonic_password_)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::exportKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedKey>>&& promise) {
|
||||
if (!request.input_key_) {
|
||||
return td::Status::Error(400, "Field input_key must not be empty");
|
||||
}
|
||||
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
|
||||
TRY_RESULT(exported_key, key_storage_.export_key(std::move(input_key)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::exportedKey>(std::move(exported_key.mnemonic_words)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::deleteKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
TRY_STATUS(key_storage_.delete_key(request.public_key_));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::importKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
|
||||
if (!request.exported_key_) {
|
||||
return td::Status::Error(400, "Field exported_key must not be empty");
|
||||
}
|
||||
TRY_RESULT(key, key_storage_.import_key(std::move(request.local_password_), std::move(request.mnemonic_password_),
|
||||
KeyStorage::ExportedKey{std::move(request.exported_key_->word_list_)}));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::exportPemKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedPemKey>>&& promise) {
|
||||
if (!request.input_key_) {
|
||||
return td::Status::Error(400, "Field input_key must not be empty");
|
||||
}
|
||||
if (!request.input_key_->key_) {
|
||||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
|
||||
KeyStorage::InputKey input_key{
|
||||
{td::SecureString(request.input_key_->key_->public_key_), std::move(request.input_key_->key_->secret_)},
|
||||
std::move(request.input_key_->local_password_)};
|
||||
TRY_RESULT(exported_pem_key, key_storage_.export_pem_key(std::move(input_key), std::move(request.key_password_)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::exportedPemKey>(std::move(exported_pem_key.pem)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::importPemKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
|
||||
if (!request.exported_key_) {
|
||||
return td::Status::Error(400, "Field exported_key must not be empty");
|
||||
}
|
||||
TRY_RESULT(key, key_storage_.import_pem_key(std::move(request.local_password_), std::move(request.key_password_),
|
||||
KeyStorage::ExportedPemKey{std::move(request.exported_key_->pem_)}));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::exportEncryptedKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedEncryptedKey>>&& promise) {
|
||||
if (!request.input_key_) {
|
||||
return td::Status::Error(400, "Field input_key must not be empty");
|
||||
}
|
||||
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
|
||||
TRY_RESULT(exported_key, key_storage_.export_encrypted_key(std::move(input_key), request.key_password_));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::exportedEncryptedKey>(std::move(exported_key.data)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::importEncryptedKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
|
||||
if (!request.exported_encrypted_key_) {
|
||||
return td::Status::Error(400, "Field exported_encrypted_key must not be empty");
|
||||
}
|
||||
TRY_RESULT(key, key_storage_.import_encrypted_key(
|
||||
std::move(request.local_password_), std::move(request.key_password_),
|
||||
KeyStorage::ExportedEncryptedKey{std::move(request.exported_encrypted_key_->data_)}));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
|
||||
if (!request.input_key_) {
|
||||
return td::Status::Error(400, "Field input_key must not be empty");
|
||||
}
|
||||
if (!request.input_key_->key_) {
|
||||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
KeyStorage::InputKey input_key{
|
||||
{td::SecureString(request.input_key_->key_->public_key_), std::move(request.input_key_->key_->secret_)},
|
||||
std::move(request.input_key_->local_password_)};
|
||||
TRY_RESULT(key, key_storage_.change_local_password(std::move(input_key), std::move(request.new_local_password_)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
} // namespace tonlib
|
136
tonlib/tonlib/TonlibClient.h
Normal file
136
tonlib/tonlib/TonlibClient.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
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 "TonlibCallback.h"
|
||||
|
||||
#include "tonlib/Config.h"
|
||||
#include "tonlib/ExtClient.h"
|
||||
#include "tonlib/KeyStorage.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
namespace tonlib {
|
||||
class TonlibClient : public td::actor::Actor {
|
||||
public:
|
||||
template <class T>
|
||||
using object_ptr = tonlib_api::object_ptr<T>;
|
||||
|
||||
explicit TonlibClient(td::unique_ptr<TonlibCallback> callback);
|
||||
void request(td::uint64 id, object_ptr<tonlib_api::Function> function);
|
||||
void close();
|
||||
static object_ptr<tonlib_api::Object> static_request(object_ptr<tonlib_api::Function> function);
|
||||
|
||||
~TonlibClient();
|
||||
|
||||
private:
|
||||
enum class State { Uninited, Running, Closed } state_ = State::Uninited;
|
||||
td::unique_ptr<TonlibCallback> callback_;
|
||||
Config config_;
|
||||
|
||||
// KeyStorage
|
||||
KeyStorage key_storage_;
|
||||
|
||||
// network
|
||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
|
||||
td::actor::ActorOwn<LastBlock> raw_last_block_;
|
||||
ExtClient client_;
|
||||
|
||||
ExtClientRef get_client_ref();
|
||||
void init_ext_client();
|
||||
|
||||
bool is_closing_{false};
|
||||
td::uint32 ref_cnt_{1};
|
||||
void hangup_shared() override {
|
||||
ref_cnt_--;
|
||||
try_stop();
|
||||
}
|
||||
void hangup() override;
|
||||
void try_stop() {
|
||||
if (is_closing_ && ref_cnt_ == 0) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void on_result(td::uint64 id, object_ptr<tonlib_api::Object> response);
|
||||
static bool is_static_request(td::int32 id);
|
||||
static bool is_uninited_request(td::int32 id);
|
||||
template <class T>
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const T& request) {
|
||||
return tonlib_api::make_object<tonlib_api::error>(400, "Function can't be executed synchronously");
|
||||
}
|
||||
static object_ptr<tonlib_api::Object> do_static_request(const tonlib_api::runTests& request);
|
||||
template <class T, class P>
|
||||
td::Status do_request(const T& request, P&& promise) {
|
||||
return td::Status::Error(400, "Function is unsupported");
|
||||
}
|
||||
|
||||
td::Status set_config(std::string config);
|
||||
|
||||
td::Status do_request(const tonlib_api::init& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(const tonlib_api::close& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(const tonlib_api::options_setConfig& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::raw_getAccountAddress& request,
|
||||
td::Promise<object_ptr<tonlib_api::accountAddress>>&& promise);
|
||||
td::Status do_request(const tonlib_api::raw_sendMessage& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(tonlib_api::raw_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::raw_accountState>>&& promise);
|
||||
td::Status do_request(tonlib_api::raw_getTransactions& request,
|
||||
td::Promise<object_ptr<tonlib_api::raw_transactions>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::testWallet_init& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(const tonlib_api::testWallet_getAccountAddress& request,
|
||||
td::Promise<object_ptr<tonlib_api::accountAddress>>&& promise);
|
||||
td::Status do_request(const tonlib_api::testWallet_sendGrams& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
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::testGiver_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::testGiver_accountState>>&& promise);
|
||||
td::Status do_request(tonlib_api::testGiver_getAccountAddress& request,
|
||||
td::Promise<object_ptr<tonlib_api::accountAddress>>&& promise);
|
||||
td::Status do_request(const tonlib_api::testGiver_sendGrams& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::generic_getAccountState& request,
|
||||
td::Promise<object_ptr<tonlib_api::generic_AccountState>>&& promise);
|
||||
td::Status do_request(tonlib_api::generic_sendGrams& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::createNewKey& request, td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||
td::Status do_request(const tonlib_api::exportKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedKey>>&& promise);
|
||||
td::Status do_request(const tonlib_api::deleteKey& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
td::Status do_request(const tonlib_api::importKey& request, td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::exportPemKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedPemKey>>&& promise);
|
||||
td::Status do_request(const tonlib_api::importPemKey& request, td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::exportEncryptedKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedEncryptedKey>>&& promise);
|
||||
td::Status do_request(const tonlib_api::importEncryptedKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::changeLocalPassword& request,
|
||||
td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||
};
|
||||
} // namespace tonlib
|
81
tonlib/tonlib/keys/DecryptedKey.cpp
Normal file
81
tonlib/tonlib/keys/DecryptedKey.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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 "DecryptedKey.h"
|
||||
|
||||
#include "tonlib/keys/EncryptedKey.h"
|
||||
#include "tonlib/keys/SimpleEncryption.h"
|
||||
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
namespace tonlib {
|
||||
DecryptedKey::DecryptedKey(const Mnemonic &mnemonic)
|
||||
: mnemonic_words(mnemonic.get_words()), private_key(mnemonic.to_private_key()) {
|
||||
}
|
||||
DecryptedKey::DecryptedKey(std::vector<td::SecureString> mnemonic_words, td::Ed25519::PrivateKey key)
|
||||
: mnemonic_words(std::move(mnemonic_words)), private_key(std::move(key)) {
|
||||
}
|
||||
DecryptedKey::DecryptedKey(RawDecryptedKey key)
|
||||
: DecryptedKey(std::move(key.mnemonic_words), td::Ed25519::PrivateKey(key.private_key.copy())) {
|
||||
}
|
||||
|
||||
td::SecureString DecryptedKey::change_local_password(td::Slice secret_str, td::Slice old_local_password,
|
||||
td::Slice new_local_password) {
|
||||
CHECK(secret_str.size() == 32);
|
||||
td::SecureString old_local_password_hash(32);
|
||||
sha256(old_local_password, old_local_password_hash.as_mutable_slice());
|
||||
td::SecureString new_local_password_hash(32);
|
||||
sha256(new_local_password, new_local_password_hash.as_mutable_slice());
|
||||
|
||||
td::SecureString new_secret(32);
|
||||
for (size_t i = 0; i < new_secret.size(); i++) {
|
||||
new_secret.as_mutable_slice()[i] =
|
||||
secret_str[i] ^ old_local_password_hash.as_slice()[i] ^ new_local_password_hash.as_slice()[i];
|
||||
}
|
||||
return new_secret;
|
||||
}
|
||||
|
||||
EncryptedKey DecryptedKey::encrypt(td::Slice local_password, td::Slice old_secret) const {
|
||||
LOG(ERROR) << "encrypt";
|
||||
td::SecureString secret(32);
|
||||
if (old_secret.size() == td::as_slice(secret).size()) {
|
||||
secret.as_mutable_slice().copy_from(old_secret);
|
||||
} else {
|
||||
td::Random::secure_bytes(secret.as_mutable_slice());
|
||||
}
|
||||
td::SecureString local_password_hash(32);
|
||||
sha256(local_password, local_password_hash.as_mutable_slice());
|
||||
td::SecureString decrypted_secret(32);
|
||||
for (size_t i = 0; i < decrypted_secret.size(); i++) {
|
||||
decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i];
|
||||
}
|
||||
|
||||
td::SecureString encryption_secret(64);
|
||||
pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", PBKDF_ITERATIONS, encryption_secret.as_mutable_slice());
|
||||
|
||||
std::vector<td::SecureString> mnemonic_words_copy;
|
||||
for (auto &w : mnemonic_words) {
|
||||
mnemonic_words_copy.push_back(w.copy());
|
||||
}
|
||||
auto data = td::serialize_secure(RawDecryptedKey{std::move(mnemonic_words_copy), private_key.as_octet_string()});
|
||||
auto encrypted_data = SimpleEncryption::encrypt_data(data, as_slice(encryption_secret));
|
||||
|
||||
return EncryptedKey{std::move(encrypted_data), private_key.get_public_key().move_as_ok(), std::move(secret)};
|
||||
}
|
||||
} // namespace tonlib
|
64
tonlib/tonlib/keys/DecryptedKey.h
Normal file
64
tonlib/tonlib/keys/DecryptedKey.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 <vector>
|
||||
#include <string>
|
||||
|
||||
#include "td/utils/tl_helpers.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
|
||||
#include "tonlib/keys/Mnemonic.h"
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
struct RawDecryptedKey {
|
||||
std::vector<td::SecureString> mnemonic_words;
|
||||
td::SecureString private_key;
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const {
|
||||
using td::store;
|
||||
store(mnemonic_words, storer);
|
||||
store(private_key, storer);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser) {
|
||||
using td::parse;
|
||||
parse(mnemonic_words, parser);
|
||||
parse(private_key, parser);
|
||||
}
|
||||
};
|
||||
|
||||
struct EncryptedKey;
|
||||
struct DecryptedKey {
|
||||
DecryptedKey() = default;
|
||||
explicit DecryptedKey(const Mnemonic &mnemonic);
|
||||
DecryptedKey(std::vector<td::SecureString> mnemonic_words, td::Ed25519::PrivateKey key);
|
||||
DecryptedKey(RawDecryptedKey key);
|
||||
|
||||
std::vector<td::SecureString> mnemonic_words;
|
||||
td::Ed25519::PrivateKey private_key;
|
||||
|
||||
static td::SecureString change_local_password(td::Slice secret, td::Slice old_local_password,
|
||||
td::Slice new_local_password);
|
||||
EncryptedKey encrypt(td::Slice local_password, td::Slice secret = {}) const;
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
53
tonlib/tonlib/keys/EncryptedKey.cpp
Normal file
53
tonlib/tonlib/keys/EncryptedKey.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
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 "EncryptedKey.h"
|
||||
|
||||
#include "tonlib/keys/DecryptedKey.h"
|
||||
#include "tonlib/keys/SimpleEncryption.h"
|
||||
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::Result<DecryptedKey> EncryptedKey::decrypt(td::Slice local_password, bool check_public_key) {
|
||||
LOG(ERROR) << "decrypt";
|
||||
if (secret.size() != 32) {
|
||||
return td::Status::Error("Failed to decrypt key: invalid secret size");
|
||||
}
|
||||
td::SecureString local_password_hash(32);
|
||||
sha256(local_password, local_password_hash.as_mutable_slice());
|
||||
td::SecureString decrypted_secret(32);
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i];
|
||||
}
|
||||
|
||||
td::SecureString encryption_secret(64);
|
||||
pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", PBKDF_ITERATIONS, encryption_secret.as_mutable_slice());
|
||||
TRY_RESULT(decrypted_data, SimpleEncryption::decrypt_data(as_slice(encrypted_data), as_slice(encryption_secret)));
|
||||
|
||||
RawDecryptedKey raw_decrypted_key;
|
||||
TRY_STATUS(td::unserialize(raw_decrypted_key, decrypted_data));
|
||||
DecryptedKey res(std::move(raw_decrypted_key));
|
||||
TRY_RESULT(got_public_key, res.private_key.get_public_key());
|
||||
if (check_public_key &&
|
||||
got_public_key.as_octet_string().as_slice() != this->public_key.as_octet_string().as_slice()) {
|
||||
return td::Status::Error("Something wrong: public key of decrypted private key differs from requested public key");
|
||||
}
|
||||
return std::move(res);
|
||||
}
|
||||
} // namespace tonlib
|
38
tonlib/tonlib/keys/EncryptedKey.h
Normal file
38
tonlib/tonlib/keys/EncryptedKey.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 "td/utils/Status.h"
|
||||
|
||||
#include "crypto/Ed25519.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tonlib {
|
||||
constexpr int PBKDF_ITERATIONS = 100000;
|
||||
struct DecryptedKey;
|
||||
struct EncryptedKey {
|
||||
td::SecureString encrypted_data;
|
||||
td::Ed25519::PublicKey public_key;
|
||||
td::SecureString secret;
|
||||
|
||||
td::Result<DecryptedKey> decrypt(td::Slice local_password, bool check_public_key = true);
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
188
tonlib/tonlib/keys/Mnemonic.cpp
Normal file
188
tonlib/tonlib/keys/Mnemonic.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
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 "Mnemonic.h"
|
||||
|
||||
#include "tonlib/keys/bip39.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Span.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/optional.h"
|
||||
|
||||
#include "crypto/Ed25519.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::Result<Mnemonic> Mnemonic::create(td::SecureString words, td::SecureString password) {
|
||||
return create_from_normalized(normalize_and_split(std::move(words)), std::move(password));
|
||||
}
|
||||
td::Result<Mnemonic> Mnemonic::create(std::vector<td::SecureString> words, td::SecureString password) {
|
||||
return create(join(words), std::move(password));
|
||||
}
|
||||
td::Result<Mnemonic> Mnemonic::create_from_normalized(std::vector<td::SecureString> words, td::SecureString password) {
|
||||
auto new_words = normalize_and_split(join(words));
|
||||
if (new_words != words) {
|
||||
return td::Status::Error("Mnemonic string is not normalized");
|
||||
}
|
||||
return Mnemonic(std::move(words), std::move(password));
|
||||
}
|
||||
|
||||
td::SecureString Mnemonic::to_entropy() const {
|
||||
td::SecureString res(64);
|
||||
td::hmac_sha512(join(words_), password_, res.as_mutable_slice());
|
||||
return res;
|
||||
}
|
||||
|
||||
td::SecureString Mnemonic::to_seed() const {
|
||||
td::SecureString hash(64);
|
||||
td::pbkdf2_sha512(as_slice(to_entropy()), "TON default seed", PBKDF_ITERATIONS, hash.as_mutable_slice());
|
||||
return hash;
|
||||
}
|
||||
|
||||
td::Ed25519::PrivateKey Mnemonic::to_private_key() const {
|
||||
return td::Ed25519::PrivateKey(td::SecureString(as_slice(to_seed()).substr(0, td::Ed25519::PrivateKey::LENGTH)));
|
||||
}
|
||||
|
||||
bool Mnemonic::is_basic_seed() {
|
||||
td::SecureString hash(64);
|
||||
td::pbkdf2_sha512(as_slice(to_entropy()), "TON seed version", td::max(1, PBKDF_ITERATIONS / 256),
|
||||
hash.as_mutable_slice());
|
||||
return hash.as_slice()[0] == 0;
|
||||
}
|
||||
|
||||
bool Mnemonic::is_password_seed() {
|
||||
td::SecureString hash(64);
|
||||
td::pbkdf2_sha512(as_slice(to_entropy()), "TON fast seed version", 1, hash.as_mutable_slice());
|
||||
return hash.as_slice()[0] == 1;
|
||||
}
|
||||
|
||||
std::vector<td::SecureString> Mnemonic::get_words() const {
|
||||
std::vector<td::SecureString> res;
|
||||
for (auto &word : words_) {
|
||||
res.push_back(word.copy());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<td::SecureString> Mnemonic::normalize_and_split(td::SecureString words) {
|
||||
for (auto &c : words.as_mutable_slice()) {
|
||||
if (td::is_alpha(c)) {
|
||||
c = td::to_lower(c);
|
||||
} else {
|
||||
c = ' ';
|
||||
}
|
||||
}
|
||||
auto vec = td::full_split(words.as_slice(), ' ');
|
||||
std::vector<td::SecureString> res;
|
||||
for (auto &s : vec) {
|
||||
if (!s.empty()) {
|
||||
res.push_back(td::SecureString(s));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
td::StringBuilder &operator<<(td::StringBuilder &sb, const Mnemonic &mnemonic) {
|
||||
sb << "Mnemonic" << td::format::as_array(mnemonic.words_);
|
||||
if (!mnemonic.password_.empty()) {
|
||||
sb << " with password[" << mnemonic.password_ << "]";
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
Mnemonic::Mnemonic(std::vector<td::SecureString> words, td::SecureString password)
|
||||
: words_(std::move(words)), password_(std::move(password)) {
|
||||
}
|
||||
td::SecureString Mnemonic::join(td::Span<td::SecureString> words) {
|
||||
size_t res_size = 0;
|
||||
for (size_t i = 0; i < words.size(); i++) {
|
||||
if (i != 0) {
|
||||
res_size++;
|
||||
}
|
||||
res_size += words[i].size();
|
||||
}
|
||||
td::SecureString res(res_size);
|
||||
auto dst = res.as_mutable_slice();
|
||||
for (size_t i = 0; i < words.size(); i++) {
|
||||
if (i != 0) {
|
||||
dst[0] = ' ';
|
||||
dst.remove_prefix(1);
|
||||
}
|
||||
dst.copy_from(words[i].as_slice());
|
||||
dst.remove_prefix(words[i].size());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Result<Mnemonic> Mnemonic::create_new(Options options) {
|
||||
if (options.words_count == 0) {
|
||||
options.words_count = 24;
|
||||
}
|
||||
if (options.words_count < 8 || options.words_count > 48) {
|
||||
return td::Status::Error(PSLICE() << "Invalid words count(" << options.words_count
|
||||
<< ") requested for mnemonic creation");
|
||||
}
|
||||
td::int32 max_iterations = 256 * 20;
|
||||
if (!options.password.empty()) {
|
||||
max_iterations *= 256;
|
||||
}
|
||||
|
||||
auto bip_words = Mnemonic::normalize_and_split(td::SecureString(bip39_english()));
|
||||
CHECK(bip_words.size() == 2048);
|
||||
|
||||
int A = 0, B = 0, C = 0;
|
||||
for (int iteration = 0; iteration < max_iterations; iteration++) {
|
||||
std::vector<td::SecureString> words;
|
||||
for (int i = 0; i < options.words_count; i++) {
|
||||
words.push_back(bip_words[td::Random::secure_int32() & 2047].copy());
|
||||
}
|
||||
|
||||
bool has_password = !options.password.empty();
|
||||
|
||||
td::optional<Mnemonic> mnemonic_without_password;
|
||||
if (has_password) {
|
||||
auto copy_words = td::transform(words, [](auto &w) { return w.copy(); });
|
||||
mnemonic_without_password = Mnemonic::create(std::move(copy_words), {}).move_as_ok();
|
||||
if (!mnemonic_without_password.value().is_password_seed()) {
|
||||
A++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto mnemonic = Mnemonic::create(std::move(words), options.password.copy()).move_as_ok();
|
||||
|
||||
if (!mnemonic.is_basic_seed()) {
|
||||
B++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (has_password && mnemonic_without_password.value().is_basic_seed()) {
|
||||
C++;
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Mnemonic generation debug stats: " << A << " " << B << " " << C;
|
||||
return std::move(mnemonic);
|
||||
}
|
||||
return td::Status::Error("Failed to create a mnemonic (should not happen)");
|
||||
}
|
||||
} // namespace tonlib
|
65
tonlib/tonlib/keys/Mnemonic.h
Normal file
65
tonlib/tonlib/keys/Mnemonic.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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 "crypto/Ed25519.h"
|
||||
|
||||
#include "td/utils/int_types.h"
|
||||
#include "td/utils/Span.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/UInt.h"
|
||||
|
||||
namespace tonlib {
|
||||
class Mnemonic {
|
||||
public:
|
||||
static constexpr int PBKDF_ITERATIONS = 100000;
|
||||
static td::Result<Mnemonic> create(td::SecureString words, td::SecureString password);
|
||||
static td::Result<Mnemonic> create(std::vector<td::SecureString> words, td::SecureString password);
|
||||
struct Options {
|
||||
Options() {
|
||||
}
|
||||
int words_count = 24;
|
||||
td::SecureString password;
|
||||
};
|
||||
static td::Result<Mnemonic> create_new(Options options = {});
|
||||
|
||||
td::SecureString to_entropy() const;
|
||||
|
||||
td::SecureString to_seed() const;
|
||||
|
||||
td::Ed25519::PrivateKey to_private_key() const;
|
||||
|
||||
bool is_basic_seed();
|
||||
bool is_password_seed();
|
||||
|
||||
std::vector<td::SecureString> get_words() const;
|
||||
|
||||
static std::vector<td::SecureString> normalize_and_split(td::SecureString words);
|
||||
|
||||
private:
|
||||
std::vector<td::SecureString> words_;
|
||||
td::SecureString password_;
|
||||
|
||||
Mnemonic(std::vector<td::SecureString> words, td::SecureString password);
|
||||
static td::SecureString join(td::Span<td::SecureString> words);
|
||||
static td::Result<Mnemonic> create_from_normalized(std::vector<td::SecureString> words, td::SecureString password);
|
||||
friend td::StringBuilder &operator<<(td::StringBuilder &sb, const Mnemonic &mnemonic);
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
101
tonlib/tonlib/keys/SimpleEncryption.cpp
Normal file
101
tonlib/tonlib/keys/SimpleEncryption.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
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 "SimpleEncryption.h"
|
||||
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::AesCbcState SimpleEncryption::calc_aes_cbc_state_hash(td::Slice hash) {
|
||||
CHECK(hash.size() == 64);
|
||||
td::SecureString key(32);
|
||||
key.as_mutable_slice().copy_from(hash.substr(0, 32));
|
||||
td::SecureString iv(16);
|
||||
iv.as_mutable_slice().copy_from(hash.substr(32, 16));
|
||||
return td::AesCbcState{key, iv};
|
||||
}
|
||||
|
||||
td::AesCbcState SimpleEncryption::calc_aes_cbc_state_sha512(td::Slice seed) {
|
||||
td::SecureString hash(64);
|
||||
sha512(seed, hash.as_mutable_slice());
|
||||
return calc_aes_cbc_state_hash(hash.as_slice());
|
||||
}
|
||||
td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size) {
|
||||
td::SecureString buff(td::narrow_cast<size_t>(((32 + 15 + data_size) & -16) - data_size), 0);
|
||||
td::Random::secure_bytes(buff.as_mutable_slice());
|
||||
buff.as_mutable_slice()[0] = td::narrow_cast<td::uint8>(buff.size());
|
||||
CHECK((buff.size() + data_size) % 16 == 0);
|
||||
return buff;
|
||||
}
|
||||
|
||||
td::SecureString SimpleEncryption::combine_secrets(td::Slice a, td::Slice b) {
|
||||
td::SecureString res(64, 0);
|
||||
hmac_sha512(a, b, res.as_mutable_slice());
|
||||
return res;
|
||||
}
|
||||
|
||||
td::SecureString SimpleEncryption::encrypt_data_with_prefix(td::Slice data, td::Slice secret) {
|
||||
CHECK(data.size() % 16 == 0);
|
||||
auto data_hash = sha256(data);
|
||||
|
||||
td::SecureString res_buf(data.size() + 32, 0);
|
||||
auto res = res_buf.as_mutable_slice();
|
||||
res.copy_from(data_hash);
|
||||
|
||||
auto cbc_state = calc_aes_cbc_state_hash(combine_secrets(data_hash, secret));
|
||||
cbc_state.encrypt(data, res.substr(32));
|
||||
|
||||
return res_buf;
|
||||
}
|
||||
|
||||
td::SecureString SimpleEncryption::encrypt_data(td::Slice data, td::Slice secret) {
|
||||
auto prefix = gen_random_prefix(data.size());
|
||||
td::SecureString combined(prefix.size() + data.size());
|
||||
combined.as_mutable_slice().copy_from(prefix);
|
||||
combined.as_mutable_slice().substr(prefix.size()).copy_from(data);
|
||||
return encrypt_data_with_prefix(combined.as_slice(), secret);
|
||||
}
|
||||
|
||||
td::Result<td::SecureString> SimpleEncryption::decrypt_data(td::Slice encrypted_data, td::Slice secret) {
|
||||
if (encrypted_data.size() < 33) {
|
||||
return td::Status::Error("Failed to decrypt: data is too small");
|
||||
}
|
||||
if (encrypted_data.size() % 16 != 0) {
|
||||
return td::Status::Error("Failed to decrypt: data size is not divisible by 32");
|
||||
}
|
||||
auto data_hash = encrypted_data.substr(0, 32);
|
||||
encrypted_data = encrypted_data.substr(32);
|
||||
|
||||
auto cbc_state = calc_aes_cbc_state_hash(combine_secrets(data_hash, secret));
|
||||
td::SecureString decrypted_data(encrypted_data.size(), 0);
|
||||
cbc_state.decrypt(encrypted_data, decrypted_data.as_mutable_slice());
|
||||
|
||||
// check hash
|
||||
if (data_hash != td::sha256(decrypted_data)) {
|
||||
return td::Status::Error("Failed to decrypt: hash mismatch");
|
||||
}
|
||||
|
||||
td::uint8 prefix_size = static_cast<td::uint8>(decrypted_data[0]);
|
||||
if (prefix_size > decrypted_data.size() || prefix_size < 32) {
|
||||
return td::Status::Error("Failed to decrypt: invalid prefix size");
|
||||
}
|
||||
|
||||
return td::SecureString(decrypted_data.as_slice().substr(prefix_size));
|
||||
}
|
||||
} // namespace tonlib
|
39
tonlib/tonlib/keys/SimpleEncryption.h
Normal file
39
tonlib/tonlib/keys/SimpleEncryption.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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 "td/utils/crypto.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
|
||||
namespace tonlib {
|
||||
class SimpleEncryption {
|
||||
public:
|
||||
static td::SecureString encrypt_data(td::Slice data, td::Slice secret);
|
||||
static td::Result<td::SecureString> decrypt_data(td::Slice encrypted_data, td::Slice secret);
|
||||
|
||||
private:
|
||||
static td::AesCbcState calc_aes_cbc_state_hash(td::Slice hash);
|
||||
static td::AesCbcState calc_aes_cbc_state_sha512(td::Slice seed);
|
||||
static td::SecureString gen_random_prefix(td::int64 data_size);
|
||||
|
||||
static td::SecureString combine_secrets(td::Slice a, td::Slice b);
|
||||
static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret);
|
||||
};
|
||||
} // namespace tonlib
|
2072
tonlib/tonlib/keys/bip39.cpp
Normal file
2072
tonlib/tonlib/keys/bip39.cpp
Normal file
File diff suppressed because it is too large
Load diff
24
tonlib/tonlib/keys/bip39.h
Normal file
24
tonlib/tonlib/keys/bip39.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
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 "td/utils/Slice.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::CSlice bip39_english();
|
||||
}
|
57
tonlib/tonlib/tonlib_client_json.cpp
Normal file
57
tonlib/tonlib/tonlib_client_json.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
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/tonlib_client_json.h"
|
||||
|
||||
#include "tonlib/ClientJson.h"
|
||||
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
extern "C" int tonlib_client_json_square(int x, const char *str) {
|
||||
return x * x;
|
||||
}
|
||||
|
||||
void *tonlib_client_json_create() {
|
||||
return new tonlib::ClientJson();
|
||||
}
|
||||
|
||||
void tonlib_client_json_destroy(void *client) {
|
||||
delete static_cast<tonlib::ClientJson *>(client);
|
||||
}
|
||||
|
||||
void tonlib_client_json_send(void *client, const char *request) {
|
||||
static_cast<tonlib::ClientJson *>(client)->send(td::Slice(request == nullptr ? "" : request));
|
||||
}
|
||||
|
||||
const char *tonlib_client_json_receive(void *client, double timeout) {
|
||||
auto slice = static_cast<tonlib::ClientJson *>(client)->receive(timeout);
|
||||
if (slice.empty()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return slice.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
const char *tonlib_client_json_execute(void *client, const char *request) {
|
||||
auto slice = tonlib::ClientJson::execute(td::Slice(request == nullptr ? "" : request));
|
||||
if (slice.empty()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return slice.c_str();
|
||||
}
|
||||
}
|
39
tonlib/tonlib/tonlib_client_json.h
Normal file
39
tonlib/tonlib/tonlib_client_json.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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/tonlibjson_export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
TONLIBJSON_EXPORT void *tonlib_client_json_create();
|
||||
|
||||
TONLIBJSON_EXPORT void tonlib_client_json_send(void *client, const char *request);
|
||||
|
||||
TONLIBJSON_EXPORT const char *tonlib_client_json_receive(void *client, double timeout);
|
||||
|
||||
TONLIBJSON_EXPORT const char *tonlib_client_json_execute(void *client, const char *request);
|
||||
|
||||
TONLIBJSON_EXPORT void tonlib_client_json_destroy(void *client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
35
tonlib/tonlib/utils.cpp
Normal file
35
tonlib/tonlib/utils.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
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/utils.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "vm/cellslice.h"
|
||||
namespace tonlib {
|
||||
td::Result<td::Ref<vm::CellSlice>> binary_bitstring_to_cellslice(td::Slice literal) {
|
||||
unsigned char buff[128];
|
||||
if (!begins_with(literal, "b{") || !ends_with(literal, "}")) {
|
||||
return td::Status::Error("Invalid binary bitstring constant");
|
||||
}
|
||||
int bits =
|
||||
(int)td::bitstring::parse_bitstring_binary_literal(buff, sizeof(buff), literal.begin() + 2, literal.end() - 1);
|
||||
if (bits < 0) {
|
||||
return td::Status::Error("Invalid binary bitstring constant");
|
||||
}
|
||||
return td::Ref<vm::CellSlice>{true, vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize()};
|
||||
}
|
||||
} // namespace tonlib
|
26
tonlib/tonlib/utils.h
Normal file
26
tonlib/tonlib/utils.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
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 "ton/ton-types.h"
|
||||
#include "block/block.h"
|
||||
#include "block/block-parse.h"
|
||||
namespace tonlib {
|
||||
td::Result<td::Ref<vm::CellSlice>> binary_bitstring_to_cellslice(td::Slice literal);
|
||||
} // namespace tonlib
|
5
tonlib/tonlibclientjson_export_list
Normal file
5
tonlib/tonlibclientjson_export_list
Normal file
|
@ -0,0 +1,5 @@
|
|||
_tonlib_client_json_create
|
||||
_tonlib_client_json_destroy
|
||||
_tonlib_client_json_send
|
||||
_tonlib_client_json_receive
|
||||
_tonlib_client_json_execute
|
Loading…
Add table
Add a link
Reference in a new issue