From 28df74178c43aee3bc288e11cfdfadb9a1138c17 Mon Sep 17 00:00:00 2001 From: ton Date: Sun, 22 Sep 2019 10:14:09 +0400 Subject: [PATCH] updated tonlib 1. updated tonlib 2. fixed bug in state download --- crypto/block/check-proof.cpp | 3 + crypto/block/check-proof.h | 14 +-- tdutils/td/utils/filesystem.cpp | 15 +-- third-party/wingetopt/CMakeLists.txt | 2 +- tl/generate/scheme/tonlib_api.tl | 20 ++-- tl/generate/scheme/tonlib_api.tlo | Bin 8696 -> 9420 bytes tonlib/CMakeLists.txt | 2 + tonlib/test/offline.cpp | 15 +-- tonlib/test/online.cpp | 10 +- tonlib/tonlib/ExtClient.cpp | 6 +- tonlib/tonlib/ExtClient.h | 5 +- tonlib/tonlib/LastBlock.cpp | 72 +++++++++----- tonlib/tonlib/LastBlock.h | 32 ++++-- tonlib/tonlib/TonlibClient.cpp | 140 +++++++++++++++++++++------ tonlib/tonlib/TonlibClient.h | 12 +++ tonlib/tonlib/tonlib-cli.cpp | 109 ++++++++++++++++++++- validator/db/filedb.cpp | 20 ++-- 17 files changed, 362 insertions(+), 115 deletions(-) diff --git a/crypto/block/check-proof.cpp b/crypto/block/check-proof.cpp index e8316f5..a856c87 100644 --- a/crypto/block/check-proof.cpp +++ b/crypto/block/check-proof.cpp @@ -258,6 +258,7 @@ td::Result 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::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; diff --git a/crypto/block/check-proof.h b/crypto/block/check-proof.h index e9c43a7..6640281 100644 --- a/crypto/block/check-proof.h +++ b/crypto/block/check-proof.h @@ -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 transaction; @@ -74,21 +75,12 @@ struct TransactionList { td::BufferSlice transactions_boc; struct Info { + ton::LogicalTime lt; + ton::Bits256 hash; std::vector transactions; }; td::Result validate() const; }; -struct BlockChain { - ton::BlockIdExt from; - ton::BlockIdExt to; - td::int32 mode; - td::BufferSlice proof; - - using Info = std::unique_ptr; - - td::Result validate() const; -}; - } // namespace block diff --git a/tdutils/td/utils/filesystem.cpp b/tdutils/td/utils/filesystem.cpp index 9ee0cf6..0d6a21a 100644 --- a/tdutils/td/utils/filesystem.cpp +++ b/tdutils/td/utils/filesystem.cpp @@ -53,17 +53,20 @@ SecureString create_empty(size_t size) { template Result 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(narrow_cast(size)); TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset)); if (got_size != static_cast(size)) { diff --git a/third-party/wingetopt/CMakeLists.txt b/third-party/wingetopt/CMakeLists.txt index 3700633..415f5e6 100644 --- a/third-party/wingetopt/CMakeLists.txt +++ b/third-party/wingetopt/CMakeLists.txt @@ -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 $) diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index e17c235..9535f05 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -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.Transaction; -raw.transactions transactions:vector = raw.Transactions; +raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; +raw.transactions transactions:vector 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; diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index 4971c24f989c589eca985cd0277f47494727e155..7d87ccac80f8c60377aeecb6efe0bc2109fd84ef 100644 GIT binary patch delta 1119 zcmb7D&ui0Q7*5(RU2W}>wb8ZPIwzYlq0Gt()`2jnKPHU%qo|i+$=ax4F{w%Fe&9tN z(u>&cQ#|b8LH__H6GVz^Fx+Ja4~i%gM=1kA#gls2!MtDEx+w_DC12jW@AJOT^FH6N z#PSJWWp@7nReQQizMpuG=5dg&k~inbqT`8yB|PCMdsps{JaV1QWd%blsUaM5E}}N` zRy$sI7Et*|OK1lG zH>o*8QWYJ}?_c?cow(#VIoQ7TXi|LFY%cDYOOiy1_wX`A{aBd*Noq zyQe<8mT*NNM#lZ(c^rdrLwPc8QdF|Tk|8EV?V6~a&WqY4MZte)>97!>p+m}2c%J9+ zY74?EYzI!UZUjl@wAW4BREyhX!e_=O+XQpg0eG3KzI*g;kb~2N@jfAwQS*wCG%T$w zc!)zQ20!Jy34WQq9EGMHeNxG!^M-T<@+b-zd|SG4i6&nZRc8eVW|ZrpSU&D`FfC-2sg}{PE+U|aw#Q=EW!^~9cKY(XMJue&o17t=gEiLg# zXCLM|slzI C{(ijx delta 601 zcmX@(`NNs_(QJJy1}IRP$oqX_iO6IL#wQ?3fGLIL=d8V_Cs#1-nH<4U^QTwwak}ovJGnv%c6G{os-wF>M*Kq zzR7x=MHFNbdwxMlW`15Vh<)>zkPp-3tz7<-C$Moq>~Y~#9YGaFS&)1AixSKA zN{SNmiW8GTjsS^)+`u}SkwYA+k7e=+VV%hfL|7)@5vni*selE|RXMI0kY@$ZOeqE` z0EvT4Vw~J6Y^;H-tH_y6hr_n*AV>wWNnq~?h)8gP7$B|8lMO}kL5>yyi6AQlhvx&J zQV;`0DI|0jh*m&?T1HHQ6BOnUml%pDPZp5o;01}mjFaAcRE(J&64VOv3X`A6J%I$C zjFbh0!J(i6iBbcF6fk4+422v<379KE2En`p65A}J()).ensure(); - sync_send(client, make_object(make_object("", "."))).ensure_error(); + sync_send(client, make_object(make_object("", ".", false))).ensure_error(); } { Client client; sync_send(client, make_object(nullptr)).ensure_error(); - sync_send(client, make_object(make_object("fdajkfldsjkafld", "."))) + sync_send(client, make_object(make_object("fdajkfldsjkafld", ".", false))) .ensure_error(); - sync_send(client, make_object(make_object("", "fdhskfds"))).ensure_error(); - sync_send(client, make_object(make_object("", "."))).ensure(); - sync_send(client, make_object(make_object("", "."))).ensure_error(); + sync_send(client, make_object(make_object("", "fdhskfds", false))) + .ensure_error(); + sync_send(client, make_object(make_object("", ".", false))).ensure(); + sync_send(client, make_object(make_object("", ".", false))).ensure_error(); td::Slice bad_config = R"abc( { @@ -194,7 +195,7 @@ TEST(Tonlib, InitClose) { sync_send(client, make_object()).ensure_error(); sync_send(client, make_object()).ensure(); sync_send(client, make_object()).ensure_error(); - sync_send(client, make_object(make_object("", "."))).ensure_error(); + sync_send(client, make_object(make_object("", ".", false))).ensure_error(); } } @@ -289,7 +290,7 @@ TEST(Tonlib, KeysApi) { Client client; // init - sync_send(client, make_object(make_object("", "."))).ensure(); + sync_send(client, make_object(make_object("", ".", false))).ensure(); auto local_password = td::SecureString("local password"); auto mnemonic_password = td::SecureString("mnemonic password"); { diff --git a/tonlib/test/online.cpp b/tonlib/test/online.cpp index 89a9eaa..8f5a73e 100644 --- a/tonlib/test/online.cpp +++ b/tonlib/test/online.cpp @@ -170,12 +170,12 @@ void dump_transaction_history(Client& client, std::string address) { make_object(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(make_object(global_config_str, "."))).ensure(); + sync_send(client, make_object(make_object(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(make_object(global_config_str, "."))).ensure(); + sync_send(client, make_object(make_object(global_config_str, ".", false))) + .ensure(); auto key = sync_send(client, make_object( td::SecureString("local"), td::SecureString("mnemonic"), td::SecureString())) diff --git a/tonlib/tonlib/ExtClient.cpp b/tonlib/tonlib/ExtClient.cpp index 56ba747..5633363 100644 --- a/tonlib/tonlib/ExtClient.cpp +++ b/tonlib/tonlib/ExtClient.cpp @@ -21,10 +21,10 @@ #include "tonlib/LastBlock.h" namespace tonlib { -void ExtClient::with_last_block(td::Promise promise) { +void ExtClient::with_last_block(td::Promise promise) { auto query_id = last_block_queries_.create(std::move(promise)); - td::Promise P = [query_id, self = this, - actor_id = td::actor::actor_id()](td::Result result) { + td::Promise P = [query_id, self = this, + actor_id = td::actor::actor_id()](td::Result 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)); }); diff --git a/tonlib/tonlib/ExtClient.h b/tonlib/tonlib/ExtClient.h index bacc473..8f92ea9 100644 --- a/tonlib/tonlib/ExtClient.h +++ b/tonlib/tonlib/ExtClient.h @@ -29,6 +29,7 @@ namespace tonlib { class LastBlock; +struct LastBlockInfo; struct ExtClientRef { td::actor::ActorId andl_ext_client_; td::actor::ActorId last_block_actor_; @@ -49,7 +50,7 @@ class ExtClient { return client_; } - void with_last_block(td::Promise promise); + void with_last_block(td::Promise promise); template void send_query(QueryT query, td::Promise promise) { @@ -74,7 +75,7 @@ class ExtClient { private: ExtClientRef client_; td::Container> queries_; - td::Container> last_block_queries_; + td::Container> last_block_queries_; void send_raw_query(td::BufferSlice query, td::Promise promise); }; diff --git a/tonlib/tonlib/LastBlock.cpp b/tonlib/tonlib/LastBlock.cpp index 16eb3eb..f475402 100644 --- a/tonlib/tonlib/LastBlock.cpp +++ b/tonlib/tonlib/LastBlock.cpp @@ -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) + : state_(std::move(state)), callback_(std::move(callback)) { client_.set_client(client); - parent_ = std::move(parent); } -void LastBlock::get_last_block(td::Promise promise) { +void LastBlock::get_last_block(td::Promise promise) { if (promises_.empty()) { do_get_last_block(); } @@ -39,13 +36,16 @@ void LastBlock::get_last_block(td::Promise 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 LastBlock::process_block_proof( @@ -60,6 +60,12 @@ td::Result 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> 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 diff --git a/tonlib/tonlib/LastBlock.h b/tonlib/tonlib/LastBlock.h index 79a6527..968f21b 100644 --- a/tonlib/tonlib/LastBlock.h +++ b/tonlib/tonlib/LastBlock.h @@ -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 promise); + class Callback { + public: + virtual ~Callback() { + } + virtual void on_state_changes(State state) = 0; + }; + + explicit LastBlock(ExtClientRef client, State state, td::unique_ptr callback); + void get_last_block(td::Promise promise); private: ExtClient client_; - ton::ZeroStateIdExt zero_state_id_; - ton::BlockIdExt mc_last_block_id_; + State state_; + td::unique_ptr callback_; - std::vector> promises_; - - td::actor::ActorShared<> parent_; + std::vector> promises_; void do_get_last_block(); void on_masterchain_info(td::Result> 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 diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 489abb6..7b48876 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -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 code; td::Ref data; block::AccountState::Info info; + td::int64 sync_utime = 0; }; td::Result to_balance_or_throw(td::Ref balance_ref) { @@ -169,7 +171,7 @@ class GetRawAccountState : public td::actor::Actor { block::StdAddress address_; td::Promise promise_; ExtClient client_; - ton::BlockIdExt last_block_; + LastBlockInfo last_block_; void with_account_state(td::Result> 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> 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 r_last_block) { + client_.with_last_block([self = this](td::Result 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( 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(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(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 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 parent_; + }; + ref_cnt_++; + auto client = ExtClientOutbound::create(td::make_unique(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(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(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 client) : client_(std::move(client)) { + } + void on_state_changes(LastBlock::State state) override { + //TODO } private: - td::actor::ActorShared<> parent_; + td::actor::ActorShared client_; }; - ref_cnt_++; - raw_client_ = ExtClientLazy::create(lite_client.adnl_id, lite_client.address, - td::make_unique(td::actor::actor_shared())); - ref_cnt_++; - raw_last_block_ = td::actor::create_actor( - "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", get_client_ref(), std::move(state), + td::make_unique(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()); return td::Status::OK(); } + td::Status TonlibClient::do_request(const tonlib_api::options_setConfig& request, td::Promise>&& 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 empty_transaction_id() { + return tonlib_api::make_object(0, std::string(32, 0)); +} + tonlib_api::object_ptr to_transaction_id(const block::AccountState::Info& info) { return tonlib_api::make_object(info.last_trans_lt, info.last_trans_hash.as_slice().str()); @@ -482,7 +532,7 @@ td::Result> to_raw_accountS .str(); } return tonlib_api::make_object(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 to_std_address_or_throw(td::Ref cs) { @@ -591,7 +641,7 @@ td::Result> to_raw_transacti } } return tonlib_api::make_object( - data, + info.now, data, tonlib_api::make_object(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> 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(std::move(transactions)); + + auto transaction_id = + tonlib_api::make_object(info.lt, info.hash.as_slice().str()); + for (auto& transaction : transactions) { + std::swap(transaction->transaction_id_, transaction_id); + } + + return tonlib_api::make_object(std::move(transactions), std::move(transaction_id)); } td::Result> to_testWallet_accountState( @@ -622,8 +679,8 @@ td::Result> to_testW if (seqno == cs.fetch_ulong_eof) { return td::Status::Error("Failed to parse seq_no"); } - return tonlib_api::make_object(raw_state.balance, static_cast(seqno), - to_transaction_id(raw_state.info)); + return tonlib_api::make_object( + raw_state.balance, static_cast(seqno), to_transaction_id(raw_state.info), raw_state.sync_utime); } td::Result> to_testGiver_accountState( @@ -637,15 +694,16 @@ td::Result> to_testGi if (seqno == cs.fetch_ulong_eof) { return td::Status::Error("Failed to parse seq_no"); } - return tonlib_api::make_object(raw_state.balance, static_cast(seqno), - to_transaction_id(raw_state.info)); + return tonlib_api::make_object( + raw_state.balance, static_cast(seqno), to_transaction_id(raw_state.info), raw_state.sync_utime); } td::Result> to_generic_accountState( RawAccountState&& raw_state) { if (raw_state.code.is_null()) { return tonlib_api::make_object( - tonlib_api::make_object(raw_state.balance)); + tonlib_api::make_object(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>&& promise) { + send_closure(ext_client_outbound_, &ExtClientOutbound::on_query_result, request.id_, td::BufferSlice(request.bytes_), + [promise = std::move(promise)](td::Result res) mutable { + if (res.is_ok()) { + promise.set_value(tonlib_api::make_object()); + } else { + promise.set_error(res.move_as_error()); + } + }); + return td::Status::OK(); +} +td::Status TonlibClient::do_request(const tonlib_api::onLiteServerQueryError& request, + td::Promise>&& 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 res) mutable { + if (res.is_ok()) { + promise.set_value(tonlib_api::make_object()); + } else { + promise.set_error(res.move_as_error()); + } + }); + return td::Status::OK(); +} + } // namespace tonlib diff --git a/tonlib/tonlib/TonlibClient.h b/tonlib/tonlib/TonlibClient.h index 244506c..0e36a28 100644 --- a/tonlib/tonlib/TonlibClient.h +++ b/tonlib/tonlib/TonlibClient.h @@ -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 callback_; Config config_; + bool use_callbacks_for_network_{false}; + td::actor::ActorId 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>&& promise); + + td::Status do_request(const tonlib_api::onLiteServerQueryResult& request, + td::Promise>&& promise); + td::Status do_request(const tonlib_api::onLiteServerQueryError& request, + td::Promise>&& promise); + + void proxy_request(td::int64 query_id, std::string data); }; } // namespace tonlib diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index 8de1133..cdbec51 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -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 #include @@ -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>> query_handlers_; + td::actor::ActorOwn 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(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(td::actor::actor_shared())); + } + using tonlib_api::make_object; - send_query(make_object(make_object(options_.config, options_.key_dir)), + send_query(make_object(make_object(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 - set lite server config\n"; td::TerminalIO::out() << "getstate - get state of simple wallet with requested key\n"; + td::TerminalIO::out() + << "gethistory - get history fo simple wallet with requested key (last 10 transactions)\n"; td::TerminalIO::out() << "init - init simple wallet with requested key\n"; td::TerminalIO::out() << "transfer - transfer of grams from " " to .\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 res) { + using tonlib_api::make_object; + if (res.is_ok()) { + send_query(make_object(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( + id, make_object(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 result) { + if (id == 0) { + if (result->get_id() == tonlib_api::updateSendLiteServerQuery::ID) { + auto update = tonlib_api::move_object_as(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 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( + ton::move_tl_object_as(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 transaction_id; + downcast_call(state, [&](auto& state) { transaction_id = std::move(state.account_state_->last_transaction_id_); }); + + send_query( + tonlib_api::make_object( + ton::move_tl_object_as(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()) { diff --git a/validator/db/filedb.cpp b/validator/db/filedb.cpp index 57dc057..6e20998 100644 --- a/validator/db/filedb.cpp +++ b/validator/db/filedb.cpp @@ -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 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 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("readfile", get_file_name(ref_id, false), offset, max_size, std::move(P)) .release();