diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index 408b1c5d..99bbc927 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -217,6 +217,9 @@ blocks.transactions id:ton.blockIdExt req_count:int32 incomplete:Bool transactio blocks.header id:ton.blockIdExt global_id:int32 version:int32 flags:# after_merge:Bool after_split:Bool before_split:Bool want_merge:Bool want_split:Bool validator_list_hash_short:int32 catchain_seqno:int32 min_ref_mc_seqno:int32 is_key_block:Bool prev_key_block_seqno:int32 start_lt:int64 end_lt:int64 gen_utime:int53 vert_seqno:# prev_blocks:vector = blocks.Header; //blocks.shortData header:blocks.Header transactions:blocks.Header = blocks.BlockData; +blocks.signature node_id_short:int256 signature:bytes = blocks.Signature; +blocks.blockSignatures id:ton.blockIdExt signatures:(vector blocks.signature) = blocks.BlockSignatures; + configInfo config:tvm.cell = ConfigInfo; ---functions--- @@ -307,6 +310,7 @@ blocks.getShards id:ton.blockIdExt = blocks.Shards; blocks.lookupBlock mode:int32 id:ton.blockId lt:int64 utime:int32 = ton.BlockIdExt; blocks.getTransactions id:ton.blockIdExt mode:# count:# after:blocks.accountTransactionId = blocks.Transactions; blocks.getBlockHeader id:ton.blockIdExt = blocks.Header; +blocks.getMasterchainBlockSignatures seqno:int32 = blocks.BlockSignatures; onLiteServerQueryResult id:int64 bytes:bytes = Ok; onLiteServerQueryError id:int64 error:error = Ok; diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index e2d32cea..0cc2a6d9 100644 Binary files a/tl/generate/scheme/tonlib_api.tlo and b/tl/generate/scheme/tonlib_api.tlo differ diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 12dbcd2b..14fd4100 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -41,6 +41,7 @@ #include "block/check-proof.h" #include "ton/lite-tl.hpp" #include "ton/ton-shard.h" +#include "lite-client/lite-client-common.h" #include "vm/boc.h" #include "vm/cellops.h" @@ -1317,6 +1318,148 @@ class GetRawAccountState : public td::actor::Actor { } }; +class GetMasterchainBlockSignatures : public td::actor::Actor { + public: + GetMasterchainBlockSignatures(ExtClientRef ext_client_ref, ton::BlockSeqno seqno, td::actor::ActorShared<> parent, + td::Promise>&& promise) + : block_id_short_(ton::masterchainId, ton::shardIdAll, seqno) + , parent_(std::move(parent)) + , promise_(std::move(promise)) { + client_.set_client(ext_client_ref); + } + + void start_up() override { + if (block_id_short_.seqno == 0) { + abort(td::Status::Error("can't get signatures of block #0")); + return; + } + client_.with_last_block([SelfId = actor_id(this)](td::Result R) { + if (R.is_error()) { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::abort, R.move_as_error()); + } else { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::got_last_block, R.ok().last_block_id); + } + }); + } + + void got_last_block(ton::BlockIdExt id) { + last_block_ = id; + prev_block_id_short_ = block_id_short_; + prev_block_id_short_.seqno--; + client_.send_query( + ton::lite_api::liteServer_lookupBlock(1, ton::create_tl_lite_block_id_simple(prev_block_id_short_), 0, 0), + [SelfId = actor_id(this)](td::Result> R) { + if (R.is_error()) { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::abort, R.move_as_error()); + } else { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::got_prev_block_id, + ton::create_block_id(R.ok()->id_)); + } + }); + } + + void got_prev_block_id(ton::BlockIdExt id) { + prev_block_id_ = id; + if (prev_block_id_.id != prev_block_id_short_) { + abort(td::Status::Error("got incorrect block header from liteserver")); + return; + } + client_.send_query( + ton::lite_api::liteServer_getBlockProof(0x1001, ton::create_tl_lite_block_id(last_block_), + ton::create_tl_lite_block_id(prev_block_id_)), + [SelfId = actor_id(this)](td::Result> R) { + if (R.is_error()) { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::abort, R.move_as_error()); + } else { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::got_prev_proof, R.move_as_ok()); + } + }); + } + + void got_prev_proof(lite_api_ptr proof) { + auto R = liteclient::deserialize_proof_chain(std::move(proof)); + if (R.is_error()) { + abort(R.move_as_error()); + return; + } + auto chain = R.move_as_ok(); + if (chain->from != last_block_ || chain->to != prev_block_id_ || !chain->complete) { + abort(td::Status::Error("got invalid proof chain")); + return; + } + auto S = chain->validate(); + if (S.is_error()) { + abort(std::move(S)); + return; + } + client_.send_query( + ton::lite_api::liteServer_lookupBlock(1, ton::create_tl_lite_block_id_simple(block_id_short_), 0, 0), + [SelfId = actor_id(this)](td::Result> R) { + if (R.is_error()) { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::abort, R.move_as_error()); + } else { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::got_block_id, + ton::create_block_id(R.ok()->id_)); + } + }); + } + + void got_block_id(ton::BlockIdExt id) { + block_id_ = id; + client_.send_query( + ton::lite_api::liteServer_getBlockProof(0x1001, ton::create_tl_lite_block_id(prev_block_id_), + ton::create_tl_lite_block_id(block_id_)), + [SelfId = actor_id(this)](td::Result> R) { + if (R.is_error()) { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::abort, R.move_as_error()); + } else { + td::actor::send_closure(SelfId, &GetMasterchainBlockSignatures::got_proof, R.move_as_ok()); + } + }); + } + + void got_proof(lite_api_ptr proof) { + auto R = liteclient::deserialize_proof_chain(std::move(proof)); + if (R.is_error()) { + abort(R.move_as_error()); + return; + } + auto chain = R.move_as_ok(); + if (chain->from != prev_block_id_ || chain->to != block_id_ || !chain->complete || chain->links.empty() || + chain->last_link().signatures.empty()) { + abort(td::Status::Error("got invalid proof chain")); + return; + } + auto S = chain->validate(); + if (S.is_error()) { + abort(std::move(S)); + return; + } + std::vector> signatures; + for (const auto& s : chain->last_link().signatures) { + signatures.push_back(ton::create_tl_object(s.node, s.signature.as_slice().str())); + } + promise_.set_result( + ton::create_tl_object(to_tonlib_api(block_id_), std::move(signatures))); + stop(); + } + + void abort(td::Status error) { + promise_.set_error(std::move(error)); + stop(); + } + + private: + ton::BlockId block_id_short_; + td::actor::ActorShared<> parent_; + td::Promise> promise_; + ExtClient client_; + ton::BlockIdExt block_id_; + ton::BlockId prev_block_id_short_; + ton::BlockIdExt prev_block_id_; + ton::BlockIdExt last_block_; +}; + TonlibClient::TonlibClient(td::unique_ptr callback) : callback_(std::move(callback)) { } TonlibClient::~TonlibClient() = default; @@ -4471,6 +4614,15 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getBlockHeader& req return td::Status::OK(); } +td::Status TonlibClient::do_request(const tonlib_api::blocks_getMasterchainBlockSignatures& request, + td::Promise>&& promise) { + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetMasterchainBlockSignatures", client_.get_client(), request.seqno_, actor_shared(this, actor_id), + std::move(promise)); + return td::Status::OK(); +} + void TonlibClient::load_libs_from_disk() { LOG(DEBUG) << "loading libraries from disk cache"; auto r_data = kv_->get("tonlib.libcache"); diff --git a/tonlib/tonlib/TonlibClient.h b/tonlib/tonlib/TonlibClient.h index 02c06e17..bbb9b900 100644 --- a/tonlib/tonlib/TonlibClient.h +++ b/tonlib/tonlib/TonlibClient.h @@ -364,6 +364,8 @@ class TonlibClient : public td::actor::Actor { td::Promise>&& promise); td::Status do_request(const tonlib_api::blocks_getBlockHeader& request, td::Promise>&& promise); + td::Status do_request(const tonlib_api::blocks_getMasterchainBlockSignatures& request, + td::Promise>&& promise); td::Status do_request(const tonlib_api::getConfigParam& request, td::Promise>&& promise); diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index be550454..e889234a 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -430,6 +430,7 @@ class TonlibCli : public td::actor::Actor { << "\t 'e' modifier - encrypt all messages\n" << "\t 'k' modifier - use fake key\n" << "\t 'c' modifier - just esmitate fees\n"; + td::TerminalIO::out() << "getmasterchainsignatures - get sigratures of masterchain block \n"; } else if (cmd == "genkey") { generate_key(); } else if (cmd == "exit" || cmd == "quit") { @@ -510,6 +511,9 @@ class TonlibCli : public td::actor::Actor { auto key = parser.read_word(); auto init_key = parser.read_word(); guess_account(key, init_key, std::move(cmd_promise)); + } else if (cmd == "getmasterchainsignatures") { + auto seqno = parser.read_word(); + run_get_masterchain_block_signatures(seqno, std::move(cmd_promise)); } else { cmd_promise.set_error(td::Status::Error(PSLICE() << "Unkwnown query `" << cmd << "`")); } @@ -2096,6 +2100,18 @@ class TonlibCli : public td::actor::Actor { })); } + void run_get_masterchain_block_signatures(td::Slice seqno_s, td::Promise promise) { + TRY_RESULT_PROMISE(promise, seqno, td::to_integer_safe(seqno_s)); + send_query(make_object(seqno), promise.wrap([](auto signatures) { + td::TerminalIO::out() << "Signatures: " << signatures->signatures_.size() << "\n"; + for (const auto& s : signatures->signatures_) { + td::TerminalIO::out() << " " << s->node_id_short_ << " : " << td::base64_encode(td::Slice(s->signature_)) + << "\n"; + } + return td::Unit(); + })); + } + void get_history2(td::Slice key, td::Result> r_state, td::Promise promise) { TRY_RESULT_PROMISE(promise, state, std::move(r_state));