From dd745485e26cf581019c2b8c3013d4c14ec0473e Mon Sep 17 00:00:00 2001 From: ton Date: Fri, 4 Oct 2019 16:08:02 +0400 Subject: [PATCH] update tonlib tonlib: update collator: increased collation speed for masterchain fift: bugfixes --- crypto/block/mc-config.cpp | 2 +- crypto/common/bigint.hpp | 6 +- crypto/fift/fift-main.cpp | 4 +- crypto/func/analyzer.cpp | 2 +- crypto/tl/boc.tlb | 3 +- crypto/vm/boc.cpp | 11 +-- crypto/vm/cells/CellBuilder.cpp | 3 - doc/tblkch.tex | 54 ++++++++------ tl/generate/scheme/tonlib_api.tl | 4 +- tl/generate/scheme/tonlib_api.tlo | Bin 13000 -> 13072 bytes tonlib/test/offline.cpp | 5 +- tonlib/tonlib/ExtClient.h | 7 +- tonlib/tonlib/KeyStorage.cpp | 28 +++++--- tonlib/tonlib/KeyValue.cpp | 2 +- tonlib/tonlib/LastBlock.cpp | 37 ++++++++-- tonlib/tonlib/LastBlock.h | 2 + tonlib/tonlib/TonlibClient.cpp | 40 +++++++---- tonlib/tonlib/TonlibError.h | 3 + tonlib/tonlib/keys/DecryptedKey.cpp | 23 +----- tonlib/tonlib/keys/DecryptedKey.h | 2 - tonlib/tonlib/keys/EncryptedKey.cpp | 14 ++-- tonlib/tonlib/keys/EncryptedKey.h | 2 +- tonlib/tonlib/tonlib-cli.cpp | 75 +++++++++++++++++--- validator/impl/collator.cpp | 40 +++++++++-- validator/impl/liteserver.cpp | 105 +++++++++++++++++----------- validator/impl/liteserver.hpp | 7 +- validator/manager.cpp | 4 +- 27 files changed, 313 insertions(+), 172 deletions(-) diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index a8fbeed..ceefca7 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -897,7 +897,7 @@ static int process_workchain_shard_hashes(Ref& branch, ton::ShardIdFul int f = (int)cs.fetch_ulong(1); if (f == 1) { if ((shard.shard & 1) || cs.size_ext() != 0x20000) { - return false; + return -1; } auto left = cs.prefetch_ref(0), right = cs.prefetch_ref(1); int r = process_workchain_shard_hashes(left, ton::shard_child(shard, true), func); diff --git a/crypto/common/bigint.hpp b/crypto/common/bigint.hpp index 63bfe46..6734f07 100644 --- a/crypto/common/bigint.hpp +++ b/crypto/common/bigint.hpp @@ -1922,7 +1922,7 @@ bool AnyIntView::export_bits_any(unsigned char* buff, int offs, unsigned bit if (--ptr > buff) { *ptr = (unsigned char)(v & 0xff); } else { - int mask = (-0x100 >> offs) & 0xff; + int mask = (0xff00 >> offs) & 0xff; if (((unsigned char)v ^ s) & mask) { return false; } @@ -1943,7 +1943,7 @@ bool AnyIntView::export_bits_any(unsigned char* buff, int offs, unsigned bit if (--ptr > buff) { *ptr = (unsigned char)(v & 0xff); } else { - int mask = (-0x100 >> offs) & 0xff; + int mask = (0xff00 >> offs) & 0xff; if (((unsigned char)v ^ s) & mask) { return false; } @@ -1961,7 +1961,7 @@ bool AnyIntView::export_bits_any(unsigned char* buff, int offs, unsigned bit *ptr = (unsigned char)(v & 0xff); v >>= 8; } - int mask = (-0x100 >> offs) & 0xff; + int mask = (0xff00 >> offs) & 0xff; if (((unsigned char)v ^ s) & mask) { return false; } diff --git a/crypto/fift/fift-main.cpp b/crypto/fift/fift-main.cpp index e040b6e..8702f13 100644 --- a/crypto/fift/fift-main.cpp +++ b/crypto/fift/fift-main.cpp @@ -132,9 +132,7 @@ int main(int argc, char* const argv[]) { if (!no_env) { const char* path = std::getenv("FIFTPATH"); - if (path) { - parse_include_path_set(path ? path : "/usr/lib/fift", source_include_path); - } + parse_include_path_set(path ? path : "/usr/lib/fift", source_include_path); } std::string current_dir; auto r_current_dir = td::realpath("."); diff --git a/crypto/func/analyzer.cpp b/crypto/func/analyzer.cpp index 207aa64..4d2e790 100644 --- a/crypto/func/analyzer.cpp +++ b/crypto/func/analyzer.cpp @@ -138,7 +138,7 @@ bool Op::set_var_info_except(const VarDescrList& new_var_info, const std::vector } VarDescrList tmp_info{new_var_info}; tmp_info -= var_list; - return set_var_info(new_var_info); + return set_var_info(tmp_info); } bool Op::set_var_info_except(VarDescrList&& new_var_info, const std::vector& var_list) { diff --git a/crypto/tl/boc.tlb b/crypto/tl/boc.tlb index c296cb6..d283c78 100644 --- a/crypto/tl/boc.tlb +++ b/crypto/tl/boc.tlb @@ -31,8 +31,9 @@ serialized_boc#b5ee9c72 has_idx:(## 1) has_crc32c:(## 1) absent:(##(size * 8)) { roots + absent <= cells } tot_cells_size:(##(off_bytes * 8)) root_list:(roots * ##(size * 8)) - index:(cells * ##(off_bytes * 8)) + index:has_idx?(cells * ##(off_bytes * 8)) cell_data:(tot_cells_size * [ uint8 ]) + crc32c:has_crc32c?uint32 = BagOfCells; compiled_smart_contract diff --git a/crypto/vm/boc.cpp b/crypto/vm/boc.cpp index 9b60884..fbb39df 100644 --- a/crypto/vm/boc.cpp +++ b/crypto/vm/boc.cpp @@ -75,7 +75,7 @@ td::Result CellSerializationInfo::get_bits(td::Slice cell) const { if (data_with_bits) { DCHECK(data_len != 0); int last = cell[data_offset + data_len - 1]; - if (!last || last == 0x80) { + if (!(last & 0x7f)) { return td::Status::Error("overlong encoding"); } return td::narrow_cast((data_len - 1) * 8 + 7 - td::count_trailing_zeroes_non_zero32(last)); @@ -391,15 +391,6 @@ td::uint64 BagOfCells::compute_sizes(int mode, int& r_size, int& o_size) { r_size = o_size = 0; return 0; } - if (!(mode & Mode::WithIndex)) { - if (rs > 2 || os > 4) { - rs = std::max(3, rs); - os = 8; - data_bytes_adj = data_bytes + (unsigned long long)int_refs * rs + hashes; - } else { - os = 4; - } - } r_size = rs; o_size = os; return data_bytes_adj; diff --git a/crypto/vm/cells/CellBuilder.cpp b/crypto/vm/cells/CellBuilder.cpp index 37940f7..223959b 100644 --- a/crypto/vm/cells/CellBuilder.cpp +++ b/crypto/vm/cells/CellBuilder.cpp @@ -527,9 +527,6 @@ int CellBuilder::serialize(unsigned char* buff, int buff_size) const { CellBuilder* CellBuilder::make_copy() const { CellBuilder* c = new CellBuilder(); - if (!c) { - throw CellWriteError(); - } c->bits = bits; std::memcpy(c->data, data, (bits + 7) >> 3); c->refs_cnt = refs_cnt; diff --git a/doc/tblkch.tex b/doc/tblkch.tex index 10de9cd..daf5006 100644 --- a/doc/tblkch.tex +++ b/doc/tblkch.tex @@ -2000,36 +2000,46 @@ In addition to the values listed in~\ptref{sp:boc.ser.class}, fixed by the choic \end{itemize} \nxsubpoint\label{sp:boc.ser.sch}\emb{TL-B scheme for serializing bags of cells} -Several TL-B constructors can be used to serialize bags of cells into octet (i.e., 8-bit byte) sequences: +Several TL-B constructors can be used to serialize bags of cells into octet (i.e., 8-bit byte) sequences. The only one that is currently used to serialize new bags of cell is \begin{verbatim} -serialized_boc_tiny cells:uint8 roots:uint8 absent:uint8 - tot_cells_size:(## 32) cell_data:(tot_cells_size * [ uint8 ]) - = BagOfCells; -serialized_boc_small cells:uint16 roots:uint16 absent:uint16 - tot_cells_size:(## 32) cell_data:(tot_cells_size * [ uint8 ]) - = BagOfCells; -serialized_boc_medium cells:uint24 roots:uint24 absent:uint24 - tot_cells_size:(## 64) cell_data:(tot_cells_size * [ uint8 ]) - = BagOfCells; -serialized_boc_large cells:uint32 roots:uint32 absent:uint32 - tot_cells_size:(## 64) cell_data:(tot_cells_size * [ uint8 ]) - = BagOfCells; -\end{verbatim} -Field {\tt cells} is $n$, {\tt roots} is $k$, {\tt absent} is $l$, and {\tt tot\_cells\_size} is $L_n$ (the total size of the serialization of all cells in bytes). - -If an index is present, parameters $s/8$ and $t/8$ are serialized separately as 8-bit fields {\tt size} and {\tt off\_bytes}, respectively: -\begin{verbatim} -serialized_boc_idx size:(## 8) { size <= 4 } +serialized_boc#b5ee9c72 has_idx:(## 1) has_crc32c:(## 1) + has_cache_bits:(## 1) flags:(## 2) { flags = 0 } + size:(## 3) { size <= 4 } off_bytes:(## 8) { off_bytes <= 8 } cells:(##(size * 8)) - roots:(##(size * 8)) + roots:(##(size * 8)) { roots >= 1 } absent:(##(size * 8)) { roots + absent <= cells } tot_cells_size:(##(off_bytes * 8)) - index:(cells * [ ##(off_bytes * 8) ]) + root_list:(roots * ##(size * 8)) + index:has_idx?(cells * ##(off_bytes * 8)) cell_data:(tot_cells_size * [ uint8 ]) + crc32c:has_crc32c?uint32 = BagOfCells; \end{verbatim} -Finally, constructors {\tt serialized\_boc\_*\_crc32}, with the asterisk replaced by either {\tt tiny}, {\tt small}, {\tt medium}, {\tt large}, or {\tt idx}, are also introduced, with one extra field {\tt crc32c:uint32} added as the last field. +Field {\tt cells} is $n$, {\tt roots} is $k$, {\tt absent} is $l$, and {\tt tot\_cells\_size} is $L_n$ (the total size of the serialization of all cells in bytes). If an index is present, parameters $s/8$ and $t/8$ are serialized separately as {\tt size} and {\tt off\_bytes}, respectively, and the flag {\tt has\_idx} is set. The index itself is contained in {\tt index}, present only if {\tt has\_idx} is set. The field {\tt root\_list} contains the (zero-based) indices of the root nodes of the bag of cells. + +Two older constructors are still supported in the bag-of-cells deserialization functions: +\begin{verbatim} +serialized_boc_idx#68ff65f3 size:(## 8) { size <= 4 } + off_bytes:(## 8) { off_bytes <= 8 } + cells:(##(size * 8)) + roots:(##(size * 8)) { roots = 1 } + absent:(##(size * 8)) { roots + absent <= cells } + tot_cells_size:(##(off_bytes * 8)) + index:(cells * ##(off_bytes * 8)) + cell_data:(tot_cells_size * [ uint8 ]) + = BagOfCells; + +serialized_boc_idx_crc32c#acc3a728 size:(## 8) { size <= 4 } + off_bytes:(## 8) { off_bytes <= 8 } + cells:(##(size * 8)) + roots:(##(size * 8)) { roots = 1 } + absent:(##(size * 8)) { roots + absent <= cells } + tot_cells_size:(##(off_bytes * 8)) + index:(cells * ##(off_bytes * 8)) + cell_data:(tot_cells_size * [ uint8 ]) + crc32c:uint32 = BagOfCells; +\end{verbatim} \nxsubpoint\emb{Storing compiled TVM code in files} Notice that the above procedure for serializing bags of cells may be used to serialize compiled smart contracts and other TVM code. One must define a TL-B constructor similar to the following: diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index deae3fa..c0dc53c 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -38,7 +38,7 @@ unpackedAccountAddress workchain_id:int32 bounceable:Bool testnet:Bool addr:byte internal.transactionId lt:int64 hash:bytes = internal.TransactionId; raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; -raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState; +raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId frozen_hash:bytes sync_utime:int53 = raw.AccountState; raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes = raw.Message; raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; @@ -51,7 +51,7 @@ wallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.trans testGiver.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53= testGiver.AccountState; -uninited.accountState balance:int64 last_transaction_id:internal.transactionId sync_utime:int53 = uninited.AccountState; +uninited.accountState balance:int64 last_transaction_id:internal.transactionId frozen_hash:bytes sync_utime:int53 = uninited.AccountState; //generic.initialAccountStateRaw initital_account_state:raw.initialAccountState = generic.InitialAccountState; //generic.initialAccountStateTestWallet initital_account_state:testWallet.initialAccountState = generic.InitialAccountState; diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index 180f3521725fa8e4ac53b9db1d7e62587be7636c..1050a59cfde56bf149a42689b6fab05c8647c041 100644 GIT binary patch delta 230 zcmX?+Iw5U?04s}^>_hj>BCH*ZEL$0@Pi|homcauSn{1$@uvtfV21FdhoBTqgMiHc3 zpeV6iFEKeezcjBTxFoS8m4Sf)B!2UlkPqABk230$*NEouaHkdJSEc5~XCxM9OimCK znOq>jGI@=Z2E;}eu{*2^AR9$X^D^@?OHxzNOa#eIej}qZ`HiR!ZnMB{J|c4l>gEF) QDw7ZBi9oElp!tIX0Ak@%uK)l5 delta 185 zcmbP`b|Q6y04s~s=4R>5BCH*ZEG^ISGdC|_%iw{C@d)pLh)w1ZR+#)kq(%{>RG=ua zTrV*>IlnZoB)BB8B$a`I0VIC&n2-7$!kP&CSQ=!fEbb?c866JWUy#yUS?iq nNooq3W{@06FEd#01Q{K$Ua(VmWY0jHGC4rW0%Dwm)(;K( - make_object(nullptr, make_object(".")))) + sync_send(client, make_object(make_object( + nullptr, make_object("testdir")))) .ensure(); auto local_password = td::SecureString("local password"); auto mnemonic_password = td::SecureString("mnemonic password"); diff --git a/tonlib/tonlib/ExtClient.h b/tonlib/tonlib/ExtClient.h index 69af0c0..1547337 100644 --- a/tonlib/tonlib/ExtClient.h +++ b/tonlib/tonlib/ExtClient.h @@ -61,15 +61,14 @@ class ExtClient { 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); - td::BufferSlice liteserver_query = - ton::serialize_tl_object(ton::create_tl_object(std::move(raw_query)), true); - if (seq_no >= 0) { auto wait = ton::lite_api::liteServer_waitMasterchainSeqno(seq_no, 5000); VLOG(lite_server) << " with prefix " << to_string(wait); auto prefix = ton::serialize_tl_object(&wait, true); - liteserver_query = td::BufferSlice(PSLICE() << prefix.as_slice() << liteserver_query.as_slice()); + raw_query = td::BufferSlice(PSLICE() << prefix.as_slice() << raw_query.as_slice()); } + td::BufferSlice liteserver_query = + ton::serialize_tl_object(ton::create_tl_object(std::move(raw_query)), true); send_raw_query( std::move(liteserver_query), [promise = std::move(promise), tag](td::Result R) mutable { diff --git a/tonlib/tonlib/KeyStorage.cpp b/tonlib/tonlib/KeyStorage.cpp index fd66077..6e01f2f 100644 --- a/tonlib/tonlib/KeyStorage.cpp +++ b/tonlib/tonlib/KeyStorage.cpp @@ -69,7 +69,7 @@ td::Result KeyStorage::export_decrypted_key(InputKey input_key) { if (r_encrypted_data.is_error()) { r_encrypted_data = kv_->get(to_file_name_old(input_key.key)); if (r_encrypted_data.is_ok()) { - LOG(WARNING) << "Restore private from deprecated location " << to_file_name_old(input_key.key) << " --> " + LOG(WARNING) << "Restore private key from deprecated location " << to_file_name_old(input_key.key) << " --> " << to_file_name(input_key.key); TRY_STATUS_PREFIX(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok()), TonlibError::Internal()); kv_->erase(to_file_name_old(input_key.key)).ignore(); @@ -78,6 +78,21 @@ td::Result KeyStorage::export_decrypted_key(InputKey input_key) { TRY_RESULT_PREFIX(encrypted_data, std::move(r_encrypted_data), TonlibError::KeyUnknown()); EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)), std::move(input_key.key.secret)}; + { + auto r_decrypted_key = encrypted_key.decrypt(input_key.local_password.copy(), true, true); + if (r_decrypted_key.is_ok()) { + LOG(WARNING) << "Restore private from deprecated encryption " << to_file_name(input_key.key); + auto decrypted_key = r_decrypted_key.move_as_ok(); + auto key = Key{encrypted_key.public_key.as_octet_string(), encrypted_key.secret.copy()}; + auto new_encrypted_key = decrypted_key.encrypt(input_key.local_password.copy(), encrypted_key.secret); + CHECK(new_encrypted_key.public_key.as_octet_string() == encrypted_key.public_key.as_octet_string()); + CHECK(new_encrypted_key.secret == encrypted_key.secret); + CHECK(new_encrypted_key.decrypt(input_key.local_password.copy()).ok().private_key.as_octet_string() == + decrypted_key.private_key.as_octet_string()); + kv_->set(to_file_name(key), new_encrypted_key.encrypted_data); + return std::move(decrypted_key); + } + } TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(std::move(input_key.local_password)), TonlibError::KeyDecrypt()); return std::move(decrypted_key); @@ -139,14 +154,9 @@ td::Result KeyStorage::export_pem_key(InputKey input } td::Result KeyStorage::change_local_password(InputKey input_key, td::Slice new_local_password) { - auto new_secret = - DecryptedKey::change_local_password(input_key.key.secret, input_key.local_password, new_local_password); - Key res; - res.public_key = std::move(input_key.key.public_key); - res.secret = std::move(new_secret); - TRY_RESULT_PREFIX(value, kv_->get(to_file_name(input_key.key)), TonlibError::KeyUnknown()); - TRY_STATUS_PREFIX(kv_->add(to_file_name(res), value), TonlibError::Internal()); - return std::move(res); + auto old_name = to_file_name(input_key.key); + TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key))); + return save_key(std::move(decrypted_key), new_local_password); } td::Result KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password, diff --git a/tonlib/tonlib/KeyValue.cpp b/tonlib/tonlib/KeyValue.cpp index d71744f..7969692 100644 --- a/tonlib/tonlib/KeyValue.cpp +++ b/tonlib/tonlib/KeyValue.cpp @@ -39,7 +39,7 @@ class KeyValueDir : public KeyValue { } td::Status erase(td::Slice key) override { - return td::unlink(key.str()); + return td::unlink(to_file_path(key.str())); } void foreach_key(std::function f) override { diff --git a/tonlib/tonlib/LastBlock.cpp b/tonlib/tonlib/LastBlock.cpp index fd15fed..d498aa7 100644 --- a/tonlib/tonlib/LastBlock.cpp +++ b/tonlib/tonlib/LastBlock.cpp @@ -32,7 +32,8 @@ namespace tonlib { // td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) { return sb << td::tag("last_block", state.last_block_id.to_str()) - << td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime); + << td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime) + << td::tag("init_block", state.init_block_id.to_str()); } LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr callback) @@ -40,8 +41,7 @@ LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, t client_.set_client(client); state_.last_block_id = state_.last_key_block_id; - VLOG(last_block) << "check_init_block: skip - FIXME before release"; - check_init_block_state_ = QueryState::Done; + VLOG(last_block) << "State: " << state_; } void LastBlock::get_last_block(td::Promise promise) { @@ -87,7 +87,7 @@ void LastBlock::sync_loop() { } else { check_init_block_state_ = QueryState::Active; check_init_block_stats_.start(); - if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) { + if (state_.last_key_block_id.id.seqno >= config_.init_block_id.id.seqno) { VLOG(last_block) << "check_init_block: start - init_block -> last_block"; do_check_init_block(config_.init_block_id, state_.last_key_block_id); } else { @@ -162,10 +162,18 @@ void LastBlock::update_state(block::BlockProofChain& chain) { update_utime(chain.last_utime); } if (is_changed) { - callback_->on_state_changed(state_); + save_state(); } } +void LastBlock::save_state() { + if (check_init_block_state_ != QueryState::Done) { + VLOG(last_block) << "skip `save_state` because `check_init_block` is not finished"; + return; + } + callback_->on_state_changed(state_); +} + void LastBlock::on_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { @@ -209,6 +217,9 @@ void LastBlock::on_init_block_proof( if (chain->complete) { VLOG(last_block) << "check_init_block: done\n" << check_init_block_stats_; check_init_block_state_ = QueryState::Done; + if (update_init_block(config_.init_block_id)) { + save_state(); + } sync_loop(); } else { do_check_init_block(chain->to, to); @@ -291,6 +302,22 @@ bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) { return false; } +bool LastBlock::update_init_block(ton::BlockIdExt init_block_id) { + if (has_fatal_error()) { + return false; + } + if (!init_block_id.is_valid()) { + LOG(ERROR) << "Ignore invalid init block"; + return false; + } + if (state_.init_block_id != init_block_id) { + state_.init_block_id = init_block_id; + LOG(INFO) << "Update init block id: " << state_.init_block_id.to_str(); + return true; + } + return false; +} + void LastBlock::update_utime(td::int64 utime) { if (state_.utime < utime) { state_.utime = utime; diff --git a/tonlib/tonlib/LastBlock.h b/tonlib/tonlib/LastBlock.h index bb2a62e..edd8c6f 100644 --- a/tonlib/tonlib/LastBlock.h +++ b/tonlib/tonlib/LastBlock.h @@ -201,7 +201,9 @@ class LastBlock : public td::actor::Actor { bool update_mc_last_block(ton::BlockIdExt mc_block_id); bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); void update_utime(td::int64 utime); + bool update_init_block(ton::BlockIdExt init_block_id); + void save_state(); void on_sync_ok(); void on_sync_error(td::Status status); void on_fatal_error(td::Status status); diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 7989e18..63203df 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -108,7 +108,6 @@ class GetTransactionHistory : public td::actor::Actor { void check(td::Status status) { if (status.is_error()) { - LOG(ERROR) << status; promise_.set_error(std::move(status)); stop(); } @@ -208,7 +207,7 @@ class GetRawAccountState : public td::actor::Actor { auto cell = res.info.root; std::ostringstream outp; block::gen::t_Account.print_ref(outp, cell); - LOG(ERROR) << outp.str(); + LOG(INFO) << outp.str(); if (cell.is_null()) { return res; } @@ -682,8 +681,9 @@ td::Result> to_raw_accountS .as_slice() .str(); } - return tonlib_api::make_object( - raw_state.balance, std::move(code), std::move(data), to_transaction_id(raw_state.info), raw_state.info.gen_utime); + return tonlib_api::make_object(raw_state.balance, std::move(code), std::move(data), + to_transaction_id(raw_state.info), raw_state.frozen_hash, + raw_state.info.gen_utime); } td::Result to_std_address_or_throw(td::Ref cs) { @@ -803,7 +803,7 @@ td::Result> to_raw_transacti std::ostringstream outp; block::gen::t_Transaction.print_ref(outp, info.transaction); - LOG(ERROR) << outp.str(); + LOG(INFO) << outp.str(); auto is_just = trans.r1.in_msg->prefetch_long(1); if (is_just == trans.r1.in_msg->fetch_long_eof) { @@ -917,7 +917,7 @@ td::Result> to_generic_ if (raw_state.code.is_null()) { return tonlib_api::make_object( tonlib_api::make_object(raw_state.balance, to_transaction_id(raw_state.info), - raw_state.info.gen_utime)); + raw_state.frozen_hash, raw_state.info.gen_utime)); } auto code_hash = raw_state.code->prefetch_ref()->get_hash(); @@ -953,7 +953,6 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_sendMessage& request, client_.send_query(ton::lite_api::liteServer_sendMessage(vm::std_boc_serialize(message).move_as_ok()), [promise = std::move(promise)](auto r_info) mutable { TRY_RESULT_PROMISE(promise, info, std::move(r_info)); - LOG(ERROR) << "info: " << to_string(info); promise.set_value(tonlib_api::make_object()); }); return td::Status::OK(); @@ -1042,7 +1041,6 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ return TonlibError::MessageTooLong(); } TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); - account_address.bounceable = false; TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto address = GenericAccount::get_address( 0 /*zerochain*/, TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); @@ -1116,7 +1114,6 @@ td::Status TonlibClient::do_request(const tonlib_api::wallet_sendGrams& request, TRY_RESULT_PREFIX(valid_until, td::narrow_cast_safe(request.valid_until_), TonlibError::InvalidField("valid_until", "overflow")); TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); - account_address.bounceable = false; TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto address = GenericAccount::get_address( 0 /*zerochain*/, Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); @@ -1168,7 +1165,6 @@ td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& reque return TonlibError::MessageTooLong(); } TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); - account_address.bounceable = false; auto message = TestGiver::make_a_gift_message(request.seqno_, request.amount_, request.message_, account_address); auto message_hash = message->get_hash().as_slice().str(); td::Promise> new_promise = @@ -1245,7 +1241,7 @@ class GenericSendGrams : public TonlibQueryActor { block::StdAddress source_address_; tonlib_api::object_ptr destination_state_; - bool is_destination_bounce_{false}; + bool is_destination_bounceable_{false}; void check(td::Status status) { if (status.is_error()) { @@ -1263,7 +1259,7 @@ class GenericSendGrams : public TonlibQueryActor { return TonlibError::EmptyField("destination"); } TRY_RESULT(destination_address, get_account_address(send_grams_.destination_->account_address_)); - is_destination_bounce_ = destination_address.bounceable; + is_destination_bounceable_ = destination_address.bounceable; if (!send_grams_.source_) { return TonlibError::EmptyField("destination"); @@ -1333,9 +1329,23 @@ class GenericSendGrams : public TonlibQueryActor { td::Status do_on_destination_state(td::Result> r_state) { TRY_RESULT(state, std::move(r_state)); destination_state_ = std::move(state); - if (destination_state_->get_id() == tonlib_api::generic_accountStateUninited::ID && is_destination_bounce_ && - !send_grams_.allow_send_to_uninited_) { - return TonlibError::DangerousTransaction("Transfer to uninited wallet"); + if (destination_state_->get_id() == tonlib_api::generic_accountStateUninited::ID && is_destination_bounceable_) { + //FIXME: after restoration of frozen accounts will be supported + if (!static_cast(*destination_state_) + .account_state_->frozen_hash_.empty()) { + return TonlibError::TransferToFrozen(); + //return TonlibError::DangerousTransaction("Transfer to frozen wallet"); + } + if (send_grams_.allow_send_to_uninited_) { + TRY_RESULT(destination_address, get_account_address(send_grams_.destination_->account_address_)); + destination_address.bounceable = false; + auto new_destination_address = destination_address.rserialize(true); + LOG(INFO) << "Change destination address from bounceable to non-bounceable " + << send_grams_.destination_->account_address_ << " -> " << new_destination_address; + send_grams_.destination_->account_address_ = std::move(new_destination_address); + } else { + return TonlibError::DangerousTransaction("Transfer to uninited wallet"); + } } return do_loop(); } diff --git a/tonlib/tonlib/TonlibError.h b/tonlib/tonlib/TonlibError.h index e0b4d0b..b521c13 100644 --- a/tonlib/tonlib/TonlibError.h +++ b/tonlib/tonlib/TonlibError.h @@ -128,6 +128,9 @@ struct TonlibError { static td::Status NotEnoughFunds() { return td::Status::Error(500, "NOT_ENOUGH_FUNDS"); } + static td::Status TransferToFrozen() { + return td::Status::Error(500, "TRANSFER_TO_FROZEN"); + } static td::Status LiteServer(td::int32 code, td::Slice message) { auto f = [&](td::Slice code_description) { return LiteServer(code, code_description, message); }; diff --git a/tonlib/tonlib/keys/DecryptedKey.cpp b/tonlib/tonlib/keys/DecryptedKey.cpp index 746ca18..931b9f0 100644 --- a/tonlib/tonlib/keys/DecryptedKey.cpp +++ b/tonlib/tonlib/keys/DecryptedKey.cpp @@ -35,36 +35,15 @@ DecryptedKey::DecryptedKey(RawDecryptedKey key) : DecryptedKey(std::move(key.mnemonic_words), td::Ed25519::PrivateKey(key.private_key.copy())) { } -td::SecureString DecryptedKey::change_local_password(td::Slice secret_str, td::Slice old_local_password, - td::Slice new_local_password) { - CHECK(secret_str.size() == 32); - td::SecureString old_local_password_hash(32); - sha256(old_local_password, old_local_password_hash.as_mutable_slice()); - td::SecureString new_local_password_hash(32); - sha256(new_local_password, new_local_password_hash.as_mutable_slice()); - - td::SecureString new_secret(32); - for (size_t i = 0; i < new_secret.size(); i++) { - new_secret.as_mutable_slice()[i] = - secret_str[i] ^ old_local_password_hash.as_slice()[i] ^ new_local_password_hash.as_slice()[i]; - } - return new_secret; -} - EncryptedKey DecryptedKey::encrypt(td::Slice local_password, td::Slice old_secret) const { - LOG(ERROR) << "encrypt"; td::SecureString secret(32); if (old_secret.size() == td::as_slice(secret).size()) { secret.as_mutable_slice().copy_from(old_secret); } else { td::Random::secure_bytes(secret.as_mutable_slice()); } - td::SecureString local_password_hash(32); - sha256(local_password, local_password_hash.as_mutable_slice()); td::SecureString decrypted_secret(32); - for (size_t i = 0; i < decrypted_secret.size(); i++) { - decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i]; - } + hmac_sha256(secret, local_password, decrypted_secret.as_mutable_slice()); td::SecureString encryption_secret(64); pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS, diff --git a/tonlib/tonlib/keys/DecryptedKey.h b/tonlib/tonlib/keys/DecryptedKey.h index 14086d0..bf53bc0 100644 --- a/tonlib/tonlib/keys/DecryptedKey.h +++ b/tonlib/tonlib/keys/DecryptedKey.h @@ -56,8 +56,6 @@ struct DecryptedKey { std::vector mnemonic_words; td::Ed25519::PrivateKey private_key; - static td::SecureString change_local_password(td::Slice secret, td::Slice old_local_password, - td::Slice new_local_password); EncryptedKey encrypt(td::Slice local_password, td::Slice secret = {}) const; }; diff --git a/tonlib/tonlib/keys/EncryptedKey.cpp b/tonlib/tonlib/keys/EncryptedKey.cpp index 1436779..65de8c8 100644 --- a/tonlib/tonlib/keys/EncryptedKey.cpp +++ b/tonlib/tonlib/keys/EncryptedKey.cpp @@ -24,15 +24,19 @@ #include "td/utils/crypto.h" namespace tonlib { -td::Result EncryptedKey::decrypt(td::Slice local_password, bool check_public_key) { +td::Result EncryptedKey::decrypt(td::Slice local_password, bool check_public_key, bool old) const { if (secret.size() != 32) { return td::Status::Error("Failed to decrypt key: invalid secret size"); } - td::SecureString local_password_hash(32); - sha256(local_password, local_password_hash.as_mutable_slice()); td::SecureString decrypted_secret(32); - for (size_t i = 0; i < 32; i++) { - decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i]; + if (old) { + td::SecureString local_password_hash(32); + sha256(local_password, local_password_hash.as_mutable_slice()); + for (size_t i = 0; i < 32; i++) { + decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i]; + } + } else { + hmac_sha256(secret, local_password, decrypted_secret.as_mutable_slice()); } td::SecureString encryption_secret(64); diff --git a/tonlib/tonlib/keys/EncryptedKey.h b/tonlib/tonlib/keys/EncryptedKey.h index 56aa661..6eb1627 100644 --- a/tonlib/tonlib/keys/EncryptedKey.h +++ b/tonlib/tonlib/keys/EncryptedKey.h @@ -32,7 +32,7 @@ struct EncryptedKey { td::Ed25519::PublicKey public_key; td::SecureString secret; - td::Result decrypt(td::Slice local_password, bool check_public_key = true); + td::Result decrypt(td::Slice local_password, bool check_public_key = true, bool old = false) const; }; } // namespace tonlib diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index a783d2a..8b3c94f 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -186,11 +186,21 @@ class TonlibCli : public td::actor::Actor { if (cmd.empty()) { return; } + auto to_bool = [](td::Slice word, bool def = false) { + if (word.empty()) { + return def; + } + if (word == "0" || word == "FALSE" || word == "false") { + return false; + } + return true; + }; if (cmd == "help") { td::TerminalIO::out() << "help - show this help\n"; td::TerminalIO::out() << "genkey - generate new secret key\n"; td::TerminalIO::out() << "keys - show all stored keys\n"; td::TerminalIO::out() << "unpackaddress
- validate and parse address\n"; + td::TerminalIO::out() << "setbounceble
[] - change bounceble flag in address\n"; td::TerminalIO::out() << "importkey - import key\n"; td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n"; td::TerminalIO::out() << "exportkey [] - export key\n"; @@ -214,6 +224,8 @@ class TonlibCli : public td::actor::Actor { try_stop(); } else if (cmd == "keys") { dump_keys(); + } else if (cmd == "deletekey") { + //delete_key(parser.read_word()); } else if (cmd == "deletekeys") { delete_all_keys(); } else if (cmd == "exportkey") { @@ -223,15 +235,6 @@ class TonlibCli : public td::actor::Actor { } else if (cmd == "setconfig") { auto config = parser.read_word(); auto name = parser.read_word(); - auto to_bool = [](td::Slice word) { - if (word.empty()) { - return false; - } - if (word == "0" || word == "FALSE" || word == "false") { - return false; - } - return true; - }; auto use_callback = parser.read_word(); auto force = parser.read_word(); set_config(config, name, to_bool(use_callback), to_bool(force)); @@ -251,6 +254,10 @@ class TonlibCli : public td::actor::Actor { get_hints(parser.read_word()); } else if (cmd == "unpackaddress") { unpack_address(parser.read_word()); + } else if (cmd == "setbounceable") { + auto addr = parser.read_word(); + auto bounceable = parser.read_word(); + set_bounceable(addr, to_bool(bounceable, true)); } } @@ -325,6 +332,26 @@ class TonlibCli : public td::actor::Actor { }); } + void set_bounceable(td::Slice addr, bool bounceable) { + send_query(tonlib_api::make_object(addr.str()), + [addr = addr.str(), bounceable, this](auto r_parsed_addr) mutable { + if (r_parsed_addr.is_error()) { + LOG(ERROR) << "Failed to parse address: " << r_parsed_addr.error(); + return; + } + auto parsed_addr = r_parsed_addr.move_as_ok(); + parsed_addr->bounceable_ = bounceable; + this->send_query(tonlib_api::make_object(std::move(parsed_addr)), + [](auto r_addr) mutable { + if (r_addr.is_error()) { + LOG(ERROR) << "Failed to pack address"; + return; + } + td::TerminalIO::out() << r_addr.ok()->account_address_ << "\n"; + }); + }); + } + void generate_key(td::SecureString entropy = {}) { if (entropy.size() < 20) { td::TerminalIO::out() << "Enter some entropy"; @@ -527,6 +554,25 @@ class TonlibCli : public td::actor::Actor { return std::move(res); } + void delete_key(td::Slice key) { + auto r_key_i = to_key_i(key); + if (r_key_i.is_error()) { + td::TerminalIO::out() << "Unknown key id: [" << key << "]\n"; + return; + } + using tonlib_api::make_object; + auto key_i = r_key_i.move_as_ok(); + send_query(make_object( + make_object(keys_[key_i].public_key, keys_[key_i].secret.copy())), + + [key = key.str()](auto r_res) { + if (r_res.is_error()) { + td::TerminalIO::out() << "Can't delete key id: [" << key << "] " << r_res.error() << "\n"; + return; + } + td::TerminalIO::out() << "Ok\n"; + }); + } void export_key(td::Slice key) { if (key.empty()) { dump_keys(); @@ -754,6 +800,11 @@ class TonlibCli : public td::actor::Actor { } void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message, bool allow_send_to_uninited) { + auto r_sz = td::to_integer_safe(message); + auto msg = message.str(); + if (r_sz.is_ok()) { + msg = std::string(r_sz.ok(), 'Z'); + } using tonlib_api::make_object; auto key = !from.secret.empty() ? make_object( @@ -761,7 +812,7 @@ class TonlibCli : public td::actor::Actor { : nullptr; send_query( make_object(std::move(key), std::move(from.address), std::move(to.address), - grams, 30, allow_send_to_uninited, message.str()), + grams, 60, allow_send_to_uninited, std::move(msg)), [this](auto r_res) { if (r_res.is_error()) { td::TerminalIO::out() << "Can't transfer: " << r_res.error() << "\n"; @@ -881,6 +932,10 @@ int main(int argc, char* argv[]) { options.config = std::move(data); return td::Status::OK(); }); + p.add_option('N', "config-name", "set lite server config name", [&](td::Slice arg) { + options.name = arg.str(); + return td::Status::OK(); + }); p.add_option('n', "use-callbacks-for-network", "do not use this", [&]() { options.use_callbacks_for_network = true; return td::Status::OK(); diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 16bc873..269b13e 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -3099,7 +3099,8 @@ bool Collator::create_mc_state_extra() { CHECK(cb.store_long_bool(0x17, 8) && cb.append_cellslice_bool(block_create_stats_->get_root())); auto cs = vm::load_cell_slice_ref(cb.finalize()); state_extra.r1.block_create_stats = cs; - if (verify >= 1) { + if (verify >= 2) { + LOG(INFO) << "verifying new BlockCreateStats"; if (!block::gen::t_BlockCreateStats.validate_csr(cs)) { cs->print_rec(std::cerr); block::gen::t_BlockCreateStats.print(std::cerr, *cs); @@ -3154,10 +3155,12 @@ bool Collator::update_block_creator_count(td::ConstBitPtr key, unsigned shard_in int Collator::creator_count_outdated(td::ConstBitPtr key, vm::CellSlice& cs) { block::DiscountedCounter mc_cnt, shard_cnt; if (!(block::fetch_CreatorStats(cs, mc_cnt, shard_cnt) && cs.empty_ext())) { - return fatal_error("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state"); + fatal_error("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state"); + return -1; } if (!(mc_cnt.increase_by(0, now_) && shard_cnt.increase_by(0, now_))) { - return fatal_error("cannot amortize counters in CreatorStats for "s + key.to_hex(256)); + fatal_error("cannot amortize counters in CreatorStats for "s + key.to_hex(256)); + return -1; } if (!(mc_cnt.cnt65536 | shard_cnt.cnt65536)) { LOG(DEBUG) << "removing stale CreatorStats for " << key.to_hex(256); @@ -3178,17 +3181,42 @@ bool Collator::update_block_creator_stats() { return fatal_error("cannot update CreatorStats for "s + p.first.to_hex()); } } - if (!created_by_.is_zero() && !update_block_creator_count(created_by_.as_bits256().bits(), 0, 1)) { + auto has_creator = !created_by_.is_zero(); + if (has_creator && !update_block_creator_count(created_by_.as_bits256().bits(), 0, 1)) { return fatal_error("cannot update CreatorStats for "s + created_by_.as_bits256().to_hex()); } - if (!update_block_creator_count(td::Bits256::zero().bits(), block_create_total_, !created_by_.is_zero())) { + if ((has_creator || block_create_total_) && + !update_block_creator_count(td::Bits256::zero().bits(), block_create_total_, has_creator)) { return fatal_error("cannot update CreatorStats with zero index (representing the sum of other CreatorStats)"); } + // -> DEBUG + LOG(INFO) << "scanning for outdated CreatorStats entries"; + /* int cnt = block_create_stats_->filter([this](vm::CellSlice& cs, td::ConstBitPtr key, int key_len) { CHECK(key_len == 256); return creator_count_outdated(key, cs); }); - LOG(DEBUG) << "removed " << cnt << " stale CreatorStats entries"; + */ + // alternative version with partial scan + td::Bits256 key; + prng::rand_gen().rand_bytes(key.data(), 32); + int scanned, cnt = 0; + for (scanned = 0; scanned < 100; scanned++) { + auto cs = block_create_stats_->lookup_nearest_key(key.bits(), 256, true); + if (cs.is_null()) { + break; + } + auto res = creator_count_outdated(key.bits(), cs.write()); + if (!res) { + LOG(DEBUG) << "prunning CreatorStats for " << key.to_hex(); + block_create_stats_->lookup_delete(key); + ++cnt; + } else if (res < 0) { + return fatal_error("error scanning stale CreatorStats entries"); + } + } + // -> DEBUG + LOG(INFO) << "removed " << cnt << " stale CreatorStats entries out of " << scanned << " scanned"; return cnt >= 0; } diff --git a/validator/impl/liteserver.cpp b/validator/impl/liteserver.cpp index 2cf588b..23831af 100644 --- a/validator/impl/liteserver.cpp +++ b/validator/impl/liteserver.cpp @@ -192,7 +192,7 @@ void LiteQuery::perform_getMasterchainInfo(int mode) { } td::actor::send_closure_later( manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, - [Self = actor_id(this), mode](td::Result, BlockIdExt>> res) { + [ Self = actor_id(this), mode ](td::Result, BlockIdExt>> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -230,7 +230,7 @@ void LiteQuery::perform_getBlock(BlockIdExt blkid) { return; } td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -256,7 +256,7 @@ void LiteQuery::perform_getBlockHeader(BlockIdExt blkid, int mode) { return; } td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid, - [Self = actor_id(this), blkid, mode](td::Result> res) { + [ Self = actor_id(this), blkid, mode ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -371,7 +371,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) { } if (blkid.id.seqno) { td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -381,7 +381,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) { }); } else { td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid, - [Self = actor_id(this), blkid](td::Result res) { + [ Self = actor_id(this), blkid ](td::Result res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -440,7 +440,7 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_block_data_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : ")); @@ -466,7 +466,7 @@ bool LiteQuery::request_mc_proof(BlockIdExt blkid, int mode) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_block_proof_from_db_short, blkid, - [Self = actor_id(this), blkid, mode](td::Result> res) { + [ Self = actor_id(this), blkid, mode ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : ")); @@ -488,7 +488,7 @@ bool LiteQuery::request_mc_block_state(BlockIdExt blkid) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_shard_state_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : ")); @@ -519,7 +519,7 @@ bool LiteQuery::request_block_state(BlockIdExt blkid) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_shard_state_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : ")); @@ -541,7 +541,7 @@ bool LiteQuery::request_block_data(BlockIdExt blkid) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_block_data_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : ")); @@ -563,7 +563,7 @@ bool LiteQuery::request_proof_link(BlockIdExt blkid) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid, - [Self = actor_id(this), blkid](td::Result> res) { + [ Self = actor_id(this), blkid ](td::Result> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : ")); @@ -588,7 +588,7 @@ bool LiteQuery::request_zero_state(BlockIdExt blkid) { ++pending_; td::actor::send_closure_later( manager_, &ValidatorManager::get_zero_state, blkid, - [Self = actor_id(this), blkid](td::Result res) { + [ Self = actor_id(this), blkid ](td::Result res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : ")); @@ -632,7 +632,7 @@ void LiteQuery::perform_getAccountState(BlockIdExt blkid, WorkchainId workchain, LOG(INFO) << "sending a get_top_masterchain_state_block query to manager"; td::actor::send_closure_later( manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, - [Self = actor_id(this)](td::Result, BlockIdExt>> res) -> void { + [Self = actor_id(this)](td::Result, BlockIdExt>> res)->void { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -1067,7 +1067,7 @@ void LiteQuery::continue_getTransactions(unsigned remaining, bool exact) { << " " << trans_lt_; td::actor::send_closure_later( manager_, &ValidatorManager::get_block_by_lt_from_db, ton::extract_addr_prefix(acc_workchain_, acc_addr_), - trans_lt_, [Self = actor_id(this), remaining, manager = manager_](td::Result res) { + trans_lt_, [ Self = actor_id(this), remaining, manager = manager_ ](td::Result res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{}); } else { @@ -1141,7 +1141,7 @@ void LiteQuery::perform_getShardInfo(BlockIdExt blkid, ShardIdFull shard, bool e void LiteQuery::perform_getConfigParams(BlockIdExt blkid, int mode, std::vector param_list) { LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", ) liteserver query"; - set_continuation([this, mode, param_list = std::move(param_list)]() mutable { + set_continuation([ this, mode, param_list = std::move(param_list) ]() mutable { continue_getConfigParams(mode, std::move(param_list)); }); request_mc_block_data_state(blkid); @@ -1294,7 +1294,7 @@ void LiteQuery::perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, Uni LOG(INFO) << "performing a lookupBlock(" << blkid.to_str() << ", " << mode << ", " << lt << ", " << utime << ") query"; auto P = td::PromiseCreator::lambda( - [Self = actor_id(this), manager = manager_, mode = (mode >> 4)](td::Result res) { + [ Self = actor_id(this), manager = manager_, mode = (mode >> 4) ](td::Result res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { @@ -1446,58 +1446,83 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, return; } if (mode & 1) { - base_blk_id_ = (from.seqno() > to.seqno()) ? from : to; - td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, base_blk_id_, - [Self = actor_id(this), from, to, mode](td::Result> res) { - if (res.is_error()) { - td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); - } else { - td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to, - mode, Ref(res.move_as_ok())); - } - }); + if (mode & 0x1000) { + BlockIdExt bblk = (from.seqno() > to.seqno()) ? from : to; + td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, bblk, + [ Self = actor_id(this), from, to, bblk, mode ](td::Result> res) { + if (res.is_error()) { + td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); + } else { + td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, + to, mode, bblk, + Ref(res.move_as_ok())); + } + }); + } else { + td::actor::send_closure_later( + manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, + [ Self = actor_id(this), from, to, mode ](td::Result, BlockIdExt>> res) { + if (res.is_error()) { + td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); + } else { + auto pair = res.move_as_ok(); + td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to, mode, pair.second, + Ref(std::move(pair.first))); + } + }); + } } else if (mode & 2) { td::actor::send_closure_later( manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, - [Self = actor_id(this), from, mode](td::Result, BlockIdExt>> res) { + [ Self = actor_id(this), from, mode ](td::Result, BlockIdExt>> res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { auto pair = res.move_as_ok(); td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, pair.second, mode, - Ref(std::move(pair.first))); + pair.second, Ref(std::move(pair.first))); } }); } else { td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_shard_client_state, false, - [Self = actor_id(this), from, mode](td::Result res) { + [ Self = actor_id(this), from, mode ](td::Result res) { if (res.is_error()) { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); } else { td::actor::send_closure_later(Self, &LiteQuery::perform_getBlockProof, from, - res.move_as_ok(), mode | 1); + res.move_as_ok(), mode | 0x1001); } }); } } -void LiteQuery::continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, +void LiteQuery::continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, BlockIdExt baseblk, Ref state) { + base_blk_id_ = baseblk; + if (!base_blk_id_.is_masterchain_ext()) { + fatal_error("reference masterchain block "s + base_blk_id_.to_str() + " for constructing a proof chain is invalid"); + return; + } if (!(mode & 1)) { - base_blk_id_ = to; if (!to.is_masterchain_ext()) { fatal_error("last masterchain block id "s + to.to_str() + " is invalid"); return; } - if (from.seqno() > to.seqno()) { - fatal_error("client knows block "s + from.to_str() + " newer than the latest masterchain block " + to.to_str()); - return; - } } if (state.is_null()) { fatal_error("obtained no valid masterchain state for block "s + base_blk_id_.to_str()); return; } + if (from.seqno() > base_blk_id_.seqno()) { + fatal_error("client knows block "s + from.to_str() + " newer than the reference masterchain block " + + base_blk_id_.to_str()); + return; + } + if (to.seqno() > base_blk_id_.seqno()) { + fatal_error("client knows block "s + to.to_str() + " newer than the reference masterchain block " + + base_blk_id_.to_str()); + return; + } mc_state0_ = Ref(state); if (base_blk_id_ != state->get_block_id()) { fatal_error("the state for "s + base_blk_id_.to_str() + " is in fact a state for different block " + @@ -1507,13 +1532,13 @@ void LiteQuery::continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, LOG(INFO) << "continuing getBlockProof(" << mode << ", " << from.to_str() << ", " << to.to_str() << ") query with a state for " << base_blk_id_.to_str(); if (!state->check_old_mc_block_id(from)) { - fatal_error("source masterchain block "s + from.to_str() + " is unknown from the perspective of newer block " + - base_blk_id_.to_str()); + fatal_error("proof source masterchain block "s + from.to_str() + + " is unknown from the perspective of reference block " + base_blk_id_.to_str()); return; } if (!state->check_old_mc_block_id(to)) { - fatal_error("destination masterchain block "s + to.to_str() + " is unknown from the perspective of newer block " + - base_blk_id_.to_str()); + fatal_error("proof destination masterchain block "s + to.to_str() + + " is unknown from the perspective of reference block " + base_blk_id_.to_str()); return; } chain_ = std::make_unique(from, to, mode); diff --git a/validator/impl/liteserver.hpp b/validator/impl/liteserver.hpp index 580e086..9118ec0 100644 --- a/validator/impl/liteserver.hpp +++ b/validator/impl/liteserver.hpp @@ -111,9 +111,10 @@ class LiteQuery : public td::actor::Actor { void perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, UnixTime utime); void perform_listBlockTransactions(BlockIdExt blkid, int mode, int count, Bits256 account, LogicalTime lt); void finish_listBlockTransactions(int mode, int count); - void perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode); - void continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, Ref state); - bool construct_proof_chain(ton::BlockIdExt id); + void perform_getBlockProof(BlockIdExt from, BlockIdExt to, int mode); + void continue_getBlockProof(BlockIdExt from, BlockIdExt to, int mode, BlockIdExt baseblk, + Ref state); + bool construct_proof_chain(BlockIdExt id); bool construct_proof_link_forward(ton::BlockIdExt cur, ton::BlockIdExt next); bool construct_proof_link_forward_cont(ton::BlockIdExt cur, ton::BlockIdExt next); bool construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt next); diff --git a/validator/manager.cpp b/validator/manager.cpp index 3046736..376b367 100644 --- a/validator/manager.cpp +++ b/validator/manager.cpp @@ -1880,10 +1880,12 @@ void ValidatorManagerImpl::update_shard_client_block_handle(BlockHandle handle, void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) { if (min_confirmed_masterchain_seqno_ < seqno) { min_confirmed_masterchain_seqno_ = seqno; + } else { + return; } while (shard_client_waiters_.size() > 0) { auto it = shard_client_waiters_.begin(); - if (it->first > seqno) { + if (it->first > min_confirmed_masterchain_seqno_) { break; } for (auto &y : it->second.waiting_) {