mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	New liteserver config format
* Specify shards and seqno/utime/lt limits for liteservers in global config * Support in lite-client, tonlib, blockchain-explorer * Rework proxy-liteserver
This commit is contained in:
		
							parent
							
								
									38ab70c037
								
							
						
					
					
						commit
						007f1fb1d7
					
				
					 26 changed files with 1187 additions and 1130 deletions
				
			
		|  | @ -43,7 +43,6 @@ | |||
| #include "block/block-auto.h" | ||||
| #include "crypto/vm/utils.h" | ||||
| #include "td/utils/crypto.h" | ||||
| #include "lite-client/QueryTraits.h" | ||||
| 
 | ||||
| #include "vm/boc.h" | ||||
| #include "vm/cellops.h" | ||||
|  | @ -212,7 +211,8 @@ void HttpQueryBlockData::finish_query() { | |||
| } | ||||
| 
 | ||||
| void HttpQueryBlockData::start_up() { | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)); | ||||
|   auto query = ton::serialize_tl_object( | ||||
|       ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true); | ||||
| 
 | ||||
|   auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|     if (R.is_error()) { | ||||
|  | @ -223,7 +223,7 @@ void HttpQueryBlockData::start_up() { | |||
|   }); | ||||
| 
 | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryBlockData::got_block_data(td::BufferSlice data) { | ||||
|  | @ -274,7 +274,8 @@ void HttpQueryBlockView::finish_query() { | |||
| } | ||||
| 
 | ||||
| void HttpQueryBlockView::start_up_query() { | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)); | ||||
|   auto query = ton::serialize_tl_object( | ||||
|       ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true); | ||||
| 
 | ||||
|   auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|     if (R.is_error()) { | ||||
|  | @ -285,7 +286,7 @@ void HttpQueryBlockView::start_up_query() { | |||
|   }); | ||||
| 
 | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryBlockView::got_block_data(td::BufferSlice data) { | ||||
|  | @ -321,10 +322,11 @@ void HttpQueryBlockInfo::start_up_query() { | |||
|       td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_block_header, R.move_as_ok()); | ||||
|     } | ||||
|   }); | ||||
|   auto query = | ||||
|       ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(block_id_), 0); | ||||
|   auto query = ton::serialize_tl_object( | ||||
|       ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(block_id_), 0), | ||||
|       true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
|   pending_queries_ = 1; | ||||
| 
 | ||||
|   if (block_id_.is_masterchain()) { | ||||
|  | @ -336,15 +338,16 @@ void HttpQueryBlockInfo::start_up_query() { | |||
|         td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_shard_info, R.move_as_ok()); | ||||
|       } | ||||
|     }); | ||||
|     auto query_2 = | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)); | ||||
|     auto query_2 = ton::serialize_tl_object( | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)), | ||||
|         true); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query_2, true), liteclient::get_query_shard(*query_2), | ||||
|                             std::move(P_2)); | ||||
|                             std::move(query_2), std::move(P_2)); | ||||
|     pending_queries_++; | ||||
|   } | ||||
|   auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|       ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false); | ||||
|   auto query_3 = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|                                               ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false), | ||||
|                                           true); | ||||
|   auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|     if (R.is_error()) { | ||||
|       td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: ")); | ||||
|  | @ -353,8 +356,7 @@ void HttpQueryBlockInfo::start_up_query() { | |||
|     } | ||||
|   }); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), | ||||
|                           std::move(P_3)); | ||||
|                           std::move(query_3), std::move(P_3)); | ||||
|   pending_queries_++; | ||||
| } | ||||
| 
 | ||||
|  | @ -407,9 +409,11 @@ void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) { | |||
| 
 | ||||
|   if (f->incomplete_ && transactions_.size() > 0) { | ||||
|     const auto &T = *transactions_.rbegin(); | ||||
|     auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|         ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false); | ||||
|     auto query_3 = ton::serialize_tl_object( | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|             ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, | ||||
|             ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false), | ||||
|         true); | ||||
|     auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|       if (R.is_error()) { | ||||
|         td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: ")); | ||||
|  | @ -418,8 +422,7 @@ void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) { | |||
|       } | ||||
|     }); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), | ||||
|                             std::move(P_3)); | ||||
|                             std::move(query_3), std::move(P_3)); | ||||
|   } else { | ||||
|     if (!--pending_queries_) { | ||||
|       finish_query(); | ||||
|  | @ -539,13 +542,14 @@ void HttpQueryBlockSearch::start_up_query() { | |||
|       td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_block_header, R.move_as_ok()); | ||||
|     } | ||||
|   }); | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>( | ||||
|       mode_, | ||||
|       ton::create_tl_lite_block_id_simple( | ||||
|           ton::BlockId{account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}), | ||||
|       lt_, utime_); | ||||
|   auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>( | ||||
|                                             mode_, | ||||
|                                             ton::create_tl_lite_block_id_simple(ton::BlockId{ | ||||
|                                                 account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}), | ||||
|                                             lt_, utime_), | ||||
|                                         true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) { | ||||
|  | @ -567,16 +571,17 @@ void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) { | |||
|         td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_shard_info, R.move_as_ok()); | ||||
|       } | ||||
|     }); | ||||
|     auto query_2 = | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)); | ||||
|     auto query_2 = ton::serialize_tl_object( | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)), | ||||
|         true); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query_2, true), liteclient::get_query_shard(*query_2), | ||||
|                             std::move(P_2)); | ||||
|                             std::move(query_2), std::move(P_2)); | ||||
|     pending_queries_++; | ||||
|   } | ||||
| 
 | ||||
|   auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|       ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false); | ||||
|   auto query_3 = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|                                               ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false), | ||||
|                                           true); | ||||
|   auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|     if (R.is_error()) { | ||||
|       td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, R.move_as_error_prefix("litequery failed: ")); | ||||
|  | @ -585,8 +590,7 @@ void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) { | |||
|     } | ||||
|   }); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), | ||||
|                           std::move(P_3)); | ||||
|                           std::move(query_3), std::move(P_3)); | ||||
|   pending_queries_++; | ||||
| } | ||||
| 
 | ||||
|  | @ -626,9 +630,11 @@ void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) { | |||
| 
 | ||||
|   if (f->incomplete_ && transactions_.size() > 0) { | ||||
|     const auto &T = *transactions_.rbegin(); | ||||
|     auto query_3 = ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|         ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false); | ||||
|     auto query_3 = ton::serialize_tl_object( | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>( | ||||
|             ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, | ||||
|             ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false), | ||||
|         true); | ||||
|     auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|       if (R.is_error()) { | ||||
|         td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, | ||||
|  | @ -638,8 +644,7 @@ void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) { | |||
|       } | ||||
|     }); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), | ||||
|                             std::move(P_3)); | ||||
|                             std::move(query_3), std::move(P_3)); | ||||
|   } else { | ||||
|     if (!--pending_queries_) { | ||||
|       finish_query(); | ||||
|  | @ -727,10 +732,11 @@ void HttpQueryViewAccount::start_up_query() { | |||
|     } | ||||
|   }); | ||||
|   auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr); | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(ton::create_tl_lite_block_id(block_id_), | ||||
|                                                                                 std::move(a)); | ||||
|   auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>( | ||||
|                                             ton::create_tl_lite_block_id(block_id_), std::move(a)), | ||||
|                                         true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryViewAccount::got_account(td::BufferSlice data) { | ||||
|  | @ -823,9 +829,10 @@ void HttpQueryViewTransaction::start_up_query() { | |||
|     } | ||||
|   }); | ||||
|   auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr); | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(1, std::move(a), lt_, hash_); | ||||
|   auto query = ton::serialize_tl_object( | ||||
|       ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(1, std::move(a), lt_, hash_), true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryViewTransaction::got_transaction(td::BufferSlice data) { | ||||
|  | @ -913,10 +920,11 @@ void HttpQueryViewTransaction2::start_up_query() { | |||
|     } | ||||
|   }); | ||||
|   auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr); | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>( | ||||
|       ton::create_tl_lite_block_id(block_id_), std::move(a), lt_); | ||||
|   auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>( | ||||
|                                             ton::create_tl_lite_block_id(block_id_), std::move(a), lt_), | ||||
|                                         true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryViewTransaction2::got_transaction(td::BufferSlice data) { | ||||
|  | @ -975,9 +983,9 @@ void HttpQueryViewLastBlock::start_up() { | |||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(); | ||||
|   auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryViewLastBlock::got_result(td::BufferSlice data) { | ||||
|  | @ -1041,9 +1049,9 @@ void HttpQueryConfig::start_up() { | |||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(); | ||||
|     auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                             std::move(query), std::move(P)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -1067,17 +1075,16 @@ void HttpQueryConfig::send_main_query() { | |||
|       td::actor::send_closure(SelfId, &HttpQueryConfig::got_result, R.move_as_ok()); | ||||
|     } | ||||
|   }); | ||||
|   if (params_.size() > 0) { | ||||
|     auto query = ton::create_tl_object<ton::lite_api::liteServer_getConfigParams>( | ||||
|         0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(params_)); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|   } else { | ||||
|     auto query = | ||||
|         ton::create_tl_object<ton::lite_api::liteServer_getConfigAll>(0, ton::create_tl_lite_block_id(block_id_)); | ||||
|     td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                             ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|   } | ||||
|   auto query = | ||||
|       params_.size() > 0 | ||||
|           ? ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigParams>( | ||||
|                                          0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(params_)), | ||||
|                                      true) | ||||
|           : ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigAll>( | ||||
|                                          0, ton::create_tl_lite_block_id(block_id_)), | ||||
|                                      true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryConfig::got_result(td::BufferSlice data) { | ||||
|  | @ -1219,9 +1226,10 @@ void HttpQuerySend::start_up() { | |||
|       td::actor::send_closure(SelfId, &HttpQuerySend::got_result, R.move_as_ok()); | ||||
|     } | ||||
|   }); | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(std::move(data_)); | ||||
|   auto query = | ||||
|       ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(std::move(data_)), true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQuerySend::got_result(td::BufferSlice data) { | ||||
|  | @ -1327,10 +1335,12 @@ void HttpQueryRunMethod::start_up_query() { | |||
|     return abort_query(params_serialized.move_as_error_prefix("cannot serialize stack with get-method parameters : ")); | ||||
|   } | ||||
| 
 | ||||
|   auto query = ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>( | ||||
|       0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()); | ||||
|   auto query = ton::serialize_tl_object( | ||||
|       ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>( | ||||
|           0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()), | ||||
|       true); | ||||
|   td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, | ||||
|                           ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); | ||||
|                           std::move(query), std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void HttpQueryRunMethod::got_result(td::BufferSlice data) { | ||||
|  |  | |||
|  | @ -155,8 +155,6 @@ class CoreActor : public CoreActorInterface { | |||
|   td::int32 attempt_ = 0; | ||||
|   td::int32 waiting_ = 0; | ||||
| 
 | ||||
|   std::vector<bool> ready_; | ||||
| 
 | ||||
|   //void run_queries();
 | ||||
|   void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data); | ||||
| 
 | ||||
|  | @ -189,12 +187,6 @@ class CoreActor : public CoreActorInterface { | |||
|   static CoreActor* instance_; | ||||
|   td::actor::ActorId<CoreActor> self_id_; | ||||
| 
 | ||||
|   void conn_ready(td::uint32 idx) { | ||||
|     ready_.at(idx) = true; | ||||
|   } | ||||
|   void conn_closed(td::uint32 idx) { | ||||
|     ready_.at(idx) = false; | ||||
|   } | ||||
|   void set_global_config(std::string str) { | ||||
|     global_config_ = str; | ||||
|   } | ||||
|  | @ -219,7 +211,7 @@ class CoreActor : public CoreActorInterface { | |||
|     hide_ips_ = value; | ||||
|   } | ||||
| 
 | ||||
|   void send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) override; | ||||
|   void send_lite_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) override; | ||||
|   void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) override { | ||||
|   } | ||||
|   void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) override { | ||||
|  | @ -439,50 +431,24 @@ class CoreActor : public CoreActorInterface { | |||
|   } | ||||
| 
 | ||||
|   void run() { | ||||
|     std::vector<liteclient::ExtClient::LiteServer> servers; | ||||
|     std::vector<liteclient::LiteServerConfig> servers; | ||||
|     if (remote_public_key_.empty()) { | ||||
|       auto G = td::read_file(global_config_).move_as_ok(); | ||||
|       auto gc_j = td::json_decode(G.as_slice()).move_as_ok(); | ||||
|       ton::ton_api::liteclient_config_global gc; | ||||
|       ton::ton_api::from_json(gc, gc_j.get_object()).ensure(); | ||||
| 
 | ||||
|       size_t size = gc.liteservers_.size() + gc.liteservers_v2_.size(); | ||||
|       CHECK(size > 0); | ||||
|       ready_.resize(size, false); | ||||
| 
 | ||||
|       for (auto& s : gc.liteservers_) { | ||||
|         td::IPAddress addr; | ||||
|         addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); | ||||
|         addrs_.push_back(addr); | ||||
|         liteclient::ExtClient::LiteServer serv; | ||||
|         serv.address = addr; | ||||
|         serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); | ||||
|         servers.push_back(std::move(serv)); | ||||
|       } | ||||
|       for (auto& s : gc.liteservers_v2_) { | ||||
|         td::IPAddress addr; | ||||
|         addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); | ||||
|         addrs_.push_back(addr); | ||||
|         liteclient::ExtClient::LiteServer serv; | ||||
|         serv.address = addr; | ||||
|         serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); | ||||
|         serv.is_full = false; | ||||
|         for (auto& shard : s->shards_) { | ||||
|           serv.shards.emplace_back(shard->workchain_, (ton::ShardId)shard->shard_); | ||||
|           CHECK(serv.shards.back().is_valid_ext()); | ||||
|         } | ||||
|         servers.push_back(std::move(serv)); | ||||
|       auto r_servers = liteclient::LiteServerConfig::parse_global_config(gc); | ||||
|       r_servers.ensure(); | ||||
|       servers = r_servers.move_as_ok(); | ||||
|       for (const auto& serv : servers) { | ||||
|         addrs_.push_back(serv.addr); | ||||
|       } | ||||
|     } else { | ||||
|       if (!remote_addr_.is_valid()) { | ||||
|         LOG(FATAL) << "remote addr not set"; | ||||
|       } | ||||
|       ready_.resize(1, false); | ||||
|       addrs_.push_back(remote_addr_); | ||||
|       liteclient::ExtClient::LiteServer serv; | ||||
|       serv.address = remote_addr_; | ||||
|       serv.adnl_id = ton::adnl::AdnlNodeIdFull{remote_public_key_}; | ||||
|       servers.push_back(std::move(serv)); | ||||
|       servers.push_back(liteclient::LiteServerConfig{ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_}); | ||||
|     } | ||||
|     client_ = liteclient::ExtClient::create(std::move(servers), make_callback()); | ||||
|     daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast<td::uint16>(http_port_), nullptr, nullptr, | ||||
|  | @ -545,7 +511,7 @@ void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result<td::Buf | |||
|   } | ||||
| }*/ | ||||
| 
 | ||||
| void CoreActor::send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) { | ||||
| void CoreActor::send_lite_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) { | ||||
|   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()); | ||||
|  | @ -563,7 +529,7 @@ void CoreActor::send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, t | |||
|     promise.set_value(std::move(B)); | ||||
|   }); | ||||
|   auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query)); | ||||
|   td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", serialize_tl_object(q, true), shard, | ||||
|   td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", serialize_tl_object(q, true), | ||||
|                           td::Timestamp::in(10.0), std::move(P)); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ class CoreActorInterface : public td::actor::Actor { | |||
|   }; | ||||
|   virtual ~CoreActorInterface() = default; | ||||
| 
 | ||||
|   virtual void send_lite_query(td::BufferSlice data, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) = 0; | ||||
|   virtual void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0; | ||||
|   virtual void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) = 0; | ||||
|   virtual void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) = 0; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| cmake_minimum_required(VERSION 3.5 FATAL_ERROR) | ||||
| 
 | ||||
| add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h ext-client.cpp ext-client.h QueryTraits.h) | ||||
| target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block) | ||||
| add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h ext-client.cpp ext-client.h | ||||
|   query-utils.hpp query-utils.cpp) | ||||
| target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto | ||||
|   ton_block) | ||||
| 
 | ||||
| add_executable(lite-client lite-client.cpp lite-client.h ext-client.h ext-client.cpp) | ||||
| target_link_libraries(lite-client tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block | ||||
|  |  | |||
|  | @ -1,229 +0,0 @@ | |||
| /*
 | ||||
|     This file is part of TON Blockchain Library. | ||||
| 
 | ||||
|     TON Blockchain Library is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Lesser General Public License as published by | ||||
|     the Free Software Foundation, either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     TON Blockchain Library is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU Lesser General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU Lesser General Public License | ||||
|     along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| #pragma once | ||||
| #include "ton/ton-types.h" | ||||
| #include "auto/tl/lite_api.h" | ||||
| #include "auto/tl/lite_api.hpp" | ||||
| #include "vm/boc.h" | ||||
| #include "vm/cellslice.h" | ||||
| #include "block/block-auto.h" | ||||
| #include "block/block-parse.h" | ||||
| #include "auto/tl/lite_api.hpp" | ||||
| 
 | ||||
| namespace liteclient { | ||||
| 
 | ||||
| template <typename Query> | ||||
| struct QueryTraits { | ||||
|   static ton::ShardIdFull get_shard(const Query& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getMasterchainInfo> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfo& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getMasterchainInfoExt> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfoExt& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getTime> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTime& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getVersion> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getVersion& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getBlock> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlock& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getState> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getState& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getBlockHeader> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockHeader& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_sendMessage> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_sendMessage& q) { | ||||
|     auto shard = [&]() -> td::Result<ton::ShardIdFull> { | ||||
|       vm::BagOfCells boc; | ||||
|       TRY_STATUS(boc.deserialize(q.body_.as_slice())); | ||||
|       if (boc.get_root_count() != 1) { | ||||
|         return td::Status::Error("external message is not a valid bag of cells"); | ||||
|       } | ||||
|       block::gen::CommonMsgInfo::Record_ext_in_msg_info info; | ||||
|       if (!tlb::unpack_cell_inexact(boc.get_root_cell(), info)) { | ||||
|         return td::Status::Error("cannot unpack external message header"); | ||||
|       } | ||||
|       auto dest_prefix = block::tlb::t_MsgAddressInt.get_prefix(info.dest); | ||||
|       if (!dest_prefix.is_valid()) { | ||||
|         return td::Status::Error("destination of an inbound external message is an invalid blockchain address"); | ||||
|       } | ||||
|       return dest_prefix.as_leaf_shard(); | ||||
|     }(); | ||||
|     if (shard.is_error()) { | ||||
|       LOG(DEBUG) << "Failed to get shard from query liteServer.sendMessage: " << shard.move_as_error(); | ||||
|       return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|     } | ||||
|     return shard.move_as_ok(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getAccountState> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAccountState& q) { | ||||
|     return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getAccountStatePrunned> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAccountStatePrunned& q) { | ||||
|     return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_runSmcMethod> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_runSmcMethod& q) { | ||||
|     return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getShardInfo> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardInfo& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getAllShardsInfo> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAllShardsInfo& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getOneTransaction> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getOneTransaction& q) { | ||||
|     return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getTransactions> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTransactions& q) { | ||||
|     return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_lookupBlock> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_lookupBlock& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_listBlockTransactions> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactions& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_listBlockTransactionsExt> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactionsExt& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getBlockProof> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockProof& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getConfigAll> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigAll& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getConfigParams> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigParams& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getValidatorStats> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getValidatorStats& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getLibraries> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getLibraries& q) { | ||||
|     return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
| struct QueryTraits<ton::lite_api::liteServer_getShardBlockProof> { | ||||
|   static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardBlockProof& q) { | ||||
|     return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template<typename Query> | ||||
| inline ton::ShardIdFull get_query_shard(const Query& q) { | ||||
|   return QueryTraits<Query>::get_shard(q); | ||||
| } | ||||
| 
 | ||||
| }  // namespace tonlib
 | ||||
|  | @ -17,92 +17,75 @@ | |||
| #include "ext-client.h" | ||||
| #include "td/utils/Random.h" | ||||
| #include "ton/ton-shard.h" | ||||
| #include <map> | ||||
| 
 | ||||
| namespace liteclient { | ||||
| 
 | ||||
| class ExtClientImpl : public ExtClient { | ||||
|  public: | ||||
|   ExtClientImpl(std::vector<LiteServer> servers, td::unique_ptr<ExtClient::Callback> callback) | ||||
|   ExtClientImpl(std::vector<LiteServerConfig> liteservers, td::unique_ptr<Callback> callback) | ||||
|       : callback_(std::move(callback)) { | ||||
|     CHECK(!servers.empty()); | ||||
|     servers_.resize(servers.size()); | ||||
|     CHECK(!liteservers.empty()); | ||||
|     servers_.resize(liteservers.size()); | ||||
|     for (size_t i = 0; i < servers_.size(); ++i) { | ||||
|       servers_[i].s = std::move(servers[i]); | ||||
|       if (!servers_[i].s.is_full) { | ||||
|         for (auto shard : servers_[i].s.shards) { | ||||
|           CHECK(shard.is_valid_ext()); | ||||
|           max_server_shard_depth_ = std::max(max_server_shard_depth_, shard.pfx_len()); | ||||
|         } | ||||
|       } | ||||
|       servers_[i].config = std::move(liteservers[i]); | ||||
|       servers_[i].idx = i; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void start_up() override { | ||||
|     LOG(INFO) << "Started ext client, " << servers_.size() << " liteservers"; | ||||
|     td::Random::Fast rnd; | ||||
|     td::random_shuffle(td::as_mutable_span(servers_), rnd); | ||||
|   } | ||||
| 
 | ||||
|   void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout, | ||||
|   void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, | ||||
|                   td::Promise<td::BufferSlice> promise) override { | ||||
|     TRY_RESULT_PROMISE(promise, server_idx, before_query(shard)); | ||||
|     QueryInfo query_info = get_query_info(data); | ||||
|     TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info)); | ||||
|     auto& server = servers_[server_idx]; | ||||
|     CHECK(!server.client.empty()); | ||||
|     alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT)); | ||||
|     td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), server_idx, | ||||
|         promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable { | ||||
|                                       promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable { | ||||
|       if (R.is_error() && | ||||
|           (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) { | ||||
|         td::actor::send_closure(SelfId, &ExtClientImpl::set_server_bad, server_idx); | ||||
|         td::actor::send_closure(SelfId, &ExtClientImpl::on_server_error, server_idx); | ||||
|       } | ||||
|       promise.set_result(std::move(R)); | ||||
|     }; | ||||
|     LOG(DEBUG) << "Sending query " << query_info.to_str() << " to server #" << server.idx << " (" | ||||
|                << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")"; | ||||
|     send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout, | ||||
|                  std::move(P)); | ||||
|   } | ||||
| 
 | ||||
|   void force_change_liteserver() override { | ||||
|     if (servers_.size() == 1) { | ||||
|       return; | ||||
|     } | ||||
|     auto it = shard_to_server_.find(ton::ShardIdFull(ton::masterchainId)); | ||||
|     if (it != shard_to_server_.end()) { | ||||
|       set_server_bad(it->second); | ||||
|   void reset_servers() override { | ||||
|     LOG(INFO) << "Force resetting all liteservers"; | ||||
|     for (Server& server : servers_) { | ||||
|       server.alive = false; | ||||
|       server.timeout = {}; | ||||
|       server.ignore_until = {}; | ||||
|       server.client.reset(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   td::Result<size_t> before_query(ton::ShardIdFull shard) { | ||||
|     if (!shard.is_valid_ext()) { | ||||
|       return td::Status::Error("Invalid shard"); | ||||
|     } | ||||
|     if (is_closing_) { | ||||
|       return td::Status::Error("Client is closing"); | ||||
|     } | ||||
|     if (shard.pfx_len() > max_server_shard_depth_) { | ||||
|       shard = shard_prefix(shard, max_server_shard_depth_); | ||||
|     } | ||||
|     auto it = shard_to_server_.find(shard); | ||||
|     if (it != shard_to_server_.end()) { | ||||
|       size_t server_idx = it->second; | ||||
|       if (!servers_[server_idx].client.empty()) { | ||||
|         return server_idx; | ||||
|   td::Result<size_t> select_server(const QueryInfo& query_info) { | ||||
|     for (size_t i = 0; i < servers_.size(); ++i) { | ||||
|       if (servers_[i].alive && servers_[i].config.accepts_query(query_info)) { | ||||
|         return i; | ||||
|       } | ||||
|       shard_to_server_.erase(it); | ||||
|     } | ||||
| 
 | ||||
|     size_t server_idx = servers_.size(); | ||||
|     int cnt = 0; | ||||
|     int best_priority = -1; | ||||
|     for (size_t i = 0; i < servers_.size(); ++i) { | ||||
|       Server& server = servers_[i]; | ||||
|       if (!server.supports(shard)) { | ||||
|       if (!server.config.accepts_query(query_info)) { | ||||
|         continue; | ||||
|       } | ||||
|       int priority = 0; | ||||
|       priority += (server.client.empty() ? 0 : 100); | ||||
|       priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10); | ||||
|       priority += (server.s.is_full ? 1 : 0); | ||||
|       if (priority < best_priority) { | ||||
|         continue; | ||||
|       } | ||||
|  | @ -116,100 +99,76 @@ class ExtClientImpl : public ExtClient { | |||
|       ++cnt; | ||||
|     } | ||||
|     if (server_idx == servers_.size()) { | ||||
|       return td::Status::Error(PSTRING() << "No liteserver for shard " << shard.to_str()); | ||||
|       return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str()); | ||||
|     } | ||||
|     Server& server = servers_[server_idx]; | ||||
|     server.alive = true; | ||||
|     server.ignore_until = {}; | ||||
|     alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT)); | ||||
|     if (!server.client.empty()) { | ||||
|       return server_idx; | ||||
|     } | ||||
| 
 | ||||
|     class Callback : public ton::adnl::AdnlExtClient::Callback { | ||||
|      public: | ||||
|       explicit Callback(td::actor::ActorShared<ExtClientImpl> parent, size_t idx) | ||||
|           : parent_(std::move(parent)), idx_(idx) { | ||||
|       explicit Callback(td::actor::ActorId<ExtClientImpl> parent, size_t idx) : parent_(std::move(parent)), idx_(idx) { | ||||
|       } | ||||
|       void on_ready() override { | ||||
|       } | ||||
|       void on_stop_ready() override { | ||||
|         td::actor::send_closure(parent_, &ExtClientImpl::set_server_bad, idx_); | ||||
|         td::actor::send_closure(parent_, &ExtClientImpl::on_server_error, idx_); | ||||
|       } | ||||
| 
 | ||||
|      private: | ||||
|       td::actor::ActorShared<ExtClientImpl> parent_; | ||||
|       td::actor::ActorId<ExtClientImpl> parent_; | ||||
|       size_t idx_; | ||||
|     }; | ||||
|     ref_cnt_++; | ||||
|     if (shard.is_masterchain()) { | ||||
|       LOG(INFO) << "Connecting to liteserver " << server.s.address << " for masterchain"; | ||||
|     } else { | ||||
|       LOG(INFO) << "Connecting to liteserver " << server.s.address << " for shard " << shard.to_str(); | ||||
|     } | ||||
|     server.client = ton::adnl::AdnlExtClient::create( | ||||
|         server.s.adnl_id, server.s.address, std::make_unique<Callback>(td::actor::actor_shared(this), server_idx)); | ||||
|     alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT)); | ||||
|     LOG(INFO) << "Connecting to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str() << ":" | ||||
|               << server.config.addr.get_port() << ") for query " << query_info.to_str(); | ||||
|     server.client = ton::adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr, | ||||
|                                                      std::make_unique<Callback>(actor_id(this), server_idx)); | ||||
|     return server_idx; | ||||
|   } | ||||
| 
 | ||||
|   struct Server { | ||||
|     LiteServer s; | ||||
|     LiteServerConfig config; | ||||
|     size_t idx = 0; | ||||
|     td::actor::ActorOwn<ton::adnl::AdnlExtClient> client; | ||||
|     bool alive = false; | ||||
|     td::Timestamp timeout = td::Timestamp::never(); | ||||
|     td::Timestamp ignore_until = td::Timestamp::never(); | ||||
| 
 | ||||
|     bool supports(const ton::ShardIdFull& shard) const { | ||||
|       return s.is_full || shard.is_masterchain() || | ||||
|              std::any_of(s.shards.begin(), s.shards.end(), | ||||
|                          [&](const ton::ShardIdFull s_shard) { return ton::shard_intersects(shard, s_shard); }); | ||||
|     } | ||||
|   }; | ||||
|   std::vector<Server> servers_; | ||||
|   std::map<ton::ShardIdFull, size_t> shard_to_server_; | ||||
|   int max_server_shard_depth_ = 0; | ||||
| 
 | ||||
|   td::unique_ptr<ExtClient::Callback> callback_; | ||||
|   static constexpr double MAX_NO_QUERIES_TIMEOUT = 100; | ||||
| 
 | ||||
|   bool is_closing_{false}; | ||||
|   td::uint32 ref_cnt_{1}; | ||||
|   td::unique_ptr<Callback> callback_; | ||||
|   static constexpr double MAX_NO_QUERIES_TIMEOUT = 100.0; | ||||
|   static constexpr double BAD_SERVER_TIMEOUT = 30.0; | ||||
| 
 | ||||
|   void alarm() override { | ||||
|     for (Server& server : servers_) { | ||||
|       if (server.timeout && server.timeout.is_in_past()) { | ||||
|         LOG(INFO) << "Closing connection to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str() | ||||
|                   << ":" << server.config.addr.get_port() << ")"; | ||||
|         server.client.reset(); | ||||
|         server.alive = false; | ||||
|         server.ignore_until = {}; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   void set_server_bad(size_t idx) { | ||||
|     servers_[idx].client.reset(); | ||||
|     servers_[idx].timeout = td::Timestamp::never(); | ||||
|     servers_[idx].ignore_until = td::Timestamp::in(60.0); | ||||
|   } | ||||
|   void hangup_shared() override { | ||||
|     ref_cnt_--; | ||||
|     try_stop(); | ||||
|   } | ||||
|   void hangup() override { | ||||
|     is_closing_ = true; | ||||
|     ref_cnt_--; | ||||
|     for (Server& server : servers_) { | ||||
|       server.client.reset(); | ||||
|     } | ||||
|     try_stop(); | ||||
|   } | ||||
|   void try_stop() { | ||||
|     if (is_closing_ && ref_cnt_ == 0) { | ||||
|       stop(); | ||||
|     } | ||||
| 
 | ||||
|   void on_server_error(size_t idx) { | ||||
|     servers_[idx].alive = false; | ||||
|     servers_[idx].ignore_until = td::Timestamp::in(BAD_SERVER_TIMEOUT); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| td::actor::ActorOwn<ExtClient> ExtClient::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr, | ||||
|                                                          td::unique_ptr<Callback> callback) { | ||||
|   return create({LiteServer{dst, dst_addr, true, {}}}, std::move(callback)); | ||||
|                                                  td::unique_ptr<Callback> callback) { | ||||
|   return create({LiteServerConfig{dst, dst_addr}}, std::move(callback)); | ||||
| } | ||||
| 
 | ||||
| td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServer> servers, | ||||
|                                                          td::unique_ptr<Callback> callback) { | ||||
|   return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(servers), std::move(callback)); | ||||
| td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServerConfig> liteservers, | ||||
|                                                  td::unique_ptr<Callback> callback) { | ||||
|   return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(liteservers), std::move(callback)); | ||||
| } | ||||
| }  // namespace liteclient
 | ||||
|  |  | |||
|  | @ -18,29 +18,24 @@ | |||
| #include "td/actor/actor.h" | ||||
| #include "ton/ton-types.h" | ||||
| #include "adnl/adnl-ext-client.h" | ||||
| #include "query-utils.hpp" | ||||
| 
 | ||||
| namespace liteclient { | ||||
| class ExtClient : public td::actor::Actor { | ||||
|  public: | ||||
|   struct LiteServer { | ||||
|     ton::adnl::AdnlNodeIdFull adnl_id; | ||||
|     td::IPAddress address; | ||||
|     bool is_full = true; | ||||
|     std::vector<ton::ShardIdFull> shards; | ||||
|   }; | ||||
| 
 | ||||
|   class Callback { | ||||
|    public: | ||||
|     virtual ~Callback() { | ||||
|     } | ||||
|     virtual ~Callback() = default; | ||||
|   }; | ||||
| 
 | ||||
|   virtual void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout, | ||||
|   virtual void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, | ||||
|                           td::Promise<td::BufferSlice> promise) = 0; | ||||
|   virtual void force_change_liteserver() = 0; | ||||
|   virtual void reset_servers() { | ||||
|   } | ||||
| 
 | ||||
|   static td::actor::ActorOwn<ExtClient> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr, | ||||
|                                                td::unique_ptr<Callback> callback); | ||||
|   static td::actor::ActorOwn<ExtClient> create(std::vector<LiteServer> servers, td::unique_ptr<Callback> callback); | ||||
|   static td::actor::ActorOwn<ExtClient> create(std::vector<LiteServerConfig> liteservers, | ||||
|                                                td::unique_ptr<Callback> callback); | ||||
| }; | ||||
| }  // namespace liteclient
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -26,6 +26,7 @@ | |||
|     Copyright 2017-2020 Telegram Systems LLP | ||||
| */ | ||||
| #pragma once | ||||
| #include "ext-client.h" | ||||
| #include "adnl/adnl-ext-client.h" | ||||
| #include "tl-utils/tl-utils.hpp" | ||||
| #include "ton/ton-types.h" | ||||
|  | @ -46,35 +47,19 @@ class TestNode : public td::actor::Actor { | |||
|     min_ls_version = 0x101, | ||||
|     min_ls_capabilities = 1 | ||||
|   };  // server version >= 1.1, capabilities at least +1 = build proof chains
 | ||||
|   td::actor::ActorOwn<liteclient::ExtClient> client_; | ||||
|   td::actor::ActorOwn<td::TerminalIO> io_; | ||||
| 
 | ||||
|   struct LiteServer { | ||||
|     td::IPAddress addr; | ||||
|     ton::PublicKey public_key; | ||||
|     bool is_full = true; | ||||
|     std::vector<ton::ShardIdFull> shards; | ||||
| 
 | ||||
|     td::actor::ActorOwn<ton::adnl::AdnlExtClient> client; | ||||
|     bool client_ready = false; | ||||
|     std::vector<td::Promise<td::Unit>> wait_client_ready; | ||||
| 
 | ||||
|     bool supports(ton::ShardIdFull shard) const; | ||||
|   }; | ||||
|   std::vector<LiteServer> servers_; | ||||
|   bool ready_ = false; | ||||
| 
 | ||||
|   td::int32 single_liteserver_idx_ = -1; | ||||
|   td::IPAddress single_remote_addr_; | ||||
|   ton::PublicKey single_remote_public_key_; | ||||
| 
 | ||||
|   std::map<ton::ShardIdFull, td::int32> shard_server_idx_cached_; | ||||
| 
 | ||||
|   bool readline_enabled_ = true; | ||||
|   int print_limit_ = 1024; | ||||
| 
 | ||||
|   std::string db_root_; | ||||
| 
 | ||||
|   // mc_server is the server for queries to masterchain
 | ||||
|   int mc_server_idx_ = -1; | ||||
|   int mc_server_time_ = 0; | ||||
|   int mc_server_time_got_at_ = 0; | ||||
|   int mc_server_version_ = 0; | ||||
|  | @ -443,18 +428,7 @@ class TestNode : public td::actor::Actor { | |||
| 
 | ||||
|   void got_result(td::Result<td::BufferSlice> R, td::Promise<td::BufferSlice> promise); | ||||
|   void after_got_result(bool ok); | ||||
|   bool envelope_send_query_to_any(td::BufferSlice query, td::Promise<td::BufferSlice> promise); | ||||
|   bool envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query, | ||||
|                                     td::Promise<td::BufferSlice> promise); | ||||
|   bool envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query, | ||||
|                                       td::Promise<td::BufferSlice> promise); | ||||
| 
 | ||||
|   bool envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise); | ||||
| 
 | ||||
|   void start_client(int server_idx); | ||||
|   void conn_ready(int server_idx); | ||||
|   void conn_closed(int server_idx); | ||||
| 
 | ||||
|   bool envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise); | ||||
|   void parse_line(td::BufferSlice data); | ||||
| 
 | ||||
|   TestNode() = default; | ||||
|  |  | |||
							
								
								
									
										394
									
								
								lite-client/query-utils.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								lite-client/query-utils.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,394 @@ | |||
| /*
 | ||||
|     This file is part of TON Blockchain Library. | ||||
| 
 | ||||
|     TON Blockchain Library is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Lesser General Public License as published by | ||||
|     the Free Software Foundation, either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     TON Blockchain Library is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU Lesser General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU Lesser General Public License | ||||
|     along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| #include "query-utils.hpp" | ||||
| 
 | ||||
| #include "block-parse.h" | ||||
| #include "td/utils/overloaded.h" | ||||
| #include "tl-utils/common-utils.hpp" | ||||
| 
 | ||||
| #include "block/block-auto.h" | ||||
| #include "auto/tl/lite_api.hpp" | ||||
| #include "overlay/overlay-broadcast.hpp" | ||||
| #include "tl-utils/lite-utils.hpp" | ||||
| #include "ton/lite-tl.hpp" | ||||
| #include "ton/ton-shard.h" | ||||
| 
 | ||||
| #include <ton/ton-tl.hpp> | ||||
| 
 | ||||
| namespace liteclient { | ||||
| 
 | ||||
| using namespace ton; | ||||
| 
 | ||||
| std::string QueryInfo::to_str() const { | ||||
|   td::StringBuilder sb; | ||||
|   sb << "[ " << lite_query_name_by_id(query_id) << " " << shard_id.to_str(); | ||||
|   switch (type) { | ||||
|     case t_simple: | ||||
|       break; | ||||
|     case t_seqno: | ||||
|       sb << " seqno=" << value; | ||||
|       break; | ||||
|     case t_utime: | ||||
|       sb << " utime=" << value; | ||||
|       break; | ||||
|     case t_lt: | ||||
|       sb << " lt=" << value; | ||||
|       break; | ||||
|     case t_mc_seqno: | ||||
|       sb << " mc_seqno=" << value; | ||||
|       break; | ||||
|   } | ||||
|   sb << " ]"; | ||||
|   return sb.as_cslice().str(); | ||||
| } | ||||
| 
 | ||||
| QueryInfo get_query_info(td::Slice data) { | ||||
|   auto F = fetch_tl_object<lite_api::liteServer_query>(data, true); | ||||
|   if (F.is_ok()) { | ||||
|     data = F.ok()->data_; | ||||
|   } else { | ||||
|     fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true).ignore(); | ||||
|   } | ||||
|   fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true).ignore(); | ||||
|   auto Q = fetch_tl_object<lite_api::Function>(data, true); | ||||
|   if (Q.is_error()) { | ||||
|     return {}; | ||||
|   } | ||||
|   return get_query_info(*Q.ok()); | ||||
| } | ||||
| 
 | ||||
| QueryInfo get_query_info(const lite_api::Function& f) { | ||||
|   QueryInfo info; | ||||
|   info.query_id = f.get_id(); | ||||
|   auto from_block_id = [&](const tl_object_ptr<lite_api::tonNode_blockIdExt>& id) { | ||||
|     BlockIdExt block_id = create_block_id(id); | ||||
|     info.shard_id = block_id.shard_full(); | ||||
|     info.type = QueryInfo::t_seqno; | ||||
|     info.value = block_id.seqno(); | ||||
|   }; | ||||
|   downcast_call( | ||||
|       const_cast<lite_api::Function&>(f), | ||||
|       td::overloaded([&](const lite_api::liteServer_getTime& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_getVersion& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_getMasterchainInfo& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_getMasterchainInfoExt& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_getBlock& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getBlockHeader& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getState& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getAccountState& q) { | ||||
|                        BlockIdExt block_id = create_block_id(q.id_); | ||||
|                        AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); | ||||
|                        info.shard_id = acc_id_prefix.as_leaf_shard(); | ||||
|                        // See LiteQuery::perform_getAccountState
 | ||||
|                        if (block_id.id.workchain != masterchainId) { | ||||
|                          info.type = QueryInfo::t_seqno; | ||||
|                          info.value = block_id.seqno(); | ||||
|                        } else if (block_id.id.seqno != ~0U) { | ||||
|                          info.type = QueryInfo::t_mc_seqno; | ||||
|                          info.value = block_id.seqno(); | ||||
|                        } else { | ||||
|                          info.type = QueryInfo::t_simple; | ||||
|                        } | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_getAccountStatePrunned& q) { | ||||
|                        BlockIdExt block_id = create_block_id(q.id_); | ||||
|                        AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); | ||||
|                        info.shard_id = acc_id_prefix.as_leaf_shard(); | ||||
|                        // See LiteQuery::perform_getAccountState
 | ||||
|                        if (block_id.id.workchain != masterchainId) { | ||||
|                          info.type = QueryInfo::t_seqno; | ||||
|                          info.value = block_id.seqno(); | ||||
|                        } else if (block_id.id.seqno != ~0U) { | ||||
|                          info.type = QueryInfo::t_mc_seqno; | ||||
|                          info.value = block_id.seqno(); | ||||
|                        } else { | ||||
|                          info.type = QueryInfo::t_simple; | ||||
|                        } | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_getOneTransaction& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getTransactions& q) { | ||||
|                        AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); | ||||
|                        info.shard_id = acc_id_prefix.as_leaf_shard(); | ||||
|                        info.type = QueryInfo::t_lt; | ||||
|                        info.value = q.lt_; | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_sendMessage& q) { | ||||
|                        info.type = QueryInfo::t_simple; | ||||
|                        auto r_root = vm::std_boc_deserialize(q.body_); | ||||
|                        if (r_root.is_error()) { | ||||
|                          return; | ||||
|                        } | ||||
|                        block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; | ||||
|                        if (!tlb::unpack_cell_inexact(r_root.ok(), msg_info)) { | ||||
|                          return; | ||||
|                        } | ||||
|                        auto dest_prefix = block::tlb::MsgAddressInt::get_prefix(msg_info.dest); | ||||
|                        if (!dest_prefix.is_valid()) { | ||||
|                          return; | ||||
|                        } | ||||
|                        info.shard_id = dest_prefix.as_leaf_shard(); | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_getShardInfo& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getAllShardsInfo& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_lookupBlock& q) { | ||||
|                        BlockId block_id = create_block_id_simple(q.id_); | ||||
|                        info.shard_id = block_id.shard_full(); | ||||
|                        // See LiteQuery::perform_lookupBlock
 | ||||
|                        if (q.mode_ & 1) { | ||||
|                          info.type = QueryInfo::t_seqno; | ||||
|                          info.value = block_id.seqno; | ||||
|                        } else if (q.mode_ == 2) { | ||||
|                          info.type = QueryInfo::t_lt; | ||||
|                          info.value = q.lt_; | ||||
|                        } else if (q.mode_ == 4) { | ||||
|                          info.type = QueryInfo::t_utime; | ||||
|                          info.value = q.utime_; | ||||
|                        } | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_lookupBlockWithProof& q) { | ||||
|                        BlockId block_id = create_block_id_simple(q.id_); | ||||
|                        info.shard_id = block_id.shard_full(); | ||||
|                        // See LiteQuery::perform_lookupBlockWithProof
 | ||||
|                        if (q.mode_ & 1) { | ||||
|                          info.type = QueryInfo::t_seqno; | ||||
|                          info.value = block_id.seqno; | ||||
|                        } else if (q.mode_ == 2) { | ||||
|                          info.type = QueryInfo::t_lt; | ||||
|                          info.value = q.lt_; | ||||
|                        } else if (q.mode_ == 4) { | ||||
|                          info.type = QueryInfo::t_utime; | ||||
|                          info.value = q.utime_; | ||||
|                        } | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_listBlockTransactions& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_listBlockTransactionsExt& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getConfigParams& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getConfigAll& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getBlockProof& q) { | ||||
|                        info.shard_id = ShardIdFull{masterchainId}; | ||||
|                        BlockIdExt from = create_block_id(q.known_block_); | ||||
|                        BlockIdExt to = create_block_id(q.target_block_); | ||||
|                        // See LiteQuery::perform_getBlockProof
 | ||||
|                        if ((q.mode_ & 1) && (q.mode_ & 0x1000)) { | ||||
|                          info.type = QueryInfo::t_seqno; | ||||
|                          info.value = std::max(from.seqno(), to.seqno()); | ||||
|                        } else { | ||||
|                          info.type = QueryInfo::t_simple; | ||||
|                        } | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_getValidatorStats& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_runSmcMethod& q) { | ||||
|                        BlockIdExt block_id = create_block_id(q.id_); | ||||
|                        AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); | ||||
|                        info.shard_id = acc_id_prefix.as_leaf_shard(); | ||||
|                        // See LiteQuery::perform_getAccountState
 | ||||
|                        if (block_id.id.workchain != masterchainId) { | ||||
|                          info.type = QueryInfo::t_seqno; | ||||
|                          info.value = block_id.seqno(); | ||||
|                        } else if (block_id.id.seqno != ~0U) { | ||||
|                          info.type = QueryInfo::t_mc_seqno; | ||||
|                          info.value = block_id.seqno(); | ||||
|                        } else { | ||||
|                          info.type = QueryInfo::t_simple; | ||||
|                        } | ||||
|                      }, | ||||
|                      [&](const lite_api::liteServer_getLibraries& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_getLibrariesWithProof& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_getShardBlockProof& q) { from_block_id(q.id_); }, | ||||
|                      [&](const lite_api::liteServer_nonfinal_getCandidate& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_nonfinal_getValidatorGroups& q) { /* t_simple */ }, | ||||
|                      [&](const lite_api::liteServer_getOutMsgQueueSizes& q) { /* t_simple */ }, | ||||
|                      [&](const auto&) { /* t_simple */ })); | ||||
|   if (info.shard_id.workchain == masterchainId) { | ||||
|     info.shard_id.shard = shardIdAll; | ||||
|   } | ||||
|   if (!info.shard_id.is_valid_ext()) { | ||||
|     info.shard_id = ShardIdFull{masterchainId}; | ||||
|     info.type = QueryInfo::t_simple; | ||||
|     info.value = 0; | ||||
|   } | ||||
|   return info; | ||||
| } | ||||
| 
 | ||||
| bool LiteServerConfig::accepts_query(const QueryInfo& query_info) const { | ||||
|   if (is_full) { | ||||
|     return true; | ||||
|   } | ||||
|   for (const Slice& s : slices) { | ||||
|     if (s.accepts_query(query_info)) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| bool LiteServerConfig::Slice::accepts_query(const QueryInfo& query_info) const { | ||||
|   if (unlimited) { | ||||
|     for (const ShardInfo& shard : shards_from) { | ||||
|       if (shard_intersects(shard.shard_id, query_info.shard_id)) { | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   if (!shards_from.empty()) { | ||||
|     bool from_ok = false; | ||||
|     DCHECK(shards_from[0].shard_id.is_masterchain()); | ||||
|     for (const ShardInfo& shard : shards_from) { | ||||
|       if (shard_intersects(shard.shard_id, query_info.shard_id)) { | ||||
|         switch (query_info.type) { | ||||
|           case QueryInfo::t_simple: | ||||
|             from_ok = true; | ||||
|             break; | ||||
|           case QueryInfo::t_seqno: | ||||
|             from_ok = shard.seqno <= query_info.value; | ||||
|             break; | ||||
|           case QueryInfo::t_utime: | ||||
|             from_ok = shard.utime <= query_info.value; | ||||
|             break; | ||||
|           case QueryInfo::t_lt: | ||||
|             from_ok = shard.lt <= query_info.value; | ||||
|             break; | ||||
|           case QueryInfo::t_mc_seqno: | ||||
|             from_ok = shards_from[0].seqno <= query_info.value; | ||||
|             break; | ||||
|         } | ||||
|         if (from_ok) { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (!from_ok) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|   if (!shards_to.empty()) { | ||||
|     bool to_ok = false; | ||||
|     DCHECK(shards_to[0].shard_id.is_masterchain()); | ||||
|     for (const ShardInfo& shard : shards_to) { | ||||
|       if (shard_intersects(shard.shard_id, query_info.shard_id)) { | ||||
|         switch (query_info.type) { | ||||
|           case QueryInfo::t_simple: | ||||
|             break; | ||||
|           case QueryInfo::t_seqno: | ||||
|             to_ok = shard.seqno >= query_info.value; | ||||
|             break; | ||||
|           case QueryInfo::t_utime: | ||||
|             to_ok = shard.utime >= query_info.value; | ||||
|             break; | ||||
|           case QueryInfo::t_lt: | ||||
|             to_ok = shard.lt >= query_info.value; | ||||
|             break; | ||||
|           case QueryInfo::t_mc_seqno: | ||||
|             to_ok = shards_from[0].seqno >= query_info.value; | ||||
|             break; | ||||
|         } | ||||
|         if (to_ok) { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (!to_ok) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| td::Result<std::vector<LiteServerConfig>> LiteServerConfig::parse_global_config( | ||||
|     const ton_api::liteclient_config_global& config) { | ||||
|   std::vector<LiteServerConfig> servers; | ||||
|   for (const auto& f : config.liteservers_) { | ||||
|     LiteServerConfig server; | ||||
|     TRY_STATUS(server.addr.init_host_port(td::IPAddress::ipv4_to_str(f->ip_), f->port_)); | ||||
|     server.adnl_id = adnl::AdnlNodeIdFull{PublicKey{f->id_}}; | ||||
|     server.is_full = true; | ||||
|     servers.push_back(std::move(server)); | ||||
|   } | ||||
|   for (const auto& f : config.liteservers_v2_) { | ||||
|     LiteServerConfig server; | ||||
|     TRY_STATUS(server.addr.init_host_port(td::IPAddress::ipv4_to_str(f->ip_), f->port_)); | ||||
|     server.adnl_id = adnl::AdnlNodeIdFull{PublicKey{f->id_}}; | ||||
|     server.is_full = false; | ||||
|     for (const auto& slice_obj : f->slices_) { | ||||
|       Slice slice; | ||||
|       td::Status S = td::Status::OK(); | ||||
|       downcast_call(*slice_obj, | ||||
|                     td::overloaded( | ||||
|                         [&](const ton_api::liteserver_descV2_sliceSimple& s) { | ||||
|                           slice.unlimited = true; | ||||
|                           slice.shards_from.push_back({ShardIdFull{masterchainId}, 0, 0, 0}); | ||||
|                           for (const auto& shard_obj : s.shards_) { | ||||
|                             ShardIdFull shard_id = create_shard_id(shard_obj); | ||||
|                             if (!shard_id.is_valid_ext()) { | ||||
|                               S = td::Status::Error(PSTRING() << "invalid shard id " << shard_id.to_str()); | ||||
|                               break; | ||||
|                             } | ||||
|                             if (!shard_id.is_masterchain()) { | ||||
|                               slice.shards_from.push_back({shard_id, 0, 0, 0}); | ||||
|                             } | ||||
|                           } | ||||
|                         }, | ||||
|                         [&](const ton_api::liteserver_descV2_sliceTimed& s) { | ||||
|                           auto parse_shards = | ||||
|                               [](const std::vector<tl_object_ptr<ton_api::liteserver_descV2_shardInfo>>& shard_objs, | ||||
|                                  std::vector<ShardInfo>& shards) -> td::Status { | ||||
|                             if (shard_objs.empty()) { | ||||
|                               return td::Status::OK(); | ||||
|                             } | ||||
|                             size_t i = 0; | ||||
|                             int mc_idx = -1; | ||||
|                             for (const auto& shard_obj : shard_objs) { | ||||
|                               ShardIdFull shard_id = create_shard_id(shard_obj->shard_id_); | ||||
|                               if (!shard_id.is_valid_ext()) { | ||||
|                                 return td::Status::Error(PSTRING() << "invalid shard id " << shard_id.to_str()); | ||||
|                               } | ||||
|                               if (shard_id.is_masterchain()) { | ||||
|                                 shard_id = ShardIdFull{masterchainId}; | ||||
|                                 if (mc_idx != -1) { | ||||
|                                   return td::Status::Error("duplicate masterchain shard in sliceTimed"); | ||||
|                                 } | ||||
|                                 mc_idx = (int)i; | ||||
|                               } | ||||
|                               shards.push_back({shard_id, (BlockSeqno)shard_obj->seqno_, (UnixTime)shard_obj->utime_, | ||||
|                                                 (LogicalTime)shard_obj->lt_}); | ||||
|                               ++i; | ||||
|                             } | ||||
|                             if (mc_idx == -1) { | ||||
|                               return td::Status::Error("no masterchain shard in sliceTimed"); | ||||
|                             } | ||||
|                             std::swap(shards[0], shards[mc_idx]); | ||||
|                             return td::Status::OK(); | ||||
|                           }; | ||||
|                           S = parse_shards(s.shards_from_, slice.shards_from); | ||||
|                           if (S.is_ok()) { | ||||
|                             S = parse_shards(s.shards_to_, slice.shards_to); | ||||
|                           } | ||||
|                           if (S.is_ok() && slice.shards_from.empty() && slice.shards_to.empty()) { | ||||
|                             S = td::Status::Error("shards_from and shards_to are both empty"); | ||||
|                           } | ||||
|                         })); | ||||
|       TRY_STATUS(std::move(S)); | ||||
|       server.slices.push_back(slice); | ||||
|     } | ||||
| 
 | ||||
|     servers.push_back(std::move(server)); | ||||
|   } | ||||
|   return servers; | ||||
| } | ||||
| 
 | ||||
| }  // namespace liteclient
 | ||||
							
								
								
									
										89
									
								
								lite-client/query-utils.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								lite-client/query-utils.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| /*
 | ||||
|     This file is part of TON Blockchain Library. | ||||
| 
 | ||||
|     TON Blockchain Library is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Lesser General Public License as published by | ||||
|     the Free Software Foundation, either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     TON Blockchain Library is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU Lesser General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU Lesser General Public License | ||||
|     along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| #pragma once | ||||
| #include "ton/ton-types.h" | ||||
| #include "auto/tl/lite_api.h" | ||||
| #include "td/utils/port/IPAddress.h" | ||||
| #include "adnl/adnl-node-id.hpp" | ||||
| 
 | ||||
| namespace liteclient { | ||||
| 
 | ||||
| struct QueryInfo { | ||||
|   enum Type { t_simple, t_seqno, t_utime, t_lt, t_mc_seqno }; | ||||
|   int query_id = 0; | ||||
|   ton::ShardIdFull shard_id{ton::masterchainId}; | ||||
|   Type type = t_simple; | ||||
|   td::uint64 value = 0; | ||||
|   /* Query types and examples:
 | ||||
|    * t_simple - query to the recent blocks in a shard, or general info. value = 0. | ||||
|    *   getTime, getMasterchainInfo (shard_id = masterchain) | ||||
|    *   sendMessage | ||||
|    *   getAccountState, runSmcMethod - when no block is given | ||||
|    * t_seqno - query to block with seqno in a shard. value = seqno. | ||||
|    *   lookupBlock by seqno | ||||
|    *   getBlock, getBlockHeader | ||||
|    *   getAccountState, runSmcMethod  - when shard block is given | ||||
|    * t_utime - query to a block with given unixtime in a shard. value = utime. | ||||
|    *   lookupBlock by utime | ||||
|    * t_lt - query to a block with given lt in a shard. value = lt. | ||||
|    *   lookupBlock by lt | ||||
|    *   getTransactions | ||||
|    * t_mc_seqno - query to a block in a shard, masterchain seqno is given. value = mc_seqno. | ||||
|    *   getAccountState, runSmcMethod - when mc block is given | ||||
|    */ | ||||
| 
 | ||||
|   std::string to_str() const; | ||||
| }; | ||||
| 
 | ||||
| QueryInfo get_query_info(td::Slice data); | ||||
| QueryInfo get_query_info(const ton::lite_api::Function& f); | ||||
| 
 | ||||
| struct LiteServerConfig { | ||||
|  private: | ||||
|   struct ShardInfo { | ||||
|     ton::ShardIdFull shard_id; | ||||
|     ton::BlockSeqno seqno; | ||||
|     ton::UnixTime utime; | ||||
|     ton::LogicalTime lt; | ||||
|   }; | ||||
| 
 | ||||
|   struct Slice { | ||||
|     std::vector<ShardInfo> shards_from, shards_to; | ||||
|     bool unlimited = false; | ||||
| 
 | ||||
|     bool accepts_query(const QueryInfo& query_info) const; | ||||
|   }; | ||||
| 
 | ||||
|   bool is_full = false; | ||||
|   std::vector<Slice> slices; | ||||
| 
 | ||||
|  public: | ||||
|   ton::adnl::AdnlNodeIdFull adnl_id; | ||||
|   td::IPAddress addr; | ||||
| 
 | ||||
|   LiteServerConfig() = default; | ||||
|   LiteServerConfig(ton::adnl::AdnlNodeIdFull adnl_id, td::IPAddress addr) | ||||
|       : is_full(true), adnl_id(adnl_id), addr(addr) { | ||||
|   } | ||||
| 
 | ||||
|   bool accepts_query(const QueryInfo& query_info) const; | ||||
| 
 | ||||
|   static td::Result<std::vector<LiteServerConfig>> parse_global_config( | ||||
|       const ton::ton_api::liteclient_config_global& config); | ||||
| }; | ||||
| 
 | ||||
| }  // namespace liteclient
 | ||||
|  | @ -148,6 +148,39 @@ td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>> | |||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| td::Result<tl_object_ptr<std::enable_if_t<std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data, | ||||
|                                                                                                 bool boxed) { | ||||
|   td::TlParser p(data); | ||||
|   tl_object_ptr<T> R; | ||||
|   if (boxed) { | ||||
|     R = TlFetchBoxed<TlFetchObject<T>, T::ID>::parse(p); | ||||
|   } else { | ||||
|     R = move_tl_object_as<T>(T::fetch(p)); | ||||
|   } | ||||
|   if (p.get_status().is_ok()) { | ||||
|     data.remove_prefix(data.size() - p.get_left_len()); | ||||
|     return std::move(R); | ||||
|   } else { | ||||
|     return p.get_status(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data, | ||||
|                                                                                                  bool boxed) { | ||||
|   CHECK(boxed); | ||||
|   td::TlParser p(data); | ||||
|   tl_object_ptr<T> R; | ||||
|   R = move_tl_object_as<T>(T::fetch(p)); | ||||
|   if (p.get_status().is_ok()) { | ||||
|     data.remove_prefix(data.size() - p.get_left_len()); | ||||
|     return std::move(R); | ||||
|   } else { | ||||
|     return p.get_status(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <class T> | ||||
| [[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) { | ||||
|   auto B = serialize_tl_object(obj, true); | ||||
|  |  | |||
|  | @ -588,8 +588,12 @@ dummyworkchain0.config.global zero_state_hash:int256 = dummyworkchain0.config.Gl | |||
| validator.config.global zero_state:tonNode.blockIdExt init_block:tonNode.blockIdExt hardforks:(vector tonNode.blockIdExt) = validator.config.Global; | ||||
| config.global adnl:adnl.config.global dht:dht.config.Global validator:validator.config.global = config.Global; | ||||
| 
 | ||||
| liteserver.descV2.sliceSimple shards:(vector tonNode.shardId) = liteserver.descV2.Slice; | ||||
| liteserver.descV2.shardInfo shard_id:tonNode.shardId seqno:int utime:int lt:long = liteserver.descV2.ShardInfo; | ||||
| liteserver.descV2.sliceTimed shards_from:(vector liteserver.descV2.shardInfo) shards_to:(vector liteserver.descV2.shardInfo) = liteserver.descV2.Slice; | ||||
| 
 | ||||
| liteserver.desc id:PublicKey ip:int port:int = liteserver.Desc; | ||||
| liteserver.descV2 id:PublicKey ip:int port:int shards:(vector tonNode.shardId) = liteserver.DescV2; | ||||
| liteserver.descV2 id:PublicKey ip:int port:int slices:(vector liteserver.descV2.Slice) = liteserver.DescV2; | ||||
| liteclient.config.global liteservers:(vector liteserver.desc) liteservers_v2:(vector liteserver.descV2) validator:validator.config.global = liteclient.config.Global; | ||||
| 
 | ||||
| engine.adnl id:int256 category:int = engine.Adnl; | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							|  | @ -190,7 +190,7 @@ smc.libraryQueryExt.one hash:int256 = smc.LibraryQueryExt; | |||
| smc.libraryQueryExt.scanBoc boc:bytes max_libs:int32 = smc.LibraryQueryExt; | ||||
| smc.libraryResultExt dict_boc:bytes libs_ok:(vector int256) libs_not_found:(vector int256) = smc.LibraryResultExt; | ||||
| 
 | ||||
| updateSendLiteServerQuery id:int64 data:bytes workchain:int32 shard:int64 = Update; | ||||
| updateSendLiteServerQuery id:int64 data:bytes = Update; | ||||
| updateSyncState sync_state:SyncState = Update; | ||||
| 
 | ||||
| //@class LogStream @description Describes a stream to which tonlib internal log is written | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							|  | @ -19,6 +19,7 @@ | |||
| #include "Config.h" | ||||
| #include "adnl/adnl-node-id.hpp" | ||||
| #include "td/utils/JsonBuilder.h" | ||||
| #include "auto/tl/ton_api_json.h" | ||||
| 
 | ||||
| namespace tonlib { | ||||
| td::Result<ton::BlockIdExt> parse_block_id_ext(td::JsonObject &obj) { | ||||
|  | @ -65,67 +66,11 @@ td::Result<Config> Config::parse(std::string str) { | |||
|   if (json.type() != td::JsonValue::Type::Object) { | ||||
|     return td::Status::Error("Invalid config (1)"); | ||||
|   } | ||||
|   td::JsonArray empty_array; | ||||
|   TRY_RESULT(lite_servers_obj, | ||||
|              td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, true)); | ||||
|   auto &lite_servers = | ||||
|       lite_servers_obj.type() == td::JsonValue::Type::Array ? lite_servers_obj.get_array() : empty_array; | ||||
|   TRY_RESULT(lite_servers_v2_obj, | ||||
|              td::get_json_object_field(json.get_object(), "liteservers_v2", td::JsonValue::Type::Array, true)); | ||||
|   auto &lite_servers_v2 = | ||||
|       lite_servers_v2_obj.type() == td::JsonValue::Type::Array ? lite_servers_v2_obj.get_array() : empty_array; | ||||
| 
 | ||||
|   auto parse_desc = [&](td::JsonValue &value) -> td::Result<Config::LiteServer> { | ||||
|     if (value.type() != td::JsonValue::Type::Object) { | ||||
|       return td::Status::Error("Invalid config (2)"); | ||||
|     } | ||||
|     auto &object = value.get_object(); | ||||
| 
 | ||||
|     TRY_RESULT(ip, td::get_json_object_long_field(object, "ip", false)); | ||||
|     TRY_RESULT(port, td::get_json_object_int_field(object, "port", false)); | ||||
|     Config::LiteServer server; | ||||
|     TRY_STATUS(server.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast<td::int32>(ip)), port)); | ||||
| 
 | ||||
|     TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false)); | ||||
|     auto &id = id_obj.get_object(); | ||||
|     TRY_RESULT(id_type, td::get_json_object_string_field(id, "@type", false)); | ||||
|     if (id_type != "pub.ed25519") { | ||||
|       return td::Status::Error("Invalid config (3)"); | ||||
|     } | ||||
|     TRY_RESULT(key_base64, td::get_json_object_string_field(id, "key", false)); | ||||
|     TRY_RESULT(key, td::base64_decode(key_base64)); | ||||
|     if (key.size() != 32) { | ||||
|       return td::Status::Error("Invalid config (4)"); | ||||
|     } | ||||
| 
 | ||||
|     server.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin()))); | ||||
|     return server; | ||||
|   }; | ||||
| 
 | ||||
|   Config res; | ||||
|   for (auto &value : lite_servers) { | ||||
|     TRY_RESULT(server, parse_desc(value)); | ||||
|     res.lite_servers.push_back(std::move(server)); | ||||
|   } | ||||
|   for (auto &value : lite_servers_v2) { | ||||
|     TRY_RESULT(server, parse_desc(value)); | ||||
|     server.is_full = false; | ||||
|     TRY_RESULT(shards_obj, td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false)); | ||||
|     for (auto &shard : shards_obj.get_array()) { | ||||
|       if (shard.type() != td::JsonValue::Type::Object) { | ||||
|         return td::Status::Error("Invalid config (5)"); | ||||
|       } | ||||
|       auto &shard_obj = shard.get_object(); | ||||
|       TRY_RESULT(workchain, td::get_json_object_int_field(shard_obj, "workchain", false)); | ||||
|       TRY_RESULT(shard_id, td::get_json_object_long_field(shard_obj, "shard", false)); | ||||
|       if (shard_id == 0) { | ||||
|         return td::Status::Error("Invalid config (6)"); | ||||
|       } | ||||
|       server.shards.emplace_back(workchain, shard_id); | ||||
|     } | ||||
| 
 | ||||
|     res.lite_servers.push_back(std::move(server)); | ||||
|   } | ||||
|   ton::ton_api::liteclient_config_global conf; | ||||
|   TRY_STATUS(ton::ton_api::from_json(conf, json.get_object())); | ||||
|   TRY_RESULT_ASSIGN(res.lite_servers, liteclient::LiteServerConfig::parse_global_config(conf)); | ||||
| 
 | ||||
|   TRY_RESULT(validator_obj, | ||||
|              td::get_json_object_field(json.get_object(), "validator", td::JsonValue::Type::Object, false)); | ||||
|  |  | |||
|  | @ -24,11 +24,10 @@ | |||
| 
 | ||||
| namespace tonlib { | ||||
| struct Config { | ||||
|   using LiteServer = liteclient::ExtClient::LiteServer; | ||||
|   ton::BlockIdExt zero_state_id; | ||||
|   ton::BlockIdExt init_block_id; | ||||
|   std::vector<ton::BlockIdExt> hardforks; | ||||
|   std::vector<LiteServer> lite_servers; | ||||
|   std::vector<liteclient::LiteServerConfig> lite_servers; | ||||
|   std::string name; | ||||
|   static td::Result<Config> parse(std::string str); | ||||
| }; | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) { | |||
|   td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P)); | ||||
| } | ||||
| 
 | ||||
| void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) { | ||||
| void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) { | ||||
|   auto query_id = queries_.create(std::move(promise)); | ||||
|   td::Promise<td::BufferSlice> P = [query_id, self = this, | ||||
|                                     actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) { | ||||
|  | @ -66,6 +66,6 @@ void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td | |||
|     return P.set_error(TonlibError::NoLiteServers()); | ||||
|   } | ||||
|   td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::send_query, "query", std::move(query), | ||||
|                           shard, td::Timestamp::in(10.0), std::move(P)); | ||||
|                           td::Timestamp::in(10.0), std::move(P)); | ||||
| } | ||||
| }  // namespace tonlib
 | ||||
|  |  | |||
|  | @ -31,7 +31,6 @@ | |||
| #include "lite-client/ext-client.h" | ||||
| #include "TonlibError.h" | ||||
| #include "utils.h" | ||||
| #include "lite-client/QueryTraits.h" | ||||
| 
 | ||||
| namespace tonlib { | ||||
| class LastBlock; | ||||
|  | @ -65,7 +64,6 @@ class ExtClient { | |||
| 
 | ||||
|   template <class QueryT> | ||||
|   void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise, td::int32 seq_no = -1) { | ||||
|     ton::ShardIdFull shard = liteclient::QueryTraits<QueryT>::get_shard(query); | ||||
|     auto raw_query = ton::serialize_tl_object(&query, true); | ||||
|     td::uint32 tag = td::Random::fast_uint32(); | ||||
|     VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query); | ||||
|  | @ -79,7 +77,7 @@ class ExtClient { | |||
|         ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true); | ||||
| 
 | ||||
|     send_raw_query( | ||||
|         std::move(liteserver_query), shard, [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable { | ||||
|         std::move(liteserver_query), [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable { | ||||
|           auto res = [&]() -> td::Result<typename QueryT::ReturnType> { | ||||
|             TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork()); | ||||
|             auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true); | ||||
|  | @ -99,7 +97,7 @@ class ExtClient { | |||
| 
 | ||||
|   void force_change_liteserver() { | ||||
|     if (!client_.adnl_ext_client_.empty()) { | ||||
|       td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::force_change_liteserver); | ||||
|       td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::reset_servers); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -109,6 +107,6 @@ class ExtClient { | |||
|   td::Container<td::Promise<LastBlockState>> last_block_queries_; | ||||
|   td::Container<td::Promise<LastConfigState>> last_config_queries_; | ||||
| 
 | ||||
|   void send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise); | ||||
|   void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise); | ||||
| }; | ||||
| }  // namespace tonlib
 | ||||
|  |  | |||
|  | @ -28,14 +28,11 @@ class ExtClientOutboundImpl : public ExtClientOutbound { | |||
|   ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) { | ||||
|   } | ||||
| 
 | ||||
|   void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout, | ||||
|   void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, | ||||
|                   td::Promise<td::BufferSlice> promise) override { | ||||
|     auto query_id = next_query_id_++; | ||||
|     queries_[query_id] = std::move(promise); | ||||
|     callback_->request(query_id, data.as_slice().str(), shard); | ||||
|   } | ||||
| 
 | ||||
|   void force_change_liteserver() override { | ||||
|     callback_->request(query_id, data.as_slice().str()); | ||||
|   } | ||||
| 
 | ||||
|   void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override { | ||||
|  |  | |||
|  | @ -27,9 +27,8 @@ class ExtClientOutbound : public liteclient::ExtClient { | |||
|    public: | ||||
|     virtual ~Callback() { | ||||
|     } | ||||
|     virtual void request(td::int64 id, std::string data, ton::ShardIdFull shard) = 0; | ||||
|     virtual void request(td::int64 id, std::string data) = 0; | ||||
|   }; | ||||
| 
 | ||||
|   virtual void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) = 0; | ||||
|   static td::actor::ActorOwn<ExtClientOutbound> create(td::unique_ptr<Callback> callback); | ||||
| }; | ||||
|  |  | |||
|  | @ -2078,9 +2078,8 @@ ExtClientRef TonlibClient::get_client_ref() { | |||
|   return ref; | ||||
| } | ||||
| 
 | ||||
| void TonlibClient::proxy_request(td::int64 query_id, std::string data, ton::ShardIdFull shard) { | ||||
|   on_update( | ||||
|       tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data, shard.workchain, shard.shard)); | ||||
| void TonlibClient::proxy_request(td::int64 query_id, std::string data) { | ||||
|   on_update(tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data)); | ||||
| } | ||||
| 
 | ||||
| void TonlibClient::init_ext_client() { | ||||
|  | @ -2091,9 +2090,9 @@ void TonlibClient::init_ext_client() { | |||
|           : parent_(std::move(parent)), config_generation_(config_generation) { | ||||
|       } | ||||
| 
 | ||||
|       void request(td::int64 id, std::string data, ton::ShardIdFull shard) override { | ||||
|         send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), std::move(data), | ||||
|                      shard); | ||||
|       void request(td::int64 id, std::string data) override { | ||||
|         send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), | ||||
|                      std::move(data)); | ||||
|       } | ||||
| 
 | ||||
|      private: | ||||
|  | @ -2106,17 +2105,8 @@ void TonlibClient::init_ext_client() { | |||
|     ext_client_outbound_ = client.get(); | ||||
|     raw_client_ = std::move(client); | ||||
|   } else { | ||||
|     class Callback : public liteclient::ExtClient::Callback { | ||||
|      public: | ||||
|       explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) { | ||||
|       } | ||||
| 
 | ||||
|      private: | ||||
|       td::actor::ActorShared<> parent_; | ||||
|     }; | ||||
|     ext_client_outbound_ = {}; | ||||
|     ref_cnt_++; | ||||
|     raw_client_ = liteclient::ExtClient::create(config_.lite_servers, td::make_unique<Callback>(td::actor::actor_shared())); | ||||
|     raw_client_ = liteclient::ExtClient::create(config_.lite_servers, nullptr); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -4491,8 +4481,8 @@ void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& v | |||
|     } | ||||
|     return; | ||||
|   } | ||||
|   for (unsigned int i = 0; i < loaded_cell.data_cell->get_refs_cnt(); i++) { | ||||
|     deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1); | ||||
|   for (unsigned int i=0; i<loaded_cell.data_cell->get_refs_cnt(); i++) { | ||||
|     deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1, max_libs); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -401,7 +401,7 @@ class TonlibClient : public td::actor::Actor { | |||
|   td::Status do_request(const tonlib_api::getConfigAll& request, | ||||
|                         td::Promise<object_ptr<tonlib_api::configInfo>>&& promise); | ||||
| 
 | ||||
|   void proxy_request(td::int64 query_id, std::string data, ton::ShardIdFull shard); | ||||
|   void proxy_request(td::int64 query_id, std::string data); | ||||
| 
 | ||||
|   void load_libs_from_disk(); | ||||
|   void store_libs_to_disk(); | ||||
|  |  | |||
|  | @ -1541,7 +1541,7 @@ class TonlibCli : public td::actor::Actor { | |||
|           CHECK(!raw_client_.empty()); | ||||
|           snd_bytes_ += update->data_.size(); | ||||
|           send_closure(raw_client_, &liteclient::ExtClient::send_query, "query", td::BufferSlice(update->data_), | ||||
|                        ton::ShardIdFull(update->workchain_, update->shard_), td::Timestamp::in(5), | ||||
|                        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)); | ||||
|                        }); | ||||
|  |  | |||
|  | @ -29,50 +29,71 @@ | |||
| #include "td/utils/OptionParser.h" | ||||
| #include "td/utils/port/path.h" | ||||
| #include "td/utils/port/signals.h" | ||||
| #include "td/utils/port/user.h" | ||||
| #include "td/utils/port/IPAddress.h" | ||||
| #include "td/utils/Random.h" | ||||
| #include "td/utils/FileLog.h" | ||||
| #include "git.h" | ||||
| #include "auto/tl/ton_api.h" | ||||
| #include "auto/tl/lite_api.h" | ||||
| #include "auto/tl/lite_api.hpp" | ||||
| #include "tl-utils/lite-utils.hpp" | ||||
| #include "ton/lite-tl.hpp" | ||||
| #include "auto/tl/ton_api_json.h" | ||||
| #include "adnl/adnl.h" | ||||
| #include "lite-client/QueryTraits.h" | ||||
| #include "lite-client/ext-client.h" | ||||
| 
 | ||||
| #if TD_DARWIN || TD_LINUX | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| #include <iostream> | ||||
| #include <map> | ||||
| 
 | ||||
| using namespace ton; | ||||
| 
 | ||||
| class ProxyLiteserver : public td::actor::Actor { | ||||
|  public: | ||||
|   ProxyLiteserver(std::string global_config, std::string db_root, td::uint16 port) | ||||
|       : global_config_(std::move(global_config)), db_root_(std::move(db_root)), port_(port) { | ||||
|   ProxyLiteserver(std::string global_config, std::string db_root, td::uint16 port, PublicKeyHash public_key_hash) | ||||
|       : global_config_(std::move(global_config)) | ||||
|       , db_root_(std::move(db_root)) | ||||
|       , port_(port) | ||||
|       , public_key_hash_(public_key_hash) { | ||||
|   } | ||||
| 
 | ||||
|   void start_up() override { | ||||
|     LOG_CHECK(db_root_ != "") << "db root is not set"; | ||||
|     LOG_CHECK(!db_root_.empty()) << "db root is not set"; | ||||
|     td::mkdir(db_root_).ensure(); | ||||
|     db_root_ = td::realpath(db_root_).move_as_ok(); | ||||
|     keyring_ = keyring::Keyring::create(db_root_ + "/keyring"); | ||||
| 
 | ||||
|     if (public_key_hash_.is_zero()) { | ||||
|       id_ = {}; | ||||
|       run(); | ||||
|     } else { | ||||
|       td::actor::send_closure(keyring_, &keyring::Keyring::get_public_key, public_key_hash_, | ||||
|                               [SelfId = actor_id(this)](td::Result<PublicKey> R) mutable { | ||||
|                                 if (R.is_error()) { | ||||
|                                   LOG(FATAL) << "Failed to load public key: " << R.move_as_error(); | ||||
|                                 } | ||||
|                                 td::actor::send_closure(SelfId, &ProxyLiteserver::got_public_key, R.move_as_ok()); | ||||
|                               }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void got_public_key(PublicKey pub) { | ||||
|     id_ = adnl::AdnlNodeIdFull{pub}; | ||||
|     run(); | ||||
|   } | ||||
| 
 | ||||
|   void run() { | ||||
|     td::Status S = prepare_local_config(); | ||||
|     if (S.is_error()) { | ||||
|       LOG(FATAL) << "Local config error: " << S; | ||||
|     } | ||||
| 
 | ||||
|     S = create_ext_client(); | ||||
|     S = parse_global_config(); | ||||
|     if (S.is_error()) { | ||||
|       LOG(FATAL) << S; | ||||
|     } | ||||
| 
 | ||||
|     run_clients(); | ||||
|     create_ext_server(); | ||||
|   } | ||||
| 
 | ||||
|  | @ -82,73 +103,123 @@ class ProxyLiteserver : public td::actor::Actor { | |||
|       auto conf_data = r_conf_data.move_as_ok(); | ||||
|       TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: "); | ||||
|       TRY_STATUS_PREFIX(ton_api::from_json(*config_, conf_json.get_object()), "json does not fit TL scheme: "); | ||||
|       TRY_RESULT_PREFIX_ASSIGN(port_, td::narrow_cast_safe<td::uint16>(config_->port_), "invalid port: "); | ||||
|       TRY_RESULT_PREFIX_ASSIGN(id_, adnl::AdnlNodeIdFull::create(config_->id_), "invalid id: "); | ||||
|       TRY_RESULT_PREFIX(cfg_port, td::narrow_cast_safe<td::uint16>(config_->port_), "invalid port: "); | ||||
|       TRY_RESULT_PREFIX(cfg_id, adnl::AdnlNodeIdFull::create(config_->id_), "invalid id: "); | ||||
|       bool rewrite_config = false; | ||||
|       if (port_ == 0) { | ||||
|         port_ = cfg_port; | ||||
|       } else { | ||||
|         rewrite_config |= (port_ != cfg_port); | ||||
|       } | ||||
|       if (id_.empty()) { | ||||
|         id_ = std::move(cfg_id); | ||||
|       } else { | ||||
|         rewrite_config |= (id_ != cfg_id); | ||||
|       } | ||||
|       if (!rewrite_config) { | ||||
|         return td::Status::OK(); | ||||
|       } | ||||
|     } else { | ||||
|       LOG(WARNING) << "First launch, creating local config"; | ||||
|       if (port_ == 0) { | ||||
|         return td::Status::Error("port is not set"); | ||||
|       } | ||||
|       config_->port_ = port_; | ||||
|     } | ||||
|     if (port_ == 0) { | ||||
|       return td::Status::Error("port is not set"); | ||||
|     } | ||||
|     config_->port_ = port_; | ||||
|     if (id_.empty()) { | ||||
|       auto pk = PrivateKey{privkeys::Ed25519::random()}; | ||||
|       id_ = adnl::AdnlNodeIdFull{pk.compute_public_key()}; | ||||
|       config_->id_ = id_.tl(); | ||||
|       td::actor::send_closure(keyring_, &keyring::Keyring::add_key, std::move(pk), false, [](td::Result<td::Unit> R) { | ||||
|         if (R.is_error()) { | ||||
|           LOG(FATAL) << "Failed to store private key"; | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|     config_->id_ = id_.tl(); | ||||
| 
 | ||||
|       auto s = td::json_encode<std::string>(td::ToJson(*config_), true); | ||||
|       TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: "); | ||||
|     auto s = td::json_encode<std::string>(td::ToJson(*config_), true); | ||||
|     TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: "); | ||||
|     LOG(WARNING) << "Writing config.json"; | ||||
|     return td::Status::OK(); | ||||
|   } | ||||
| 
 | ||||
|   td::Status parse_global_config() { | ||||
|     TRY_RESULT_PREFIX(global_config_data, td::read_file(global_config_), "Failed to read global config: "); | ||||
|     TRY_RESULT_PREFIX(global_config_json, td::json_decode(global_config_data.as_slice()), | ||||
|                       "Failed to parse global config: "); | ||||
|     ton_api::liteclient_config_global gc; | ||||
|     TRY_STATUS_PREFIX(ton_api::from_json(gc, global_config_json.get_object()), "Failed to parse global config: "); | ||||
|     TRY_RESULT_PREFIX(servers, liteclient::LiteServerConfig::parse_global_config(gc), | ||||
|                       "Falied to parse liteservers in global config: "); | ||||
|     if (servers.empty()) { | ||||
|       return td::Status::Error("No liteservers in global config"); | ||||
|     } | ||||
|     for (auto& s : servers) { | ||||
|       servers_.emplace_back(); | ||||
|       servers_.back().config = std::move(s); | ||||
|     } | ||||
|     return td::Status::OK(); | ||||
|   } | ||||
| 
 | ||||
|   td::Status create_ext_client() { | ||||
|     std::vector<liteclient::ExtClient::LiteServer> servers; | ||||
|     TRY_RESULT_PREFIX(global_config_data, td::read_file(global_config_), "Failed to read global config: "); | ||||
|     TRY_RESULT_PREFIX(global_config_json, td::json_decode(global_config_data.as_slice()), | ||||
|                       "Failed to parse global config: "); | ||||
|     ton::ton_api::liteclient_config_global gc; | ||||
|     ton::ton_api::from_json(gc, global_config_json.get_object()).ensure(); | ||||
| 
 | ||||
|     size_t size = gc.liteservers_.size() + gc.liteservers_v2_.size(); | ||||
|     if (size == 0) { | ||||
|       return td::Status::Error("No liteservers in global config"); | ||||
|     } | ||||
| 
 | ||||
|     for (auto& s : gc.liteservers_) { | ||||
|       td::IPAddress addr; | ||||
|       addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); | ||||
|       liteclient::ExtClient::LiteServer serv; | ||||
|       serv.address = addr; | ||||
|       serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); | ||||
|       servers.push_back(std::move(serv)); | ||||
|     } | ||||
|     for (auto& s : gc.liteservers_v2_) { | ||||
|       td::IPAddress addr; | ||||
|       addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); | ||||
|       liteclient::ExtClient::LiteServer serv; | ||||
|       serv.address = addr; | ||||
|       serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); | ||||
|       serv.is_full = false; | ||||
|       for (auto& shard : s->shards_) { | ||||
|         serv.shards.emplace_back(shard->workchain_, (ton::ShardId)shard->shard_); | ||||
|         CHECK(serv.shards.back().is_valid_ext()); | ||||
|   void run_clients() { | ||||
|     class Callback : public adnl::AdnlExtClient::Callback { | ||||
|      public: | ||||
|       explicit Callback(td::actor::ActorId<ProxyLiteserver> id, size_t idx) : id_(std::move(id)), idx_(idx) { | ||||
|       } | ||||
|       servers.push_back(std::move(serv)); | ||||
|       void on_ready() override { | ||||
|         td::actor::send_closure(id_, &ProxyLiteserver::on_client_status, idx_, true); | ||||
|       } | ||||
|       void on_stop_ready() override { | ||||
|         td::actor::send_closure(id_, &ProxyLiteserver::on_client_status, idx_, false); | ||||
|       } | ||||
| 
 | ||||
|      private: | ||||
|       td::actor::ActorId<ProxyLiteserver> id_; | ||||
|       size_t idx_; | ||||
|     }; | ||||
| 
 | ||||
|     for (size_t i = 0; i < servers_.size(); ++i) { | ||||
|       Server& server = servers_[i]; | ||||
|       server.client = adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr, | ||||
|                                                   std::make_unique<Callback>(actor_id(this), i)); | ||||
|       server.alive = false; | ||||
|     } | ||||
|     class Callback : public liteclient::ExtClient::Callback {}; | ||||
|     ext_client_ = liteclient::ExtClient::create(std::move(servers), td::make_unique<Callback>()); | ||||
|     return td::Status::OK(); | ||||
|   } | ||||
| 
 | ||||
|   void on_client_status(size_t idx, bool ready) { | ||||
|     Server& server = servers_[idx]; | ||||
|     if (server.alive == ready) { | ||||
|       return; | ||||
|     } | ||||
|     server.alive = ready; | ||||
|     LOG(WARNING) << (ready ? "Connected to" : "Disconnected from") << " server #" << idx << " (" | ||||
|                  << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")"; | ||||
|   } | ||||
| 
 | ||||
|   void create_ext_server() { | ||||
|     adnl_ = adnl::Adnl::create("", keyring_.get()); | ||||
|     td::actor::send_closure(adnl_, &adnl::Adnl::add_id, id_, ton::adnl::AdnlAddressList{}, (td::uint8)255); | ||||
|     td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server, | ||||
|                             std::vector<adnl::AdnlNodeIdShort>{id_.compute_short_id()}, std::vector<td::uint16>{port_}, | ||||
|     td::actor::send_closure(adnl_, &adnl::Adnl::add_id, id_, adnl::AdnlAddressList{}, (td::uint8)255); | ||||
| 
 | ||||
|     class AdnlCallback : public adnl::Adnl::Callback { | ||||
|      public: | ||||
|       explicit AdnlCallback(td::actor::ActorId<ProxyLiteserver> id) : id_(id) { | ||||
|       } | ||||
| 
 | ||||
|       void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override { | ||||
|       } | ||||
|       void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data, | ||||
|                          td::Promise<td::BufferSlice> promise) override { | ||||
|         td::actor::send_closure(id_, &ProxyLiteserver::receive_query, std::move(data), std::move(promise)); | ||||
|       } | ||||
| 
 | ||||
|      private: | ||||
|       td::actor::ActorId<ProxyLiteserver> id_; | ||||
|     }; | ||||
|     td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, id_.compute_short_id(), | ||||
|                             adnl::Adnl::int_to_bytestring(lite_api::liteServer_query::ID), | ||||
|                             std::make_unique<AdnlCallback>(actor_id(this))); | ||||
|     td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server, std::vector{id_.compute_short_id()}, | ||||
|                             std::vector{port_}, | ||||
|                             [SelfId = actor_id(this)](td::Result<td::actor::ActorOwn<adnl::AdnlExtServer>> R) { | ||||
|                               R.ensure(); | ||||
|                               td::actor::send_closure(SelfId, &ProxyLiteserver::created_ext_server, R.move_as_ok()); | ||||
|  | @ -158,93 +229,72 @@ class ProxyLiteserver : public td::actor::Actor { | |||
|   void created_ext_server(td::actor::ActorOwn<adnl::AdnlExtServer> s) { | ||||
|     ext_server_ = std::move(s); | ||||
|     LOG(WARNING) << "Started proxy liteserver on port " << port_; | ||||
| 
 | ||||
|     class AdnlCallback : public adnl::Adnl::Callback { | ||||
|      public: | ||||
|       AdnlCallback(td::actor::ActorId<liteclient::ExtClient> client) : client_(client) { | ||||
|       } | ||||
| 
 | ||||
|       void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override { | ||||
|       } | ||||
|       void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data, | ||||
|                          td::Promise<td::BufferSlice> promise) override { | ||||
|         td::actor::create_actor<QueryWorker>("worker", client_, std::move(data), std::move(promise)).release(); | ||||
|       } | ||||
| 
 | ||||
|      private: | ||||
|       td::actor::ActorId<liteclient::ExtClient> client_; | ||||
|     }; | ||||
|     td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, id_.compute_short_id(), | ||||
|                             adnl::Adnl::int_to_bytestring(lite_api::liteServer_query::ID), | ||||
|                             std::make_unique<AdnlCallback>(ext_client_.get())); | ||||
|     alarm(); | ||||
|   } | ||||
| 
 | ||||
|   class QueryWorker : public td::actor::Actor { | ||||
|    public: | ||||
|     QueryWorker(td::actor::ActorId<liteclient::ExtClient> client, td::BufferSlice data, | ||||
|                 td::Promise<td::BufferSlice> promise) | ||||
|         : client_(std::move(client)), data_(std::move(data)), promise_(std::move(promise)) { | ||||
|     } | ||||
| 
 | ||||
|     void start_up() override { | ||||
|       auto data = data_.clone(); | ||||
|       auto F = fetch_tl_object<lite_api::liteServer_query>(data, true); | ||||
|       if (F.is_ok()) { | ||||
|         data = std::move(F.move_as_ok()->data_); | ||||
|       } else { | ||||
|         auto G = fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true); | ||||
|         if (G.is_error()) { | ||||
|           fatal_error(G.move_as_error()); | ||||
|           return; | ||||
|         } | ||||
|   td::Result<size_t> select_server(const liteclient::QueryInfo& query_info) { | ||||
|     size_t best_idx = servers_.size(); | ||||
|     int cnt = 0; | ||||
|     for (size_t i = 0; i < servers_.size(); ++i) { | ||||
|       Server& server = servers_[i]; | ||||
|       if (!server.alive || !server.config.accepts_query(query_info)) { | ||||
|         continue; | ||||
|       } | ||||
|       fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true).ignore(); | ||||
|       auto F2 = fetch_tl_object<ton::lite_api::Function>(std::move(data), true); | ||||
|       if (F2.is_error()) { | ||||
|         fatal_error(F2.move_as_error()); | ||||
|       ++cnt; | ||||
|       if (td::Random::fast(1, cnt) == 1) { | ||||
|         best_idx = i; | ||||
|       } | ||||
|     } | ||||
|     if (best_idx == servers_.size()) { | ||||
|       return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str()); | ||||
|     } | ||||
|     return best_idx; | ||||
|   } | ||||
| 
 | ||||
|   void receive_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) { | ||||
|     liteclient::QueryInfo query_info = liteclient::get_query_info(data); | ||||
|     ++ls_stats_[query_info.query_id]; | ||||
|     promise = [promise = std::move(promise), query_info, timer = td::Timer()](td::Result<td::BufferSlice> R) mutable { | ||||
|       if (R.is_ok()) { | ||||
|         LOG(INFO) << "Query " << query_info.to_str() << ": OK, time=" << timer.elapsed() | ||||
|                   << ", response_size=" << R.ok().size(); | ||||
|         promise.set_value(R.move_as_ok()); | ||||
|         return; | ||||
|       } | ||||
|       auto query = F2.move_as_ok(); | ||||
|       lite_api::downcast_call(*query, [&](auto& obj) { shard_ = liteclient::get_query_shard(obj); }); | ||||
|       LOG(INFO) << "Query " << query_info.to_str() << ": " << R.error(); | ||||
|       promise.set_value(create_serialize_tl_object<lite_api::liteServer_error>( | ||||
|           R.error().code(), "Gateway error: " + R.error().message().str())); | ||||
|     }; | ||||
|     TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info)); | ||||
| 
 | ||||
|       LOG(INFO) << "Got query: shard=" << shard_.to_str() << " size=" << data_.size(); | ||||
|       td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "q", std::move(data_), shard_, | ||||
|                               td::Timestamp::in(8.0), [SelfId = actor_id(this)](td::Result<td::BufferSlice> R) { | ||||
|                                 td::actor::send_closure(SelfId, &QueryWorker::got_result, std::move(R)); | ||||
|                               }); | ||||
|     } | ||||
|     Server& server = servers_[server_idx]; | ||||
|     LOG(INFO) << "Sending query " << query_info.to_str() << ", size=" << data.size() << ", to server #" << server_idx | ||||
|               << " (" << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")"; | ||||
|     td::actor::send_closure(server.client, &adnl::AdnlExtClient::send_query, "q", std::move(data), | ||||
|                             td::Timestamp::in(8.0), std::move(promise)); | ||||
|   } | ||||
| 
 | ||||
|     void got_result(td::Result<td::BufferSlice> R) { | ||||
|       if (R.is_error()) { | ||||
|         LOG(INFO) << "Query to shard=" << shard_.to_str() << ": " << R.error(); | ||||
|         promise_.set_value(create_serialize_tl_object<lite_api::liteServer_error>( | ||||
|             R.error().code(), "gateway error: " + R.error().message().str())); | ||||
|       } else { | ||||
|         td::BufferSlice response = R.move_as_ok(); | ||||
|         LOG(INFO) << "Query to shard=" << shard_.to_str() << ": OK, size=" << response.size() | ||||
|                   << " time=" << timer_.elapsed(); | ||||
|         promise_.set_value(std::move(response)); | ||||
|   void alarm() override { | ||||
|     alarm_timestamp() = td::Timestamp::in(60.0); | ||||
|     if (!ls_stats_.empty()) { | ||||
|       td::StringBuilder sb; | ||||
|       sb << "Liteserver stats (1 minute):"; | ||||
|       td::uint32 total = 0; | ||||
|       for (const auto& p : ls_stats_) { | ||||
|         sb << " " << lite_query_name_by_id(p.first) << ":" << p.second; | ||||
|         total += p.second; | ||||
|       } | ||||
|       stop(); | ||||
|       sb << " TOTAL:" << total; | ||||
|       LOG(WARNING) << sb.as_cslice(); | ||||
|       ls_stats_.clear(); | ||||
|     } | ||||
| 
 | ||||
|     void fatal_error(td::Status S) { | ||||
|       promise_.set_error(std::move(S)); | ||||
|       stop(); | ||||
|     } | ||||
| 
 | ||||
|    private: | ||||
|     td::actor::ActorId<liteclient::ExtClient> client_; | ||||
|     td::BufferSlice data_; | ||||
|     td::Promise<td::BufferSlice> promise_; | ||||
|     td::Timer timer_ = {}; | ||||
|     ShardIdFull shard_; | ||||
|   }; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   std::string global_config_; | ||||
|   std::string db_root_; | ||||
|   td::uint16 port_; | ||||
|   PublicKeyHash public_key_hash_; | ||||
| 
 | ||||
|   tl_object_ptr<ton_api::proxyLiteserver_config> config_ = create_tl_object<ton_api::proxyLiteserver_config>(); | ||||
|   adnl::AdnlNodeIdFull id_; | ||||
|  | @ -252,7 +302,15 @@ class ProxyLiteserver : public td::actor::Actor { | |||
|   td::actor::ActorOwn<keyring::Keyring> keyring_; | ||||
|   td::actor::ActorOwn<adnl::Adnl> adnl_; | ||||
|   td::actor::ActorOwn<adnl::AdnlExtServer> ext_server_; | ||||
|   td::actor::ActorOwn<liteclient::ExtClient> ext_client_; | ||||
| 
 | ||||
|   struct Server { | ||||
|     liteclient::LiteServerConfig config; | ||||
|     td::actor::ActorOwn<adnl::AdnlExtClient> client; | ||||
|     bool alive = false; | ||||
|   }; | ||||
|   std::vector<Server> servers_; | ||||
| 
 | ||||
|   std::map<int, td::uint32> ls_stats_;  // lite_api ID -> count, 0 for unknown
 | ||||
| 
 | ||||
|   std::string config_file() const { | ||||
|     return db_root_ + "/config.json"; | ||||
|  | @ -270,6 +328,7 @@ int main(int argc, char* argv[]) { | |||
| 
 | ||||
|   std::string global_config, db_root; | ||||
|   td::uint16 port = 0; | ||||
|   PublicKeyHash public_key_hash = PublicKeyHash::zero(); | ||||
|   td::uint32 threads = 4; | ||||
| 
 | ||||
|   td::OptionParser p; | ||||
|  | @ -290,15 +349,27 @@ int main(int argc, char* argv[]) { | |||
|     std::cout << sb.as_cslice().c_str(); | ||||
|     std::exit(2); | ||||
|   }); | ||||
|   p.add_checked_option('p', "port", "liteserver port (use only on first launch)", [&](td::Slice arg) -> td::Status { | ||||
|     TRY_RESULT_ASSIGN(port, td::to_integer_safe<td::uint16>(arg)); | ||||
|     return td::Status::OK(); | ||||
|   }); | ||||
|   p.add_checked_option('p', "port", "liteserver port (required only on first launch)", | ||||
|                        [&](td::Slice arg) -> td::Status { | ||||
|                          TRY_RESULT_ASSIGN(port, td::to_integer_safe<td::uint16>(arg)); | ||||
|                          return td::Status::OK(); | ||||
|                        }); | ||||
|   p.add_checked_option( | ||||
|       'A', "adnl-id", | ||||
|       "liteserver public key hash in hex (optional). The corresponding private key is required in <db>/keyring/", | ||||
|       [&](td::Slice arg) -> td::Status { | ||||
|         td::Bits256 value; | ||||
|         if (value.from_hex(arg) != 256) { | ||||
|           return td::Status::Error("invalid adnl-id"); | ||||
|         } | ||||
|         public_key_hash = PublicKeyHash{value}; | ||||
|         return td::Status::OK(); | ||||
|       }); | ||||
|   p.add_option('C', "global-config", "global TON configuration file", | ||||
|                [&](td::Slice arg) { global_config = arg.str(); }); | ||||
|   p.add_option('D', "db", "db root", [&](td::Slice arg) { db_root = arg.str(); }); | ||||
|   p.add_option('d', "daemonize", "set SIGHUP", [&]() { | ||||
|     td::set_signal_handler(td::SignalType::HangUp, [](int sig) { | ||||
|     td::set_signal_handler(td::SignalType::HangUp, [](int) { | ||||
| #if TD_DARWIN || TD_LINUX | ||||
|       close(0); | ||||
|       setsid(); | ||||
|  | @ -318,8 +389,10 @@ int main(int argc, char* argv[]) { | |||
|   p.run(argc, argv).ensure(); | ||||
|   td::actor::Scheduler scheduler({threads}); | ||||
| 
 | ||||
|   scheduler.run_in_context( | ||||
|       [&] { td::actor::create_actor<ProxyLiteserver>("proxy-liteserver", global_config, db_root, port).release(); }); | ||||
|   scheduler.run_in_context([&] { | ||||
|     td::actor::create_actor<ProxyLiteserver>("proxy-liteserver", global_config, db_root, port, public_key_hash) | ||||
|         .release(); | ||||
|   }); | ||||
|   while (scheduler.run(1)) { | ||||
|   } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue