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
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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue