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

update tonlib

tonlib: update
collator: increased collation speed for masterchain
fift: bugfixes
This commit is contained in:
ton 2019-10-04 16:08:02 +04:00
parent 7ea00ebfcf
commit dd745485e2
27 changed files with 313 additions and 172 deletions

View File

@ -897,7 +897,7 @@ static int process_workchain_shard_hashes(Ref<vm::Cell>& branch, ton::ShardIdFul
int f = (int)cs.fetch_ulong(1); int f = (int)cs.fetch_ulong(1);
if (f == 1) { if (f == 1) {
if ((shard.shard & 1) || cs.size_ext() != 0x20000) { if ((shard.shard & 1) || cs.size_ext() != 0x20000) {
return false; return -1;
} }
auto left = cs.prefetch_ref(0), right = cs.prefetch_ref(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); int r = process_workchain_shard_hashes(left, ton::shard_child(shard, true), func);

View File

@ -1922,7 +1922,7 @@ bool AnyIntView<Tr>::export_bits_any(unsigned char* buff, int offs, unsigned bit
if (--ptr > buff) { if (--ptr > buff) {
*ptr = (unsigned char)(v & 0xff); *ptr = (unsigned char)(v & 0xff);
} else { } else {
int mask = (-0x100 >> offs) & 0xff; int mask = (0xff00 >> offs) & 0xff;
if (((unsigned char)v ^ s) & mask) { if (((unsigned char)v ^ s) & mask) {
return false; return false;
} }
@ -1943,7 +1943,7 @@ bool AnyIntView<Tr>::export_bits_any(unsigned char* buff, int offs, unsigned bit
if (--ptr > buff) { if (--ptr > buff) {
*ptr = (unsigned char)(v & 0xff); *ptr = (unsigned char)(v & 0xff);
} else { } else {
int mask = (-0x100 >> offs) & 0xff; int mask = (0xff00 >> offs) & 0xff;
if (((unsigned char)v ^ s) & mask) { if (((unsigned char)v ^ s) & mask) {
return false; return false;
} }
@ -1961,7 +1961,7 @@ bool AnyIntView<Tr>::export_bits_any(unsigned char* buff, int offs, unsigned bit
*ptr = (unsigned char)(v & 0xff); *ptr = (unsigned char)(v & 0xff);
v >>= 8; v >>= 8;
} }
int mask = (-0x100 >> offs) & 0xff; int mask = (0xff00 >> offs) & 0xff;
if (((unsigned char)v ^ s) & mask) { if (((unsigned char)v ^ s) & mask) {
return false; return false;
} }

View File

@ -132,9 +132,7 @@ int main(int argc, char* const argv[]) {
if (!no_env) { if (!no_env) {
const char* path = std::getenv("FIFTPATH"); 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; std::string current_dir;
auto r_current_dir = td::realpath("."); auto r_current_dir = td::realpath(".");

View File

@ -138,7 +138,7 @@ bool Op::set_var_info_except(const VarDescrList& new_var_info, const std::vector
} }
VarDescrList tmp_info{new_var_info}; VarDescrList tmp_info{new_var_info};
tmp_info -= var_list; 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_idx_t>& var_list) { bool Op::set_var_info_except(VarDescrList&& new_var_info, const std::vector<var_idx_t>& var_list) {

View File

@ -31,8 +31,9 @@ serialized_boc#b5ee9c72 has_idx:(## 1) has_crc32c:(## 1)
absent:(##(size * 8)) { roots + absent <= cells } absent:(##(size * 8)) { roots + absent <= cells }
tot_cells_size:(##(off_bytes * 8)) tot_cells_size:(##(off_bytes * 8))
root_list:(roots * ##(size * 8)) root_list:(roots * ##(size * 8))
index:(cells * ##(off_bytes * 8)) index:has_idx?(cells * ##(off_bytes * 8))
cell_data:(tot_cells_size * [ uint8 ]) cell_data:(tot_cells_size * [ uint8 ])
crc32c:has_crc32c?uint32
= BagOfCells; = BagOfCells;
compiled_smart_contract compiled_smart_contract

View File

@ -75,7 +75,7 @@ td::Result<int> CellSerializationInfo::get_bits(td::Slice cell) const {
if (data_with_bits) { if (data_with_bits) {
DCHECK(data_len != 0); DCHECK(data_len != 0);
int last = cell[data_offset + data_len - 1]; int last = cell[data_offset + data_len - 1];
if (!last || last == 0x80) { if (!(last & 0x7f)) {
return td::Status::Error("overlong encoding"); return td::Status::Error("overlong encoding");
} }
return td::narrow_cast<int>((data_len - 1) * 8 + 7 - td::count_trailing_zeroes_non_zero32(last)); return td::narrow_cast<int>((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; r_size = o_size = 0;
return 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; r_size = rs;
o_size = os; o_size = os;
return data_bytes_adj; return data_bytes_adj;

View File

@ -527,9 +527,6 @@ int CellBuilder::serialize(unsigned char* buff, int buff_size) const {
CellBuilder* CellBuilder::make_copy() const { CellBuilder* CellBuilder::make_copy() const {
CellBuilder* c = new CellBuilder(); CellBuilder* c = new CellBuilder();
if (!c) {
throw CellWriteError();
}
c->bits = bits; c->bits = bits;
std::memcpy(c->data, data, (bits + 7) >> 3); std::memcpy(c->data, data, (bits + 7) >> 3);
c->refs_cnt = refs_cnt; c->refs_cnt = refs_cnt;

View File

@ -2000,36 +2000,46 @@ In addition to the values listed in~\ptref{sp:boc.ser.class}, fixed by the choic
\end{itemize} \end{itemize}
\nxsubpoint\label{sp:boc.ser.sch}\emb{TL-B scheme for serializing bags of cells} \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} \begin{verbatim}
serialized_boc_tiny cells:uint8 roots:uint8 absent:uint8 serialized_boc#b5ee9c72 has_idx:(## 1) has_crc32c:(## 1)
tot_cells_size:(## 32) cell_data:(tot_cells_size * [ uint8 ]) has_cache_bits:(## 1) flags:(## 2) { flags = 0 }
= BagOfCells; size:(## 3) { size <= 4 }
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 }
off_bytes:(## 8) { off_bytes <= 8 } off_bytes:(## 8) { off_bytes <= 8 }
cells:(##(size * 8)) cells:(##(size * 8))
roots:(##(size * 8)) roots:(##(size * 8)) { roots >= 1 }
absent:(##(size * 8)) { roots + absent <= cells } absent:(##(size * 8)) { roots + absent <= cells }
tot_cells_size:(##(off_bytes * 8)) 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 ]) cell_data:(tot_cells_size * [ uint8 ])
crc32c:has_crc32c?uint32
= BagOfCells; = BagOfCells;
\end{verbatim} \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} \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: 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:

View File

@ -38,7 +38,7 @@ unpackedAccountAddress workchain_id:int32 bounceable:Bool testnet:Bool addr:byte
internal.transactionId lt:int64 hash:bytes = internal.TransactionId; internal.transactionId lt:int64 hash:bytes = internal.TransactionId;
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; 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.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.message> = raw.Transaction; 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.message> = raw.Transaction;
raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions; raw.transactions transactions:vector<raw.transaction> 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; 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.initialAccountStateRaw initital_account_state:raw.initialAccountState = generic.InitialAccountState;
//generic.initialAccountStateTestWallet initital_account_state:testWallet.initialAccountState = generic.InitialAccountState; //generic.initialAccountStateTestWallet initital_account_state:testWallet.initialAccountState = generic.InitialAccountState;

Binary file not shown.

View File

@ -434,9 +434,10 @@ TEST(Tonlib, KeysApi) {
using tonlib_api::make_object; using tonlib_api::make_object;
Client client; Client client;
td::mkdir("testdir").ignore();
// init // init
sync_send(client, make_object<tonlib_api::init>( sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(
make_object<tonlib_api::options>(nullptr, make_object<tonlib_api::keyStoreTypeDirectory>(".")))) nullptr, make_object<tonlib_api::keyStoreTypeDirectory>("testdir"))))
.ensure(); .ensure();
auto local_password = td::SecureString("local password"); auto local_password = td::SecureString("local password");
auto mnemonic_password = td::SecureString("mnemonic password"); auto mnemonic_password = td::SecureString("mnemonic password");

View File

@ -61,15 +61,14 @@ class ExtClient {
auto raw_query = ton::serialize_tl_object(&query, true); auto raw_query = ton::serialize_tl_object(&query, true);
td::uint32 tag = td::Random::fast_uint32(); td::uint32 tag = td::Random::fast_uint32();
VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query); VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query);
td::BufferSlice liteserver_query =
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
if (seq_no >= 0) { if (seq_no >= 0) {
auto wait = ton::lite_api::liteServer_waitMasterchainSeqno(seq_no, 5000); auto wait = ton::lite_api::liteServer_waitMasterchainSeqno(seq_no, 5000);
VLOG(lite_server) << " with prefix " << to_string(wait); VLOG(lite_server) << " with prefix " << to_string(wait);
auto prefix = ton::serialize_tl_object(&wait, true); 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<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
send_raw_query( send_raw_query(
std::move(liteserver_query), [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 {

View File

@ -69,7 +69,7 @@ td::Result<DecryptedKey> KeyStorage::export_decrypted_key(InputKey input_key) {
if (r_encrypted_data.is_error()) { if (r_encrypted_data.is_error()) {
r_encrypted_data = kv_->get(to_file_name_old(input_key.key)); r_encrypted_data = kv_->get(to_file_name_old(input_key.key));
if (r_encrypted_data.is_ok()) { 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); << to_file_name(input_key.key);
TRY_STATUS_PREFIX(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok()), TonlibError::Internal()); 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(); kv_->erase(to_file_name_old(input_key.key)).ignore();
@ -78,6 +78,21 @@ td::Result<DecryptedKey> KeyStorage::export_decrypted_key(InputKey input_key) {
TRY_RESULT_PREFIX(encrypted_data, std::move(r_encrypted_data), TonlibError::KeyUnknown()); 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)), EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)),
std::move(input_key.key.secret)}; 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)), TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(std::move(input_key.local_password)),
TonlibError::KeyDecrypt()); TonlibError::KeyDecrypt());
return std::move(decrypted_key); return std::move(decrypted_key);
@ -139,14 +154,9 @@ td::Result<KeyStorage::ExportedPemKey> KeyStorage::export_pem_key(InputKey input
} }
td::Result<KeyStorage::Key> KeyStorage::change_local_password(InputKey input_key, td::Slice new_local_password) { td::Result<KeyStorage::Key> KeyStorage::change_local_password(InputKey input_key, td::Slice new_local_password) {
auto new_secret = auto old_name = to_file_name(input_key.key);
DecryptedKey::change_local_password(input_key.key.secret, input_key.local_password, new_local_password); TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
Key res; return save_key(std::move(decrypted_key), new_local_password);
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);
} }
td::Result<KeyStorage::Key> KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password, td::Result<KeyStorage::Key> KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password,

View File

@ -39,7 +39,7 @@ class KeyValueDir : public KeyValue {
} }
td::Status erase(td::Slice key) override { 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<void(td::Slice)> f) override { void foreach_key(std::function<void(td::Slice)> f) override {

View File

@ -32,7 +32,8 @@ namespace tonlib {
// //
td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) { td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) {
return sb << td::tag("last_block", state.last_block_id.to_str()) 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> callback) LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr<Callback> callback)
@ -40,8 +41,7 @@ LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, t
client_.set_client(client); client_.set_client(client);
state_.last_block_id = state_.last_key_block_id; state_.last_block_id = state_.last_key_block_id;
VLOG(last_block) << "check_init_block: skip - FIXME before release"; VLOG(last_block) << "State: " << state_;
check_init_block_state_ = QueryState::Done;
} }
void LastBlock::get_last_block(td::Promise<LastBlockState> promise) { void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
@ -87,7 +87,7 @@ void LastBlock::sync_loop() {
} else { } else {
check_init_block_state_ = QueryState::Active; check_init_block_state_ = QueryState::Active;
check_init_block_stats_.start(); 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"; VLOG(last_block) << "check_init_block: start - init_block -> last_block";
do_check_init_block(config_.init_block_id, state_.last_key_block_id); do_check_init_block(config_.init_block_id, state_.last_key_block_id);
} else { } else {
@ -162,10 +162,18 @@ void LastBlock::update_state(block::BlockProofChain& chain) {
update_utime(chain.last_utime); update_utime(chain.last_utime);
} }
if (is_changed) { 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( void LastBlock::on_block_proof(
ton::BlockIdExt from, ton::BlockIdExt from,
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) { td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
@ -209,6 +217,9 @@ void LastBlock::on_init_block_proof(
if (chain->complete) { if (chain->complete) {
VLOG(last_block) << "check_init_block: done\n" << check_init_block_stats_; VLOG(last_block) << "check_init_block: done\n" << check_init_block_stats_;
check_init_block_state_ = QueryState::Done; check_init_block_state_ = QueryState::Done;
if (update_init_block(config_.init_block_id)) {
save_state();
}
sync_loop(); sync_loop();
} else { } else {
do_check_init_block(chain->to, to); 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; 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) { void LastBlock::update_utime(td::int64 utime) {
if (state_.utime < utime) { if (state_.utime < utime) {
state_.utime = utime; state_.utime = utime;

View File

@ -201,7 +201,9 @@ class LastBlock : public td::actor::Actor {
bool update_mc_last_block(ton::BlockIdExt mc_block_id); bool update_mc_last_block(ton::BlockIdExt mc_block_id);
bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
void update_utime(td::int64 utime); 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_ok();
void on_sync_error(td::Status status); void on_sync_error(td::Status status);
void on_fatal_error(td::Status status); void on_fatal_error(td::Status status);

View File

@ -108,7 +108,6 @@ class GetTransactionHistory : public td::actor::Actor {
void check(td::Status status) { void check(td::Status status) {
if (status.is_error()) { if (status.is_error()) {
LOG(ERROR) << status;
promise_.set_error(std::move(status)); promise_.set_error(std::move(status));
stop(); stop();
} }
@ -208,7 +207,7 @@ class GetRawAccountState : public td::actor::Actor {
auto cell = res.info.root; auto cell = res.info.root;
std::ostringstream outp; std::ostringstream outp;
block::gen::t_Account.print_ref(outp, cell); block::gen::t_Account.print_ref(outp, cell);
LOG(ERROR) << outp.str(); LOG(INFO) << outp.str();
if (cell.is_null()) { if (cell.is_null()) {
return res; return res;
} }
@ -682,8 +681,9 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_accountState>> to_raw_accountS
.as_slice() .as_slice()
.str(); .str();
} }
return tonlib_api::make_object<tonlib_api::raw_accountState>( return tonlib_api::make_object<tonlib_api::raw_accountState>(raw_state.balance, std::move(code), std::move(data),
raw_state.balance, std::move(code), std::move(data), to_transaction_id(raw_state.info), raw_state.info.gen_utime); to_transaction_id(raw_state.info), raw_state.frozen_hash,
raw_state.info.gen_utime);
} }
td::Result<std::string> to_std_address_or_throw(td::Ref<vm::CellSlice> cs) { td::Result<std::string> to_std_address_or_throw(td::Ref<vm::CellSlice> cs) {
@ -803,7 +803,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transaction>> to_raw_transacti
std::ostringstream outp; std::ostringstream outp;
block::gen::t_Transaction.print_ref(outp, info.transaction); 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); auto is_just = trans.r1.in_msg->prefetch_long(1);
if (is_just == trans.r1.in_msg->fetch_long_eof) { if (is_just == trans.r1.in_msg->fetch_long_eof) {
@ -917,7 +917,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> to_generic_
if (raw_state.code.is_null()) { if (raw_state.code.is_null()) {
return tonlib_api::make_object<tonlib_api::generic_accountStateUninited>( return tonlib_api::make_object<tonlib_api::generic_accountStateUninited>(
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance, to_transaction_id(raw_state.info), tonlib_api::make_object<tonlib_api::uninited_accountState>(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(); 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()), client_.send_query(ton::lite_api::liteServer_sendMessage(vm::std_boc_serialize(message).move_as_ok()),
[promise = std::move(promise)](auto r_info) mutable { [promise = std::move(promise)](auto r_info) mutable {
TRY_RESULT_PROMISE(promise, info, std::move(r_info)); TRY_RESULT_PROMISE(promise, info, std::move(r_info));
LOG(ERROR) << "info: " << to_string(info);
promise.set_value(tonlib_api::make_object<tonlib_api::ok>()); promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
}); });
return td::Status::OK(); return td::Status::OK();
@ -1042,7 +1041,6 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ
return TonlibError::MessageTooLong(); return TonlibError::MessageTooLong();
} }
TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); TRY_RESULT(account_address, get_account_address(request.destination_->account_address_));
account_address.bounceable = false;
TRY_RESULT(input_key, from_tonlib(*request.private_key_)); TRY_RESULT(input_key, from_tonlib(*request.private_key_));
auto address = GenericAccount::get_address( auto address = GenericAccount::get_address(
0 /*zerochain*/, TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); 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<td::uint32>(request.valid_until_), TRY_RESULT_PREFIX(valid_until, td::narrow_cast_safe<td::uint32>(request.valid_until_),
TonlibError::InvalidField("valid_until", "overflow")); TonlibError::InvalidField("valid_until", "overflow"));
TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); TRY_RESULT(account_address, get_account_address(request.destination_->account_address_));
account_address.bounceable = false;
TRY_RESULT(input_key, from_tonlib(*request.private_key_)); TRY_RESULT(input_key, from_tonlib(*request.private_key_));
auto address = GenericAccount::get_address( auto address = GenericAccount::get_address(
0 /*zerochain*/, Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); 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(); return TonlibError::MessageTooLong();
} }
TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); 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 = TestGiver::make_a_gift_message(request.seqno_, request.amount_, request.message_, account_address);
auto message_hash = message->get_hash().as_slice().str(); auto message_hash = message->get_hash().as_slice().str();
td::Promise<object_ptr<tonlib_api::ok>> new_promise = td::Promise<object_ptr<tonlib_api::ok>> new_promise =
@ -1245,7 +1241,7 @@ class GenericSendGrams : public TonlibQueryActor {
block::StdAddress source_address_; block::StdAddress source_address_;
tonlib_api::object_ptr<tonlib_api::generic_AccountState> destination_state_; tonlib_api::object_ptr<tonlib_api::generic_AccountState> destination_state_;
bool is_destination_bounce_{false}; bool is_destination_bounceable_{false};
void check(td::Status status) { void check(td::Status status) {
if (status.is_error()) { if (status.is_error()) {
@ -1263,7 +1259,7 @@ class GenericSendGrams : public TonlibQueryActor {
return TonlibError::EmptyField("destination"); return TonlibError::EmptyField("destination");
} }
TRY_RESULT(destination_address, get_account_address(send_grams_.destination_->account_address_)); 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_) { if (!send_grams_.source_) {
return TonlibError::EmptyField("destination"); return TonlibError::EmptyField("destination");
@ -1333,9 +1329,23 @@ class GenericSendGrams : public TonlibQueryActor {
td::Status do_on_destination_state(td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> r_state) { td::Status do_on_destination_state(td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> r_state) {
TRY_RESULT(state, std::move(r_state)); TRY_RESULT(state, std::move(r_state));
destination_state_ = std::move(state); destination_state_ = std::move(state);
if (destination_state_->get_id() == tonlib_api::generic_accountStateUninited::ID && is_destination_bounce_ && if (destination_state_->get_id() == tonlib_api::generic_accountStateUninited::ID && is_destination_bounceable_) {
!send_grams_.allow_send_to_uninited_) { //FIXME: after restoration of frozen accounts will be supported
return TonlibError::DangerousTransaction("Transfer to uninited wallet"); if (!static_cast<tonlib_api::generic_accountStateUninited&>(*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(); return do_loop();
} }

View File

@ -128,6 +128,9 @@ struct TonlibError {
static td::Status NotEnoughFunds() { static td::Status NotEnoughFunds() {
return td::Status::Error(500, "NOT_ENOUGH_FUNDS"); 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) { static td::Status LiteServer(td::int32 code, td::Slice message) {
auto f = [&](td::Slice code_description) { return LiteServer(code, code_description, message); }; auto f = [&](td::Slice code_description) { return LiteServer(code, code_description, message); };

View File

@ -35,36 +35,15 @@ DecryptedKey::DecryptedKey(RawDecryptedKey key)
: DecryptedKey(std::move(key.mnemonic_words), td::Ed25519::PrivateKey(key.private_key.copy())) { : 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 { EncryptedKey DecryptedKey::encrypt(td::Slice local_password, td::Slice old_secret) const {
LOG(ERROR) << "encrypt";
td::SecureString secret(32); td::SecureString secret(32);
if (old_secret.size() == td::as_slice(secret).size()) { if (old_secret.size() == td::as_slice(secret).size()) {
secret.as_mutable_slice().copy_from(old_secret); secret.as_mutable_slice().copy_from(old_secret);
} else { } else {
td::Random::secure_bytes(secret.as_mutable_slice()); 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); td::SecureString decrypted_secret(32);
for (size_t i = 0; i < decrypted_secret.size(); i++) { hmac_sha256(secret, local_password, decrypted_secret.as_mutable_slice());
decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i];
}
td::SecureString encryption_secret(64); td::SecureString encryption_secret(64);
pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS, pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS,

View File

@ -56,8 +56,6 @@ struct DecryptedKey {
std::vector<td::SecureString> mnemonic_words; std::vector<td::SecureString> mnemonic_words;
td::Ed25519::PrivateKey private_key; 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; EncryptedKey encrypt(td::Slice local_password, td::Slice secret = {}) const;
}; };

View File

@ -24,15 +24,19 @@
#include "td/utils/crypto.h" #include "td/utils/crypto.h"
namespace tonlib { namespace tonlib {
td::Result<DecryptedKey> EncryptedKey::decrypt(td::Slice local_password, bool check_public_key) { td::Result<DecryptedKey> EncryptedKey::decrypt(td::Slice local_password, bool check_public_key, bool old) const {
if (secret.size() != 32) { if (secret.size() != 32) {
return td::Status::Error("Failed to decrypt key: invalid secret size"); 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); td::SecureString decrypted_secret(32);
for (size_t i = 0; i < 32; i++) { if (old) {
decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i]; 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); td::SecureString encryption_secret(64);

View File

@ -32,7 +32,7 @@ struct EncryptedKey {
td::Ed25519::PublicKey public_key; td::Ed25519::PublicKey public_key;
td::SecureString secret; td::SecureString secret;
td::Result<DecryptedKey> decrypt(td::Slice local_password, bool check_public_key = true); td::Result<DecryptedKey> decrypt(td::Slice local_password, bool check_public_key = true, bool old = false) const;
}; };
} // namespace tonlib } // namespace tonlib

View File

@ -186,11 +186,21 @@ class TonlibCli : public td::actor::Actor {
if (cmd.empty()) { if (cmd.empty()) {
return; 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") { if (cmd == "help") {
td::TerminalIO::out() << "help - show this help\n"; td::TerminalIO::out() << "help - show this help\n";
td::TerminalIO::out() << "genkey - generate new secret key\n"; td::TerminalIO::out() << "genkey - generate new secret key\n";
td::TerminalIO::out() << "keys - show all stored keys\n"; td::TerminalIO::out() << "keys - show all stored keys\n";
td::TerminalIO::out() << "unpackaddress <address> - validate and parse address\n"; td::TerminalIO::out() << "unpackaddress <address> - validate and parse address\n";
td::TerminalIO::out() << "setbounceble <address> [<bounceble>] - change bounceble flag in address\n";
td::TerminalIO::out() << "importkey - import key\n"; td::TerminalIO::out() << "importkey - import key\n";
td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n"; td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n";
td::TerminalIO::out() << "exportkey [<key_id>] - export key\n"; td::TerminalIO::out() << "exportkey [<key_id>] - export key\n";
@ -214,6 +224,8 @@ class TonlibCli : public td::actor::Actor {
try_stop(); try_stop();
} else if (cmd == "keys") { } else if (cmd == "keys") {
dump_keys(); dump_keys();
} else if (cmd == "deletekey") {
//delete_key(parser.read_word());
} else if (cmd == "deletekeys") { } else if (cmd == "deletekeys") {
delete_all_keys(); delete_all_keys();
} else if (cmd == "exportkey") { } else if (cmd == "exportkey") {
@ -223,15 +235,6 @@ class TonlibCli : public td::actor::Actor {
} else if (cmd == "setconfig") { } else if (cmd == "setconfig") {
auto config = parser.read_word(); auto config = parser.read_word();
auto name = 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 use_callback = parser.read_word();
auto force = parser.read_word(); auto force = parser.read_word();
set_config(config, name, to_bool(use_callback), to_bool(force)); 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()); get_hints(parser.read_word());
} else if (cmd == "unpackaddress") { } else if (cmd == "unpackaddress") {
unpack_address(parser.read_word()); 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<tonlib_api::unpackAccountAddress>(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<tonlib_api::packAccountAddress>(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 = {}) { void generate_key(td::SecureString entropy = {}) {
if (entropy.size() < 20) { if (entropy.size() < 20) {
td::TerminalIO::out() << "Enter some entropy"; td::TerminalIO::out() << "Enter some entropy";
@ -527,6 +554,25 @@ class TonlibCli : public td::actor::Actor {
return std::move(res); 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<tonlib_api::deleteKey>(
make_object<tonlib_api::key>(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) { void export_key(td::Slice key) {
if (key.empty()) { if (key.empty()) {
dump_keys(); 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, void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message,
bool allow_send_to_uninited) { bool allow_send_to_uninited) {
auto r_sz = td::to_integer_safe<td::size_t>(message);
auto msg = message.str();
if (r_sz.is_ok()) {
msg = std::string(r_sz.ok(), 'Z');
}
using tonlib_api::make_object; using tonlib_api::make_object;
auto key = !from.secret.empty() auto key = !from.secret.empty()
? make_object<tonlib_api::inputKey>( ? make_object<tonlib_api::inputKey>(
@ -761,7 +812,7 @@ class TonlibCli : public td::actor::Actor {
: nullptr; : nullptr;
send_query( send_query(
make_object<tonlib_api::generic_sendGrams>(std::move(key), std::move(from.address), std::move(to.address), make_object<tonlib_api::generic_sendGrams>(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) { [this](auto r_res) {
if (r_res.is_error()) { if (r_res.is_error()) {
td::TerminalIO::out() << "Can't transfer: " << r_res.error() << "\n"; 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); options.config = std::move(data);
return td::Status::OK(); 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", [&]() { p.add_option('n', "use-callbacks-for-network", "do not use this", [&]() {
options.use_callbacks_for_network = true; options.use_callbacks_for_network = true;
return td::Status::OK(); return td::Status::OK();

View File

@ -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())); 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()); auto cs = vm::load_cell_slice_ref(cb.finalize());
state_extra.r1.block_create_stats = cs; 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)) { if (!block::gen::t_BlockCreateStats.validate_csr(cs)) {
cs->print_rec(std::cerr); cs->print_rec(std::cerr);
block::gen::t_BlockCreateStats.print(std::cerr, *cs); 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) { int Collator::creator_count_outdated(td::ConstBitPtr key, vm::CellSlice& cs) {
block::DiscountedCounter mc_cnt, shard_cnt; block::DiscountedCounter mc_cnt, shard_cnt;
if (!(block::fetch_CreatorStats(cs, mc_cnt, shard_cnt) && cs.empty_ext())) { 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_))) { 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)) { if (!(mc_cnt.cnt65536 | shard_cnt.cnt65536)) {
LOG(DEBUG) << "removing stale CreatorStats for " << key.to_hex(256); 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()); 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()); 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)"); 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) { int cnt = block_create_stats_->filter([this](vm::CellSlice& cs, td::ConstBitPtr key, int key_len) {
CHECK(key_len == 256); CHECK(key_len == 256);
return creator_count_outdated(key, cs); 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; return cnt >= 0;
} }

View File

@ -192,7 +192,7 @@ void LiteQuery::perform_getMasterchainInfo(int mode) {
} }
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
[Self = actor_id(this), mode](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) { [ Self = actor_id(this), mode ](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -230,7 +230,7 @@ void LiteQuery::perform_getBlock(BlockIdExt blkid) {
return; return;
} }
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid, td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::BlockData>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -256,7 +256,7 @@ void LiteQuery::perform_getBlockHeader(BlockIdExt blkid, int mode) {
return; return;
} }
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid, td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[Self = actor_id(this), blkid, mode](td::Result<Ref<ton::validator::BlockData>> res) { [ Self = actor_id(this), blkid, mode ](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -371,7 +371,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
} }
if (blkid.id.seqno) { if (blkid.id.seqno) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid, td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::ShardState>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::ShardState>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -381,7 +381,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
}); });
} else { } else {
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid, td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) { [ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -440,7 +440,7 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
++pending_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_data_from_db_short, blkid, manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : ")); 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_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_proof_from_db_short, blkid, manager_, &ValidatorManager::get_block_proof_from_db_short, blkid,
[Self = actor_id(this), blkid, mode](td::Result<Ref<Proof>> res) { [ Self = actor_id(this), blkid, mode ](td::Result<Ref<Proof>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : ")); 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_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid, manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : ")); 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_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid, manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : ")); 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_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_data_from_db_short, blkid, manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : ")); res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
@ -563,7 +563,7 @@ bool LiteQuery::request_proof_link(BlockIdExt blkid) {
++pending_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid, manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
[Self = actor_id(this), blkid](td::Result<Ref<ProofLink>> res) { [ Self = actor_id(this), blkid ](td::Result<Ref<ProofLink>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : ")); 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_; ++pending_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_zero_state, blkid, manager_, &ValidatorManager::get_zero_state, blkid,
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) { [ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : ")); 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"; LOG(INFO) << "sending a get_top_masterchain_state_block query to manager";
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) -> void { [Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res)->void {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -1067,7 +1067,7 @@ void LiteQuery::continue_getTransactions(unsigned remaining, bool exact) {
<< " " << trans_lt_; << " " << trans_lt_;
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_by_lt_from_db, ton::extract_addr_prefix(acc_workchain_, acc_addr_), 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<BlockIdExt> res) { trans_lt_, [ Self = actor_id(this), remaining, manager = manager_ ](td::Result<BlockIdExt> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{}); td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{});
} else { } 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<int> param_list) { void LiteQuery::perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list) {
LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", <list of " << param_list.size() LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", <list of " << param_list.size()
<< " parameters>) liteserver query"; << " parameters>) 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)); continue_getConfigParams(mode, std::move(param_list));
}); });
request_mc_block_data_state(blkid); 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 LOG(INFO) << "performing a lookupBlock(" << blkid.to_str() << ", " << mode << ", " << lt << ", " << utime
<< ") query"; << ") query";
auto P = td::PromiseCreator::lambda( auto P = td::PromiseCreator::lambda(
[Self = actor_id(this), manager = manager_, mode = (mode >> 4)](td::Result<BlockIdExt> res) { [ Self = actor_id(this), manager = manager_, mode = (mode >> 4) ](td::Result<BlockIdExt> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
@ -1446,58 +1446,83 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
return; return;
} }
if (mode & 1) { if (mode & 1) {
base_blk_id_ = (from.seqno() > to.seqno()) ? from : to; if (mode & 0x1000) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, base_blk_id_, BlockIdExt bblk = (from.seqno() > to.seqno()) ? from : to;
[Self = actor_id(this), from, to, mode](td::Result<Ref<ShardState>> res) { td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, bblk,
if (res.is_error()) { [ Self = actor_id(this), from, to, bblk, mode ](td::Result<Ref<ShardState>> res) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); if (res.is_error()) {
} else { td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to, } else {
mode, Ref<MasterchainStateQ>(res.move_as_ok())); td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from,
} to, mode, bblk,
}); Ref<MasterchainStateQ>(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<std::pair<Ref<MasterchainState>, 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<MasterchainStateQ>(std::move(pair.first)));
}
});
}
} else if (mode & 2) { } else if (mode & 2) {
td::actor::send_closure_later( td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block, manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
[Self = actor_id(this), from, mode](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) { [ Self = actor_id(this), from, mode ](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
auto pair = res.move_as_ok(); auto pair = res.move_as_ok();
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, pair.second, mode, td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, pair.second, mode,
Ref<MasterchainStateQ>(std::move(pair.first))); pair.second, Ref<MasterchainStateQ>(std::move(pair.first)));
} }
}); });
} else { } else {
td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_shard_client_state, false, td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_shard_client_state, false,
[Self = actor_id(this), from, mode](td::Result<BlockIdExt> res) { [ Self = actor_id(this), from, mode ](td::Result<BlockIdExt> res) {
if (res.is_error()) { if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error()); td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else { } else {
td::actor::send_closure_later(Self, &LiteQuery::perform_getBlockProof, from, 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<MasterchainStateQ> state) { Ref<MasterchainStateQ> 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)) { if (!(mode & 1)) {
base_blk_id_ = to;
if (!to.is_masterchain_ext()) { if (!to.is_masterchain_ext()) {
fatal_error("last masterchain block id "s + to.to_str() + " is invalid"); fatal_error("last masterchain block id "s + to.to_str() + " is invalid");
return; 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()) { if (state.is_null()) {
fatal_error("obtained no valid masterchain state for block "s + base_blk_id_.to_str()); fatal_error("obtained no valid masterchain state for block "s + base_blk_id_.to_str());
return; 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<MasterchainStateQ>(state); mc_state0_ = Ref<MasterchainStateQ>(state);
if (base_blk_id_ != state->get_block_id()) { 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 " + 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() LOG(INFO) << "continuing getBlockProof(" << mode << ", " << from.to_str() << ", " << to.to_str()
<< ") query with a state for " << base_blk_id_.to_str(); << ") query with a state for " << base_blk_id_.to_str();
if (!state->check_old_mc_block_id(from)) { 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 " + fatal_error("proof source masterchain block "s + from.to_str() +
base_blk_id_.to_str()); " is unknown from the perspective of reference block " + base_blk_id_.to_str());
return; return;
} }
if (!state->check_old_mc_block_id(to)) { 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 " + fatal_error("proof destination masterchain block "s + to.to_str() +
base_blk_id_.to_str()); " is unknown from the perspective of reference block " + base_blk_id_.to_str());
return; return;
} }
chain_ = std::make_unique<block::BlockProofChain>(from, to, mode); chain_ = std::make_unique<block::BlockProofChain>(from, to, mode);

View File

@ -111,9 +111,10 @@ class LiteQuery : public td::actor::Actor {
void perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, UnixTime utime); 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 perform_listBlockTransactions(BlockIdExt blkid, int mode, int count, Bits256 account, LogicalTime lt);
void finish_listBlockTransactions(int mode, int count); void finish_listBlockTransactions(int mode, int count);
void perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode); void perform_getBlockProof(BlockIdExt from, BlockIdExt to, int mode);
void continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, Ref<MasterchainStateQ> state); void continue_getBlockProof(BlockIdExt from, BlockIdExt to, int mode, BlockIdExt baseblk,
bool construct_proof_chain(ton::BlockIdExt id); Ref<MasterchainStateQ> state);
bool construct_proof_chain(BlockIdExt id);
bool construct_proof_link_forward(ton::BlockIdExt cur, ton::BlockIdExt next); 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_forward_cont(ton::BlockIdExt cur, ton::BlockIdExt next);
bool construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt next); bool construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt next);

View File

@ -1880,10 +1880,12 @@ void ValidatorManagerImpl::update_shard_client_block_handle(BlockHandle handle,
void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) { void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) {
if (min_confirmed_masterchain_seqno_ < seqno) { if (min_confirmed_masterchain_seqno_ < seqno) {
min_confirmed_masterchain_seqno_ = seqno; min_confirmed_masterchain_seqno_ = seqno;
} else {
return;
} }
while (shard_client_waiters_.size() > 0) { while (shard_client_waiters_.size() > 0) {
auto it = shard_client_waiters_.begin(); auto it = shard_client_waiters_.begin();
if (it->first > seqno) { if (it->first > min_confirmed_masterchain_seqno_) {
break; break;
} }
for (auto &y : it->second.waiting_) { for (auto &y : it->second.waiting_) {