mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated tonlib
- updated tonlib - updated validator - updated documentation - first version of http over rldp proxy
This commit is contained in:
parent
53ec9684bd
commit
77842f9b63
128 changed files with 10555 additions and 2285 deletions
|
@ -23,7 +23,7 @@
|
|||
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
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl/adnl-ext-client.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
|
@ -37,6 +37,7 @@
|
|||
#include "Ed25519.h"
|
||||
|
||||
#include "smc-envelope/GenericAccount.h"
|
||||
#include "smc-envelope/ManualDns.h"
|
||||
#include "smc-envelope/MultisigWallet.h"
|
||||
#include "smc-envelope/TestGiver.h"
|
||||
#include "smc-envelope/TestWallet.h"
|
||||
|
@ -108,6 +109,10 @@ struct Key {
|
|||
struct Wallet {
|
||||
std::string address;
|
||||
Key key;
|
||||
|
||||
auto get_address() const {
|
||||
return tonlib_api::make_object<tonlib_api::accountAddress>(address);
|
||||
}
|
||||
};
|
||||
|
||||
struct TransactionId {
|
||||
|
@ -116,7 +121,7 @@ struct TransactionId {
|
|||
};
|
||||
|
||||
struct AccountState {
|
||||
enum Type { Empty, Wallet, Unknown } type{Empty};
|
||||
enum Type { Empty, Wallet, Dns, Unknown } type{Empty};
|
||||
td::int64 sync_utime{-1};
|
||||
td::int64 balance{-1};
|
||||
TransactionId last_transaction_id;
|
||||
|
@ -136,8 +141,17 @@ void sync(Client& client) {
|
|||
static td::uint32 default_wallet_id{0};
|
||||
std::string wallet_address(Client& client, const Key& key) {
|
||||
return sync_send(client,
|
||||
make_object<tonlib_api::wallet_v3_getAccountAddress>(
|
||||
make_object<tonlib_api::wallet_v3_initialAccountState>(key.public_key, default_wallet_id)))
|
||||
make_object<tonlib_api::getAccountAddress>(
|
||||
make_object<tonlib_api::wallet_v3_initialAccountState>(key.public_key, default_wallet_id), 0))
|
||||
.move_as_ok()
|
||||
->account_address_;
|
||||
}
|
||||
|
||||
std::string highload_wallet_address(Client& client, const Key& key) {
|
||||
return sync_send(client, make_object<tonlib_api::getAccountAddress>(
|
||||
make_object<tonlib_api::wallet_highload_v2_initialAccountState>(key.public_key,
|
||||
default_wallet_id),
|
||||
1 /*TODO: guess revision!*/))
|
||||
.move_as_ok()
|
||||
->account_address_;
|
||||
}
|
||||
|
@ -148,35 +162,31 @@ Wallet import_wallet_from_pkey(Client& client, std::string pkey, std::string pas
|
|||
make_object<tonlib_api::exportedPemKey>(td::SecureString(pkey))))
|
||||
.move_as_ok();
|
||||
Wallet wallet{"", {key->public_key_, std::move(key->secret_)}};
|
||||
wallet.address = wallet_address(client, wallet.key);
|
||||
wallet.address = highload_wallet_address(client, wallet.key);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
AccountState get_account_state(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();
|
||||
auto state = sync_send(client, tonlib_api::make_object<tonlib_api::getAccountState>(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(address)))
|
||||
.move_as_ok();
|
||||
AccountState res;
|
||||
tonlib_api::downcast_call(*generic_state, [&](auto& state) {
|
||||
res.balance = state.account_state_->balance_;
|
||||
res.sync_utime = state.account_state_->sync_utime_;
|
||||
res.last_transaction_id.lt = state.account_state_->last_transaction_id_->lt_;
|
||||
res.last_transaction_id.hash = state.account_state_->last_transaction_id_->hash_;
|
||||
});
|
||||
res.balance = state->balance_;
|
||||
res.sync_utime = state->sync_utime_;
|
||||
res.last_transaction_id.lt = state->last_transaction_id_->lt_;
|
||||
res.last_transaction_id.hash = state->last_transaction_id_->hash_;
|
||||
res.address = address;
|
||||
switch (generic_state->get_id()) {
|
||||
case tonlib_api::generic_accountStateUninited::ID:
|
||||
switch (state->account_state_->get_id()) {
|
||||
case tonlib_api::uninited_accountState::ID:
|
||||
res.type = AccountState::Empty;
|
||||
break;
|
||||
case tonlib_api::generic_accountStateWalletV3::ID:
|
||||
case tonlib_api::generic_accountStateWallet::ID:
|
||||
case tonlib_api::wallet_v3_accountState::ID:
|
||||
case tonlib_api::wallet_accountState::ID:
|
||||
res.type = AccountState::Wallet;
|
||||
break;
|
||||
case tonlib_api::dns_accountState::ID:
|
||||
res.type = AccountState::Dns;
|
||||
break;
|
||||
default:
|
||||
res.type = AccountState::Unknown;
|
||||
break;
|
||||
|
@ -219,13 +229,31 @@ struct QueryInfo {
|
|||
};
|
||||
|
||||
td::Result<QueryId> create_send_grams_query(Client& client, const Wallet& source, std::string destination,
|
||||
td::int64 amount, std::string message, bool force = false, int timeout = 0,
|
||||
bool fake = false) {
|
||||
auto r_id = sync_send(client, tonlib_api::make_object<tonlib_api::generic_createSendGramsQuery>(
|
||||
fake ? source.key.get_fake_input_key() : source.key.get_input_key(),
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(source.address),
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(destination), amount, timeout,
|
||||
force, std::move(message)));
|
||||
td::int64 amount, bool encrypted, std::string message, bool force = false,
|
||||
int timeout = 0, bool fake = false) {
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message>> msgs;
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (encrypted) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(std::move(message));
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(std::move(message));
|
||||
}
|
||||
msgs.push_back(tonlib_api::make_object<tonlib_api::msg_message>(
|
||||
tonlib_api::make_object<tonlib_api::accountAddress>(destination), amount, std::move(data)));
|
||||
|
||||
auto r_id =
|
||||
sync_send(client, tonlib_api::make_object<tonlib_api::createQuery>(
|
||||
fake ? source.key.get_fake_input_key() : source.key.get_input_key(), source.get_address(),
|
||||
timeout, tonlib_api::make_object<tonlib_api::actionMsg>(std::move(msgs), force)));
|
||||
TRY_RESULT(id, std::move(r_id));
|
||||
return QueryId{id->id_};
|
||||
}
|
||||
|
||||
td::Result<QueryId> create_update_dns_query(Client& client, const Wallet& dns,
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::dns_Action>> entries) {
|
||||
using namespace ton::tonlib_api;
|
||||
auto r_id = sync_send(client, make_object<createQuery>(dns.key.get_input_key(), dns.get_address(), 60,
|
||||
make_object<actionDns>(std::move(entries))));
|
||||
TRY_RESULT(id, std::move(r_id));
|
||||
return QueryId{id->id_};
|
||||
}
|
||||
|
@ -242,7 +270,11 @@ td::Result<QueryId> create_raw_query(Client& client, std::string source, std::st
|
|||
std::pair<Fee, Fee> query_estimate_fees(Client& client, QueryId query_id, bool ignore_chksig = false) {
|
||||
auto fees = sync_send(client, tonlib_api::make_object<tonlib_api::query_estimateFees>(query_id.id, ignore_chksig))
|
||||
.move_as_ok();
|
||||
return std::make_pair(to_fee(fees->source_fees_), to_fee(fees->destination_fees_));
|
||||
Fee second;
|
||||
if (!fees->destination_fees_.empty()) {
|
||||
second = to_fee(fees->destination_fees_[0]);
|
||||
}
|
||||
return std::make_pair(to_fee(fees->source_fees_), second);
|
||||
}
|
||||
|
||||
void query_send(Client& client, QueryId query_id) {
|
||||
|
@ -266,26 +298,38 @@ td::Result<AccountState> wait_state_change(Client& client, const AccountState& o
|
|||
}
|
||||
};
|
||||
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_transactions>> get_transactions(Client& client, std::string address,
|
||||
td::Result<tonlib_api::object_ptr<tonlib_api::raw_transactions>> get_transactions(Client& client,
|
||||
td::optional<const Wallet*> wallet,
|
||||
std::string address,
|
||||
const TransactionId& from) {
|
||||
auto got_transactions = sync_send(client, make_object<tonlib_api::raw_getTransactions>(
|
||||
wallet ? wallet.value()->key.get_input_key() : nullptr,
|
||||
make_object<tonlib_api::accountAddress>(address),
|
||||
make_object<tonlib_api::internal_transactionId>(from.lt, from.hash)))
|
||||
.move_as_ok();
|
||||
return std::move(got_transactions);
|
||||
}
|
||||
|
||||
td::Status transfer_grams(Client& client, const Wallet& wallet, std::string address, td::int64 amount) {
|
||||
td::Status transfer_grams(Client& client, const Wallet& wallet, std::string address, td::int64 amount,
|
||||
bool fast = false) {
|
||||
auto src_state = get_account_state(client, wallet.address);
|
||||
auto dst_state = get_account_state(client, address);
|
||||
auto message = td::rand_string('a', 'z', 500);
|
||||
|
||||
LOG(INFO) << "Transfer: create query " << (double)amount / Gramm << " from " << wallet.address << " to " << address;
|
||||
auto r_query_id = create_send_grams_query(client, wallet, address, amount, message);
|
||||
bool encrypt = true;
|
||||
auto r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
|
||||
if (r_query_id.is_error()) {
|
||||
LOG(INFO) << "Send query WITHOUT message encryption";
|
||||
encrypt = false;
|
||||
r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
|
||||
} else {
|
||||
LOG(INFO) << "Send query WITH message encryption";
|
||||
}
|
||||
if (r_query_id.is_error() && td::begins_with(r_query_id.error().message(), "DANGEROUS_TRANSACTION")) {
|
||||
ASSERT_TRUE(dst_state.type == AccountState::Empty);
|
||||
LOG(INFO) << "Transfer: recreate query due to DANGEROUS_TRANSACTION error";
|
||||
r_query_id = create_send_grams_query(client, wallet, address, amount, message, true);
|
||||
r_query_id = create_send_grams_query(client, wallet, address, amount, false, message, true);
|
||||
}
|
||||
|
||||
r_query_id.ensure();
|
||||
|
@ -304,6 +348,9 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
LOG(INFO) << "Transfer: send query";
|
||||
|
||||
query_send(client, query_id);
|
||||
if (fast) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Timer timer;
|
||||
TRY_RESULT(new_src_state, wait_state_change(client, src_state, query_info.valid_until));
|
||||
LOG(INFO) << "Transfer: reached source in " << timer;
|
||||
|
@ -311,7 +358,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
td::int64 lt;
|
||||
td::int64 first_fee;
|
||||
{
|
||||
auto tr = get_transactions(client, src_state.address, new_src_state.last_transaction_id).move_as_ok();
|
||||
auto tr = get_transactions(client, &wallet, src_state.address, new_src_state.last_transaction_id).move_as_ok();
|
||||
CHECK(tr->transactions_.size() > 0);
|
||||
const auto& txn = tr->transactions_[0];
|
||||
CHECK(txn->in_msg_->body_hash_ == query_info.body_hash);
|
||||
|
@ -331,7 +378,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
LOG(INFO) << "Transfer: reached destination in " << timer;
|
||||
|
||||
{
|
||||
auto tr = get_transactions(client, dst_state.address, new_dst_state.last_transaction_id).move_as_ok();
|
||||
auto tr = get_transactions(client, {}, dst_state.address, new_dst_state.last_transaction_id).move_as_ok();
|
||||
CHECK(tr->transactions_.size() > 0);
|
||||
const auto& txn = tr->transactions_[0];
|
||||
ASSERT_EQ(lt, txn->in_msg_->created_lt_);
|
||||
|
@ -341,7 +388,9 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
ASSERT_EQ(new_src_state.address, txn->in_msg_->source_);
|
||||
}
|
||||
ASSERT_EQ(new_src_state.address, txn->in_msg_->source_);
|
||||
ASSERT_EQ(message, txn->in_msg_->message_);
|
||||
if (!encrypt) {
|
||||
ASSERT_EQ(message, txn->in_msg_->message_);
|
||||
}
|
||||
auto fee_difference = fees.second.sum() - txn->fee_;
|
||||
auto desc = PSTRING() << fee_difference << " storage:[" << fees.second.storage_fee << " vs " << txn->storage_fee_
|
||||
<< "] other:[" << fees.second.sum() - fees.second.storage_fee << " vs " << txn->other_fee_
|
||||
|
@ -361,9 +410,10 @@ Wallet create_empty_wallet(Client& client) {
|
|||
Wallet wallet{"", {key->public_key_, std::move(key->secret_)}};
|
||||
|
||||
auto account_address =
|
||||
sync_send(client,
|
||||
make_object<tonlib_api::wallet_v3_getAccountAddress>(
|
||||
make_object<tonlib_api::wallet_v3_initialAccountState>(wallet.key.public_key, default_wallet_id)))
|
||||
sync_send(
|
||||
client,
|
||||
make_object<tonlib_api::getAccountAddress>(
|
||||
make_object<tonlib_api::wallet_v3_initialAccountState>(wallet.key.public_key, default_wallet_id), 0))
|
||||
.move_as_ok();
|
||||
|
||||
wallet.address = account_address->account_address_;
|
||||
|
@ -376,31 +426,33 @@ Wallet create_empty_wallet(Client& client) {
|
|||
return wallet;
|
||||
}
|
||||
|
||||
void dump_transaction_history(Client& client, std::string address) {
|
||||
Wallet create_empty_dns(Client& client) {
|
||||
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->previous_transaction_id_->lt_ < lt);
|
||||
for (auto& txn : got_transactions->transactions_) {
|
||||
LOG(ERROR) << to_string(txn);
|
||||
cnt++;
|
||||
}
|
||||
tid = std::move(got_transactions->previous_transaction_id_);
|
||||
}
|
||||
LOG(ERROR) << cnt;
|
||||
auto key = sync_send(client, make_object<tonlib_api::createNewKey>(td::SecureString("local"), td::SecureString(),
|
||||
td::SecureString()))
|
||||
.move_as_ok();
|
||||
Wallet dns{"", {key->public_key_, std::move(key->secret_)}};
|
||||
|
||||
auto account_address =
|
||||
sync_send(client, make_object<tonlib_api::getAccountAddress>(
|
||||
make_object<tonlib_api::dns_initialAccountState>(dns.key.public_key, default_wallet_id), 0))
|
||||
.move_as_ok();
|
||||
|
||||
dns.address = account_address->account_address_;
|
||||
|
||||
// get state of empty account
|
||||
auto state = get_account_state(client, dns.address);
|
||||
ASSERT_EQ(-1, state.balance);
|
||||
ASSERT_EQ(AccountState::Empty, state.type);
|
||||
|
||||
return dns;
|
||||
}
|
||||
|
||||
void test_estimate_fees_without_key(Client& client, const Wallet& wallet_a, const Wallet& wallet_b) {
|
||||
LOG(ERROR) << " SUBTEST: estimate fees without key";
|
||||
{
|
||||
auto query_id = create_send_grams_query(client, wallet_a, wallet_b.address, 0, "???", true, 0, true).move_as_ok();
|
||||
auto query_id =
|
||||
create_send_grams_query(client, wallet_a, wallet_b.address, 0, false, "???", true, 0, true).move_as_ok();
|
||||
auto fees1 = query_estimate_fees(client, query_id, false);
|
||||
auto fees2 = query_estimate_fees(client, query_id, true);
|
||||
LOG(INFO) << "Fee without ignore_chksig\t" << fees1;
|
||||
|
@ -495,6 +547,74 @@ void test_multisig(Client& client, const Wallet& giver_wallet) {
|
|||
}
|
||||
}
|
||||
|
||||
void dns_resolve(Client& client, const Wallet& dns, std::string name) {
|
||||
using namespace ton::tonlib_api;
|
||||
auto address = dns.get_address();
|
||||
while (true) {
|
||||
auto resolved =
|
||||
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1)).move_as_ok();
|
||||
CHECK(resolved->entries_.size() == 1);
|
||||
LOG(INFO) << to_string(resolved);
|
||||
if (resolved->entries_[0]->category_ == -1) {
|
||||
auto entry = ton::move_tl_object_as<dns_entryDataNextResolver>(resolved->entries_[0]->entry_);
|
||||
address = std::move(entry->resolver_);
|
||||
continue;
|
||||
}
|
||||
LOG(INFO) << "OK";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void test_dns(Client& client, const Wallet& giver_wallet) {
|
||||
auto A = create_empty_dns(client);
|
||||
auto A_B = create_empty_dns(client);
|
||||
auto A_B_C = create_empty_dns(client);
|
||||
transfer_grams(client, giver_wallet, A.address, 1 * Gramm, true).ensure();
|
||||
transfer_grams(client, giver_wallet, A_B.address, 1 * Gramm, true).ensure();
|
||||
transfer_grams(client, giver_wallet, A_B_C.address, 1 * Gramm, true).ensure();
|
||||
|
||||
using namespace ton::tonlib_api;
|
||||
std::vector<object_ptr<dns_Action>> actions;
|
||||
|
||||
actions.push_back(make_object<dns_actionSet>(
|
||||
make_object<dns_entry>("A", -1, make_object<dns_entryDataNextResolver>(A_B.get_address()))));
|
||||
auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok();
|
||||
actions.push_back(make_object<dns_actionSet>(
|
||||
make_object<dns_entry>("B.A", -1, make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
|
||||
auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok();
|
||||
actions.push_back(
|
||||
make_object<dns_actionSet>(make_object<dns_entry>("C.B.A", 1, make_object<dns_entryDataText>("Hello dns"))));
|
||||
auto init_A_B_C = create_update_dns_query(client, A_B_C, std::move(actions)).move_as_ok();
|
||||
|
||||
LOG(INFO) << "Send dns init queries";
|
||||
::query_send(client, init_A);
|
||||
::query_send(client, init_A_B);
|
||||
::query_send(client, init_A_B_C);
|
||||
|
||||
auto wait = [&](auto& query, auto& dns) {
|
||||
auto info = query_get_info(client, query);
|
||||
LOG(INFO) << "Wait till dns " << dns.address << " is inited " << info.valid_until;
|
||||
while (true) {
|
||||
auto state = get_account_state(client, dns.address);
|
||||
LOG(INFO) << "Account type: " << state.type << " " << state.sync_utime;
|
||||
if (state.type == ::AccountState::Dns) {
|
||||
break;
|
||||
}
|
||||
if (state.sync_utime >= info.valid_until) {
|
||||
LOG(FATAL) << "Query expired";
|
||||
}
|
||||
LOG(INFO) << "time left to wait: " << td::format::as_time(info.valid_until - state.sync_utime);
|
||||
client.receive(1);
|
||||
}
|
||||
};
|
||||
wait(init_A, A);
|
||||
wait(init_A_B, A_B);
|
||||
wait(init_A_B_C, A_B_C);
|
||||
|
||||
// search "C.B.A"
|
||||
::dns_resolve(client, A, "C.B.A");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
td::set_default_failure_signal_handler();
|
||||
using tonlib_api::make_object;
|
||||
|
@ -550,6 +670,7 @@ int main(int argc, char* argv[]) {
|
|||
// give wallet with some test grams to run test
|
||||
auto giver_wallet = import_wallet_from_pkey(client, giver_key_str, giver_key_pwd);
|
||||
|
||||
test_dns(client, giver_wallet);
|
||||
test_back_and_forth_transfer(client, giver_wallet, false);
|
||||
test_back_and_forth_transfer(client, giver_wallet, true);
|
||||
test_multisig(client, giver_wallet);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue