1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

414
tonlib/test/offline.cpp Normal file
View 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
View 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;
}