1
0
mirror of https://github.com/danog/ton.git synced 2024-11-26 12:04:48 +01:00

updated tonlib

1. updated tonlib
2. fixed bug in state download
This commit is contained in:
ton 2019-09-22 10:14:09 +04:00
parent f40822b58a
commit 28df74178c
17 changed files with 362 additions and 115 deletions

View File

@ -258,6 +258,7 @@ td::Result<Transaction::Info> Transaction::validate() {
}
Info res;
res.blkid = blkid;
res.now = trans.now;
res.prev_trans_lt = trans.prev_trans_lt;
res.prev_trans_hash = trans.prev_trans_hash;
res.transaction = root;
@ -281,6 +282,8 @@ td::Result<TransactionList::Info> TransactionList::validate() const {
Info res;
auto current_lt = lt;
auto current_hash = hash;
res.lt = lt;
res.hash = hash;
for (auto& root : list) {
const auto& blkid = blkids[c++];
Transaction transaction;

View File

@ -60,6 +60,7 @@ struct Transaction {
struct Info {
ton::BlockIdExt blkid;
td::uint32 now;
ton::LogicalTime prev_trans_lt;
ton::Bits256 prev_trans_hash;
td::Ref<vm::Cell> transaction;
@ -74,21 +75,12 @@ struct TransactionList {
td::BufferSlice transactions_boc;
struct Info {
ton::LogicalTime lt;
ton::Bits256 hash;
std::vector<Transaction::Info> transactions;
};
td::Result<Info> validate() const;
};
struct BlockChain {
ton::BlockIdExt from;
ton::BlockIdExt to;
td::int32 mode;
td::BufferSlice proof;
using Info = std::unique_ptr<block::BlockProofChain>;
td::Result<Info> validate() const;
};
} // namespace block

View File

@ -53,17 +53,20 @@ SecureString create_empty<SecureString>(size_t size) {
template <class T>
Result<T> read_file_impl(CSlice path, int64 size, int64 offset) {
TRY_RESULT(from_file, FileFd::open(path, FileFd::Read));
TRY_RESULT(file_size, from_file.get_size());
if (offset < 0 || offset > file_size) {
return Status::Error("Failed to read file: invalid offset");
}
if (size == -1) {
TRY_RESULT(file_size, from_file.get_size());
size = file_size;
size = file_size - offset;
} else if (size >= 0) {
if (size + offset > file_size) {
size = file_size - offset;
}
}
if (size < 0) {
return Status::Error("Failed to read file: invalid size");
}
if (offset < 0 || offset > size) {
return Status::Error("Failed to read file: invalid offset");
}
size -= offset;
auto content = create_empty<T>(narrow_cast<size_t>(size));
TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset));
if (got_size != static_cast<size_t>(size)) {

View File

@ -3,5 +3,5 @@ cmake_minimum_required(VERSION 2.8)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_library(wingetopt src/getopt.c src/getopt.h)
target_include_directories(wingetopt PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_include_directories(wingetopt PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)

View File

@ -16,7 +16,7 @@ vector {t:Type} # [ t ] = Vector t;
error code:int32 message:string = Error;
ok = Ok;
options config:string keystore_directory:string = Options;
options config:string keystore_directory:string use_callbacks_for_network:Bool = Options;
key public_key:string secret:secureBytes = Key;
inputKey key:key local_password:secureBytes = InputKey;
@ -31,17 +31,17 @@ accountAddress account_address:string = AccountAddress;
internal.transactionId lt:int64 hash:bytes = internal.TransactionId;
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState;
raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId = raw.AccountState;
raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState;
raw.message source:string destination:string value:int64 = raw.Message;
raw.transaction data:bytes previous_transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
raw.transactions transactions:vector<raw.Transaction> = raw.Transactions;
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
raw.transactions transactions:vector<raw.Transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
testWallet.initialAccountState public_key:string = testWallet.InitialAccountState;
testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId = testWallet.AccountState;
testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = testWallet.AccountState;
testGiver.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId = testGiver.AccountState;
testGiver.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53= testGiver.AccountState;
uninited.accountState balance:int64 = uninited.AccountState;
uninited.accountState balance:int64 last_transaction_id:internal.transactionId sync_utime:int53 = uninited.AccountState;
generic.initialAccountStateRaw initital_account_state:raw.initialAccountState = generic.InitialAccountState;
generic.initialAccountStateTestWallet initital_account_state:testWallet.initialAccountState = generic.InitialAccountState;
@ -51,6 +51,8 @@ generic.accountStateTestWallet account_state:testWallet.accountState = generic.A
generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState;
generic.accountStateUninited account_state:uninited.accountState = generic.AccountState;
updateSendLiteServerQuery id:int64 data:bytes = Update;
---functions---
init options:options = Ok;
@ -89,5 +91,7 @@ testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 = Ok;
generic.getAccountState account_address:accountAddress = generic.AccountState;
generic.sendGrams private_key:inputKey source:accountAddress destination:accountAddress amount:int64 = Ok;
runTests dir:string = Ok;
onLiteServerQueryResult id:int64 bytes:bytes = Ok;
onLiteServerQueryError id:int64 error:error = Ok;
runTests dir:string = Ok;

Binary file not shown.

View File

@ -9,6 +9,7 @@ set(TONLIB_SOURCE
tonlib/Config.cpp
tonlib/ExtClient.cpp
tonlib/ExtClientLazy.cpp
tonlib/ExtClientOutbound.cpp
tonlib/GenericAccount.cpp
tonlib/KeyStorage.cpp
tonlib/LastBlock.cpp
@ -21,6 +22,7 @@ set(TONLIB_SOURCE
tonlib/Config.h
tonlib/ExtClient.h
tonlib/ExtClientLazy.h
tonlib/ExtClientOutbound.h
tonlib/GenericAccount.h
tonlib/KeyStorage.h
tonlib/LastBlock.h

View File

@ -172,16 +172,17 @@ TEST(Tonlib, InitClose) {
{
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();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", ".", false))).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", ".")))
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("fdajkfldsjkafld", ".", false)))
.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();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", "fdhskfds", false)))
.ensure_error();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", ".", false))).ensure();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", ".", false))).ensure_error();
td::Slice bad_config = R"abc(
{
@ -194,7 +195,7 @@ TEST(Tonlib, InitClose) {
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();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>("", ".", false))).ensure_error();
}
}
@ -289,7 +290,7 @@ TEST(Tonlib, KeysApi) {
Client client;
// init
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>("", ".", false))).ensure();
auto local_password = td::SecureString("local password");
auto mnemonic_password = td::SecureString("mnemonic password");
{

View File

@ -170,12 +170,12 @@ void dump_transaction_history(Client& client, std::string address) {
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);
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->transactions_.back()->previous_transaction_id_);
tid = std::move(got_transactions->previous_transaction_id_);
}
LOG(ERROR) << cnt;
}
@ -196,7 +196,8 @@ int main(int argc, char* argv[]) {
Client client;
{
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(global_config_str, "."))).ensure();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(global_config_str, ".", false)))
.ensure();
}
//dump_transaction_history(client, get_test_giver_address(client));
auto wallet_a = create_wallet(client);
@ -208,7 +209,8 @@ int main(int argc, char* argv[]) {
return 0;
{
// init
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(global_config_str, "."))).ensure();
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(global_config_str, ".", false)))
.ensure();
auto key = sync_send(client, make_object<tonlib_api::createNewKey>(
td::SecureString("local"), td::SecureString("mnemonic"), td::SecureString()))

View File

@ -21,10 +21,10 @@
#include "tonlib/LastBlock.h"
namespace tonlib {
void ExtClient::with_last_block(td::Promise<ton::BlockIdExt> promise) {
void ExtClient::with_last_block(td::Promise<LastBlockInfo> 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) {
td::Promise<LastBlockInfo> P = [query_id, self = this,
actor_id = td::actor::actor_id()](td::Result<LastBlockInfo> 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));
});

View File

@ -29,6 +29,7 @@
namespace tonlib {
class LastBlock;
struct LastBlockInfo;
struct ExtClientRef {
td::actor::ActorId<ton::adnl::AdnlExtClient> andl_ext_client_;
td::actor::ActorId<LastBlock> last_block_actor_;
@ -49,7 +50,7 @@ class ExtClient {
return client_;
}
void with_last_block(td::Promise<ton::BlockIdExt> promise);
void with_last_block(td::Promise<LastBlockInfo> promise);
template <class QueryT>
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
@ -74,7 +75,7 @@ class ExtClient {
private:
ExtClientRef client_;
td::Container<td::Promise<td::BufferSlice>> queries_;
td::Container<td::Promise<ton::BlockIdExt>> last_block_queries_;
td::Container<td::Promise<LastBlockInfo>> last_block_queries_;
void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
};

View File

@ -23,15 +23,12 @@
#include "lite-client/lite-client-common.h"
namespace tonlib {
LastBlock::LastBlock(ExtClientRef client, ton::ZeroStateIdExt zero_state_id, ton::BlockIdExt last_block_id,
td::actor::ActorShared<> parent) {
zero_state_id_ = std::move(zero_state_id);
mc_last_block_id_ = std::move(last_block_id);
LastBlock::LastBlock(ExtClientRef client, State state, td::unique_ptr<Callback> callback)
: state_(std::move(state)), callback_(std::move(callback)) {
client_.set_client(client);
parent_ = std::move(parent);
}
void LastBlock::get_last_block(td::Promise<ton::BlockIdExt> promise) {
void LastBlock::get_last_block(td::Promise<LastBlockInfo> promise) {
if (promises_.empty()) {
do_get_last_block();
}
@ -39,13 +36,16 @@ void LastBlock::get_last_block(td::Promise<ton::BlockIdExt> 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)); });
return;
//client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
//[this](auto r_info) { this->on_masterchain_info(std::move(r_info)); });
//return;
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
client_.send_query(
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(mc_last_block_id_), nullptr),
[this, from = mc_last_block_id_](auto r_block_proof) { this->on_block_proof(from, std::move(r_block_proof)); });
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr),
[this, from = state_.last_key_block_id](auto r_block_proof) {
this->on_block_proof(from, std::move(r_block_proof));
});
}
td::Result<bool> LastBlock::process_block_proof(
@ -60,6 +60,12 @@ td::Result<bool> LastBlock::process_block_proof(
}
TRY_STATUS(chain->validate());
update_mc_last_block(chain->to);
if (chain->has_key_block) {
update_mc_last_key_block(chain->key_blkid);
}
if (chain->has_utime) {
update_utime(chain->last_utime);
}
return chain->complete;
}
@ -68,14 +74,16 @@ void LastBlock::on_block_proof(
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
auto r_is_ready = process_block_proof(from, std::move(r_block_proof));
if (r_is_ready.is_error()) {
LOG(WARNING) << "Failed liteServer_getBlockProof " << r_block_proof.error();
LOG(WARNING) << "Failed liteServer_getBlockProof " << r_is_ready.error();
return;
}
auto is_ready = r_is_ready.move_as_ok();
if (is_ready) {
for (auto& promise : promises_) {
auto copy = mc_last_block_id_;
promise.set_value(std::move(copy));
LastBlockInfo res;
res.id = state_.last_block_id;
res.utime = state_.utime;
promise.set_value(std::move(res));
}
promises_.clear();
} else {
@ -93,8 +101,10 @@ void LastBlock::on_masterchain_info(
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
}
for (auto& promise : promises_) {
auto copy = mc_last_block_id_;
promise.set_value(std::move(copy));
LastBlockInfo res;
res.id = state_.last_block_id;
res.utime = state_.utime;
promise.set_value(std::move(res));
}
promises_.clear();
}
@ -105,17 +115,17 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
return;
}
if (!zero_state_id_.is_valid()) {
if (!state_.zero_state_id.is_valid()) {
LOG(INFO) << "Init zerostate: " << zero_state_id.to_str();
zero_state_id_ = std::move(zero_state_id);
state_.zero_state_id = std::move(zero_state_id);
return;
}
if (zero_state_id_ == zero_state_id_) {
if (state_.zero_state_id == state_.zero_state_id) {
return;
}
LOG(FATAL) << "Masterchain zerostate mismatch: expected: " << zero_state_id_.to_str() << ", found "
LOG(FATAL) << "Masterchain zerostate mismatch: expected: " << state_.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
@ -126,9 +136,25 @@ void LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
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();
if (!state_.last_block_id.is_valid() || state_.last_block_id.id.seqno < mc_block_id.id.seqno) {
state_.last_block_id = mc_block_id;
LOG(INFO) << "Update masterchain block id: " << state_.last_block_id.to_str();
}
}
void LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) {
if (!mc_key_block_id.is_valid()) {
LOG(ERROR) << "Ignore invalid masterchain block";
return;
}
if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) {
state_.last_key_block_id = mc_key_block_id;
LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
}
}
void LastBlock::update_utime(td::int64 utime) {
if (state_.utime < utime) {
state_.utime = utime;
}
}
} // namespace tonlib

View File

@ -22,21 +22,35 @@
#include "tonlib/ExtClient.h"
namespace tonlib {
struct LastBlockInfo {
ton::BlockIdExt id;
td::int64 utime{0};
};
class LastBlock : public td::actor::Actor {
public:
explicit LastBlock(ExtClientRef client, ton::ZeroStateIdExt zero_state_id, ton::BlockIdExt last_block_id,
td::actor::ActorShared<> parent);
struct State {
ton::ZeroStateIdExt zero_state_id;
ton::BlockIdExt last_key_block_id;
ton::BlockIdExt last_block_id;
td::int64 utime{0};
};
void get_last_block(td::Promise<ton::BlockIdExt> promise);
class Callback {
public:
virtual ~Callback() {
}
virtual void on_state_changes(State state) = 0;
};
explicit LastBlock(ExtClientRef client, State state, td::unique_ptr<Callback> callback);
void get_last_block(td::Promise<LastBlockInfo> promise);
private:
ExtClient client_;
ton::ZeroStateIdExt zero_state_id_;
ton::BlockIdExt mc_last_block_id_;
State state_;
td::unique_ptr<Callback> callback_;
std::vector<td::Promise<ton::BlockIdExt>> promises_;
td::actor::ActorShared<> parent_;
std::vector<td::Promise<LastBlockInfo>> promises_;
void do_get_last_block();
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
@ -49,5 +63,7 @@ class LastBlock : public td::actor::Actor {
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
void update_mc_last_block(ton::BlockIdExt mc_block_id);
void update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
void update_utime(td::int64 utime);
};
} // namespace tonlib

View File

@ -19,6 +19,7 @@
#include "TonlibClient.h"
#include "tonlib/ExtClientLazy.h"
#include "tonlib/ExtClientOutbound.h"
#include "tonlib/GenericAccount.h"
#include "tonlib/LastBlock.h"
#include "tonlib/TestWallet.h"
@ -73,6 +74,7 @@ struct RawAccountState {
td::Ref<vm::CellSlice> code;
td::Ref<vm::CellSlice> data;
block::AccountState::Info info;
td::int64 sync_utime = 0;
};
td::Result<td::int64> to_balance_or_throw(td::Ref<vm::CellSlice> balance_ref) {
@ -169,7 +171,7 @@ class GetRawAccountState : public td::actor::Actor {
block::StdAddress address_;
td::Promise<RawAccountState> promise_;
ExtClient client_;
ton::BlockIdExt last_block_;
LastBlockInfo 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))));
@ -180,10 +182,11 @@ class GetRawAccountState : public td::actor::Actor {
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_));
TRY_RESULT(info, account_state.validate(last_block_.id, address_));
auto serialized_state = account_state.state.clone();
RawAccountState res;
res.info = std::move(info);
res.sync_utime = last_block_.utime;
auto cell = res.info.root;
if (cell.is_null()) {
return res;
@ -222,14 +225,14 @@ class GetRawAccountState : public td::actor::Actor {
}
void start_up() override {
client_.with_last_block([self = this](td::Result<ton::BlockIdExt> r_last_block) {
client_.with_last_block([self = this](td::Result<LastBlockInfo> 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::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.id),
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)); });
@ -263,28 +266,68 @@ ExtClientRef TonlibClient::get_client_ref() {
return ref;
}
void TonlibClient::proxy_request(td::int64 query_id, std::string data) {
callback_->on_result(0, tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data));
}
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 {
if (use_callbacks_for_network_) {
class Callback : public ExtClientOutbound::Callback {
public:
explicit Callback(td::actor::ActorShared<TonlibClient> parent) : parent_(std::move(parent)) {
}
void request(td::int64 id, std::string data) override {
send_closure(parent_, &TonlibClient::proxy_request, id, std::move(data));
}
private:
td::actor::ActorShared<TonlibClient> parent_;
};
ref_cnt_++;
auto client = ExtClientOutbound::create(td::make_unique<Callback>(td::actor::actor_shared(this)));
ext_client_outbound_ = client.get();
raw_client_ = std::move(client);
} else {
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()));
}
}
void TonlibClient::init_last_block() {
ref_cnt_++;
class Callback : public LastBlock::Callback {
public:
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
Callback(td::actor::ActorShared<TonlibClient> client) : client_(std::move(client)) {
}
void on_state_changes(LastBlock::State state) override {
//TODO
}
private:
td::actor::ActorShared<> parent_;
td::actor::ActorShared<TonlibClient> client_;
};
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(),
ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
config_.zero_state_id.file_hash),
config_.zero_state_id, td::actor::actor_shared());
LastBlock::State state;
//state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
//config_.zero_state_id.file_hash),
state.last_block_id = config_.zero_state_id;
state.last_key_block_id = config_.zero_state_id;
raw_last_block_ = td::actor::create_actor<LastBlock>("LastBlock", get_client_ref(), std::move(state),
td::make_unique<Callback>(td::actor::actor_shared(this)));
client_.set_client(get_client_ref());
}
@ -426,6 +469,7 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request,
return td::Status::Error(400, "Field options must not be empty");
}
TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_));
use_callbacks_for_network_ = request.options_->use_callbacks_for_network_;
if (!request.options_->config_.empty()) {
TRY_STATUS(set_config(std::move(request.options_->config_)));
}
@ -444,6 +488,7 @@ td::Status TonlibClient::set_config(std::string config) {
}
config_ = std::move(new_config);
init_ext_client();
init_last_block();
return td::Status::OK();
}
@ -454,6 +499,7 @@ td::Status TonlibClient::do_request(const tonlib_api::close& request,
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_));
@ -461,6 +507,10 @@ td::Status TonlibClient::do_request(const tonlib_api::options_setConfig& request
return td::Status::OK();
}
tonlib_api::object_ptr<tonlib_api::internal_transactionId> empty_transaction_id() {
return tonlib_api::make_object<tonlib_api::internal_transactionId>(0, std::string(32, 0));
}
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());
@ -482,7 +532,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_accountState>> to_raw_accountS
.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));
to_transaction_id(raw_state.info), raw_state.sync_utime);
}
td::Result<std::string> to_std_address_or_throw(td::Ref<vm::CellSlice> cs) {
@ -591,7 +641,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transaction>> to_raw_transacti
}
}
return tonlib_api::make_object<tonlib_api::raw_transaction>(
data,
info.now, 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));
@ -608,7 +658,14 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transactions>> to_raw_transact
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));
auto transaction_id =
tonlib_api::make_object<tonlib_api::internal_transactionId>(info.lt, info.hash.as_slice().str());
for (auto& transaction : transactions) {
std::swap(transaction->transaction_id_, transaction_id);
}
return tonlib_api::make_object<tonlib_api::raw_transactions>(std::move(transactions), std::move(transaction_id));
}
td::Result<tonlib_api::object_ptr<tonlib_api::testWallet_accountState>> to_testWallet_accountState(
@ -622,8 +679,8 @@ td::Result<tonlib_api::object_ptr<tonlib_api::testWallet_accountState>> to_testW
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));
return tonlib_api::make_object<tonlib_api::testWallet_accountState>(
raw_state.balance, static_cast<td::uint32>(seqno), to_transaction_id(raw_state.info), raw_state.sync_utime);
}
td::Result<tonlib_api::object_ptr<tonlib_api::testGiver_accountState>> to_testGiver_accountState(
@ -637,15 +694,16 @@ td::Result<tonlib_api::object_ptr<tonlib_api::testGiver_accountState>> to_testGi
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));
return tonlib_api::make_object<tonlib_api::testGiver_accountState>(
raw_state.balance, static_cast<td::uint32>(seqno), to_transaction_id(raw_state.info), raw_state.sync_utime);
}
td::Result<tonlib_api::object_ptr<tonlib_api::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));
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance, empty_transaction_id(),
raw_state.sync_utime));
}
auto code_hash = raw_state.code->prefetch_ref()->get_hash();
@ -1019,4 +1077,30 @@ td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& reque
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryResult& request,
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_, td::BufferSlice(request.bytes_),
[promise = std::move(promise)](td::Result<td::Unit> res) mutable {
if (res.is_ok()) {
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
} else {
promise.set_error(res.move_as_error());
}
});
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryError& request,
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_,
td::Status::Error(request.error_->code_, request.error_->message_),
[promise = std::move(promise)](td::Result<td::Unit> res) mutable {
if (res.is_ok()) {
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
} else {
promise.set_error(res.move_as_error());
}
});
return td::Status::OK();
}
} // namespace tonlib

View File

@ -22,6 +22,7 @@
#include "tonlib/Config.h"
#include "tonlib/ExtClient.h"
#include "tonlib/ExtClientOutbound.h"
#include "tonlib/KeyStorage.h"
#include "td/actor/actor.h"
@ -44,6 +45,9 @@ class TonlibClient : public td::actor::Actor {
td::unique_ptr<TonlibCallback> callback_;
Config config_;
bool use_callbacks_for_network_{false};
td::actor::ActorId<ExtClientOutbound> ext_client_outbound_;
// KeyStorage
KeyStorage key_storage_;
@ -54,6 +58,7 @@ class TonlibClient : public td::actor::Actor {
ExtClientRef get_client_ref();
void init_ext_client();
void init_last_block();
bool is_closing_{false};
td::uint32 ref_cnt_{1};
@ -130,5 +135,12 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(const tonlib_api::changeLocalPassword& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise);
td::Status do_request(const tonlib_api::onLiteServerQueryResult& request,
td::Promise<object_ptr<tonlib_api::ok>>&& promise);
td::Status do_request(const tonlib_api::onLiteServerQueryError& request,
td::Promise<object_ptr<tonlib_api::ok>>&& promise);
void proxy_request(td::int64 query_id, std::string data);
};
} // namespace tonlib

View File

@ -5,12 +5,17 @@
#include "td/utils/Parser.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "terminal/terminal.h"
#include "tonlib/TonlibClient.h"
#include "tonlib/TonlibCallback.h"
#include "tonlib/ExtClientLazy.h"
#include "auto/tl/tonlib_api.hpp"
#include <iostream>
#include <map>
@ -20,6 +25,7 @@ class TonlibCli : public td::actor::Actor {
bool enable_readline{true};
std::string config;
std::string key_dir{"."};
bool use_callbacks_for_network{false};
};
TonlibCli(Options options) : options_(std::move(options)) {
}
@ -39,6 +45,8 @@ class TonlibCli : public td::actor::Actor {
std::map<std::uint64_t, td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>> query_handlers_;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
bool is_closing_{false};
td::uint32 ref_cnt_{1};
@ -79,8 +87,28 @@ class TonlibCli : public td::actor::Actor {
load_keys();
if (options_.use_callbacks_for_network) {
auto config = tonlib::Config::parse(options_.config).move_as_ok();
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 tonlib::ExtClientLazy::Callback {
public:
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
}
private:
td::actor::ActorShared<> parent_;
};
ref_cnt_++;
raw_client_ = tonlib::ExtClientLazy::create(lite_client.adnl_id, lite_client.address,
td::make_unique<Callback>(td::actor::actor_shared()));
}
using tonlib_api::make_object;
send_query(make_object<tonlib_api::init>(make_object<tonlib_api::options>(options_.config, options_.key_dir)),
send_query(make_object<tonlib_api::init>(make_object<tonlib_api::options>(options_.config, options_.key_dir,
options_.use_callbacks_for_network)),
[](auto r_ok) {
LOG_IF(ERROR, r_ok.is_error()) << r_ok.error();
td::TerminalIO::out() << "Tonlib is inited\n";
@ -121,6 +149,8 @@ class TonlibCli : public td::actor::Actor {
td::TerminalIO::out() << "exportkey [key_id] - export key\n";
td::TerminalIO::out() << "setconfig <path> - set lite server config\n";
td::TerminalIO::out() << "getstate <key_id> - get state of simple wallet with requested key\n";
td::TerminalIO::out()
<< "gethistory <key_id> - get history fo simple wallet with requested key (last 10 transactions)\n";
td::TerminalIO::out() << "init <key_id> - init simple wallet with requested key\n";
td::TerminalIO::out() << "transfer <from_key_id> <to_key_id> <amount> - transfer <amount> of grams from "
"<from_key_id> to <to_key_id>.\n"
@ -145,6 +175,8 @@ class TonlibCli : public td::actor::Actor {
set_config(parser.read_word());
} else if (cmd == "getstate") {
get_state(parser.read_word());
} else if (cmd == "gethistory") {
get_history(parser.read_word());
} else if (cmd == "init") {
init_simple_wallet(parser.read_word());
} else if (cmd == "transfer") {
@ -157,7 +189,31 @@ class TonlibCli : public td::actor::Actor {
}
}
void on_adnl_result(td::uint64 id, td::Result<td::BufferSlice> res) {
using tonlib_api::make_object;
if (res.is_ok()) {
send_query(make_object<tonlib_api::onLiteServerQueryResult>(id, res.move_as_ok().as_slice().str()),
[](auto r_ok) { LOG_IF(ERROR, r_ok.is_error()) << r_ok.error(); });
LOG(ERROR) << "!!!";
} else {
send_query(make_object<tonlib_api::onLiteServerQueryError>(
id, make_object<tonlib_api::error>(res.error().code(), res.error().message().str())),
[](auto r_ok) { LOG_IF(ERROR, r_ok.is_error()) << r_ok.error(); });
}
}
void on_tonlib_result(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::Object> result) {
if (id == 0) {
if (result->get_id() == tonlib_api::updateSendLiteServerQuery::ID) {
auto update = tonlib_api::move_object_as<tonlib_api::updateSendLiteServerQuery>(std::move(result));
CHECK(!raw_client_.empty());
send_closure(raw_client_, &ton::adnl::AdnlExtClient::send_query, "query", td::BufferSlice(update->data_),
td::Timestamp::in(5),
[actor_id = actor_id(this), id = update->id_](td::Result<td::BufferSlice> res) {
send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res));
});
}
}
auto it = query_handlers_.find(id);
if (it == query_handlers_.end()) {
return;
@ -468,6 +524,53 @@ class TonlibCli : public td::actor::Actor {
td::TerminalIO::out() << to_string(r_res.ok());
});
}
void get_history(td::Slice key) {
if (key.empty()) {
dump_keys();
td::TerminalIO::out() << "Choose public key (hex prefix or #N)";
cont_ = [this](td::Slice key) { this->get_state(key); };
return;
}
auto r_address = to_account_address(key, false);
if (r_address.is_error()) {
td::TerminalIO::out() << "Unknown key id: [" << key << "]\n";
return;
}
auto address = r_address.move_as_ok();
using tonlib_api::make_object;
send_query(make_object<tonlib_api::generic_getAccountState>(
ton::move_tl_object_as<tonlib_api::accountAddress>(std::move(address.address))),
[this, key = key.str()](auto r_res) {
if (r_res.is_error()) {
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";
return;
}
this->get_history(key, *r_res.move_as_ok());
});
}
void get_history(td::Slice key, tonlib_api::generic_AccountState& state) {
auto r_address = to_account_address(key, false);
if (r_address.is_error()) {
td::TerminalIO::out() << "Unknown key id: [" << key << "]\n";
return;
}
auto address = r_address.move_as_ok();
tonlib_api::object_ptr<tonlib_api::internal_transactionId> transaction_id;
downcast_call(state, [&](auto& state) { transaction_id = std::move(state.account_state_->last_transaction_id_); });
send_query(
tonlib_api::make_object<tonlib_api::raw_getTransactions>(
ton::move_tl_object_as<tonlib_api::accountAddress>(std::move(address.address)), std::move(transaction_id)),
[](auto r_res) {
if (r_res.is_error()) {
td::TerminalIO::out() << "Can't get transactions: " << r_res.error() << "\n";
return;
}
td::TerminalIO::out() << to_string(r_res.move_as_ok()) << "\n";
});
}
void transfer(td::Slice from, td::Slice to, td::Slice grams) {
auto r_from_address = to_account_address(from, true);
@ -591,6 +694,10 @@ int main(int argc, char* argv[]) {
options.config = std::move(data);
return td::Status::OK();
});
p.add_option('c', "use_callbacks_for_network (for debug)", "do not use this", [&]() {
options.use_callbacks_for_network = true;
return td::Status::OK();
});
auto S = p.run(argc, argv);
if (S.is_error()) {

View File

@ -151,19 +151,13 @@ void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size,
auto v = R.move_as_ok();
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), file_hash = v.file_hash](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
auto data = R.move_as_ok();
if (file_hash != sha256_bits256(data.as_slice())) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "db error: bad file hash"));
} else {
promise.set_value(std::move(data));
}
}
});
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_value(R.move_as_ok());
}
});
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), offset, max_size, std::move(P))
.release();