mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
Tonlib improvement fixes (#934)
* 3.6. Fix directory traversal in KeyValueDir * 3.9. Fix buffer_to_hex reversing nibbles * 3.5. Fix error handling at blocks.getBlockHeader * 3.11. Fix query.forget * 3.12. Fix error handling in RemoteRunSmcMethod * 4.1. Delete unused files * 3.10. Use named constants instead hardcoded constants * 3.4. Fix response block header verification * 3.1. Check proof of blocks.getShards response * fix td::buffer_to_hex + test * 3.2. Add proof check for listBlockTransactions response in RunEmulator actor * 3.8. Add proof checking for getLibraries method * fix regression tests * 3.3 Add proof checking for lookupBlock method * Add publishers to proof of getLibrariesWithProof response (#25) * fix missing return, fix requesting mc block * Fix requesting lookupBlock with client mc blk == mc ref block * Fix duplicating lib data in proof and data, add mode 2 for not including the data * Migration of LastBlockStorage with fixed td::buffer_to_hex --------- Co-authored-by: ms <dungeon666master@protonmail.com> Co-authored-by: Marat <98183742+dungeon-master-666@users.noreply.github.com>
This commit is contained in:
parent
69de1cb621
commit
f1592641de
25 changed files with 1000 additions and 854 deletions
|
@ -71,7 +71,7 @@ void WalletInterface::store_gift_message(vm::CellBuilder &cb, const Gift &gift)
|
|||
|
||||
cb.store_zeroes(1);
|
||||
if (gift.is_encrypted) {
|
||||
cb.store_long(0x2167da4b, 32);
|
||||
cb.store_long(EncryptedCommentOp, 32);
|
||||
} else {
|
||||
cb.store_long(0, 32);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
namespace ton {
|
||||
class WalletInterface : public SmartContract {
|
||||
public:
|
||||
static constexpr uint32_t EncryptedCommentOp = 0x2167da4b;
|
||||
struct Gift {
|
||||
block::StdAddress destination;
|
||||
td::int64 gramms;
|
||||
|
|
|
@ -153,9 +153,9 @@ string buffer_to_hex(Slice buffer) {
|
|||
const char *hex = "0123456789ABCDEF";
|
||||
string res(2 * buffer.size(), '\0');
|
||||
for (std::size_t i = 0; i < buffer.size(); i++) {
|
||||
auto c = buffer.ubegin()[i];
|
||||
res[2 * i] = hex[c & 15];
|
||||
res[2 * i + 1] = hex[c >> 4];
|
||||
unsigned char c = buffer[i];
|
||||
res[2 * i] = hex[c >> 4];
|
||||
res[2 * i + 1] = hex[c & 15];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
abce
|
||||
Test_Bigint_main_default 76f38492ec19464a1d0eac51d389023a31ce10396b3894061361d159567ce8cd
|
||||
Test_Bitstrings_main_default a8b08af3116923c4c2a14e138d168375abd0c059f2f780d3267b294929a1110e
|
||||
Test_Cells_simple_default 832502642fe4fe5db70de82681aedb7d54d7f3530e0069861fff405fe6f6cf23
|
||||
Test_Cells_simple_default 414f68da0a2f6fa09b2bdb99c453cdf919db48b5b4ca1c6ac1dfcd837e2d8170
|
||||
Test_Fift_bug_div_default 1ac42861ce96b2896001c587f65e9afe1617db48859f19c2f4e3063a20ea60b0
|
||||
Test_Fift_bug_newlize_default e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
Test_Fift_bug_ufits_default 51bf5a9f1ed7633a193f6fdd17a7a3af8e032dfe72a9669c85e8639aa8a7c195
|
||||
|
|
|
@ -53,8 +53,10 @@ liteServer.partialBlockProof complete:Bool from:tonNode.blockIdExt to:tonNode.bl
|
|||
liteServer.configInfo mode:# id:tonNode.blockIdExt state_proof:bytes config_proof:bytes = liteServer.ConfigInfo;
|
||||
liteServer.validatorStats mode:# id:tonNode.blockIdExt count:int complete:Bool state_proof:bytes data_proof:bytes = liteServer.ValidatorStats;
|
||||
liteServer.libraryResult result:(vector liteServer.libraryEntry) = liteServer.LibraryResult;
|
||||
liteServer.libraryResultWithProof id:tonNode.blockIdExt mode:# result:(vector liteServer.libraryEntry) state_proof:bytes data_proof:bytes = liteServer.LibraryResultWithProof;
|
||||
liteServer.shardBlockLink id:tonNode.blockIdExt proof:bytes = liteServer.ShardBlockLink;
|
||||
liteServer.shardBlockProof masterchain_id:tonNode.blockIdExt links:(vector liteServer.shardBlockLink) = liteServer.ShardBlockProof;
|
||||
liteServer.lookupBlockResult id:tonNode.blockIdExt mode:# mc_block_id:tonNode.blockIdExt client_mc_state_proof:bytes mc_block_proof:bytes shard_links:(vector liteServer.shardBlockLink) header:bytes prev_header:bytes = liteServer.LookupBlockResult;
|
||||
|
||||
liteServer.debug.verbosity value:int = liteServer.debug.Verbosity;
|
||||
|
||||
|
@ -76,6 +78,7 @@ liteServer.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo;
|
|||
liteServer.getOneTransaction id:tonNode.blockIdExt account:liteServer.accountId lt:long = liteServer.TransactionInfo;
|
||||
liteServer.getTransactions count:# account:liteServer.accountId lt:long hash:int256 = liteServer.TransactionList;
|
||||
liteServer.lookupBlock mode:# id:tonNode.blockId lt:mode.1?long utime:mode.2?int = liteServer.BlockHeader;
|
||||
liteServer.lookupBlockWithProof mode:# id:tonNode.blockId mc_block_id:tonNode.blockIdExt lt:mode.1?long utime:mode.2?int = liteServer.LookupBlockResult;
|
||||
liteServer.listBlockTransactions id:tonNode.blockIdExt mode:# count:# after:mode.7?liteServer.transactionId3 reverse_order:mode.6?true want_proof:mode.5?true = liteServer.BlockTransactions;
|
||||
liteServer.listBlockTransactionsExt id:tonNode.blockIdExt mode:# count:# after:mode.7?liteServer.transactionId3 reverse_order:mode.6?true want_proof:mode.5?true = liteServer.BlockTransactionsExt;
|
||||
liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||
|
@ -83,6 +86,7 @@ liteServer.getConfigAll mode:# id:tonNode.blockIdExt = liteServer.ConfigInfo;
|
|||
liteServer.getConfigParams mode:# id:tonNode.blockIdExt param_list:(vector int) = liteServer.ConfigInfo;
|
||||
liteServer.getValidatorStats#091a58bc mode:# id:tonNode.blockIdExt limit:int start_after:mode.0?int256 modified_after:mode.2?int = liteServer.ValidatorStats;
|
||||
liteServer.getLibraries library_list:(vector int256) = liteServer.LibraryResult;
|
||||
liteServer.getLibrariesWithProof id:tonNode.blockIdExt mode:# library_list:(vector int256) = liteServer.LibraryResultWithProof;
|
||||
liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof;
|
||||
|
||||
liteServer.queryPrefix = Object;
|
||||
|
|
Binary file not shown.
|
@ -83,7 +83,7 @@ using namespace tonlib;
|
|||
TEST(Tonlib, PublicKey) {
|
||||
block::PublicKey::parse("pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2").ensure_error();
|
||||
auto key = block::PublicKey::parse("Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2").move_as_ok();
|
||||
CHECK(td::buffer_to_hex(key.key) == "3EE9DC0A7A0B6CA01770CE34698792BD8ECB53A6949BFD6C81B6E3CA475B74D7");
|
||||
CHECK(td::buffer_to_hex(key.key) == "E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D");
|
||||
CHECK(key.serialize() == "Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
#include "CellString.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include "vm/cells/CellSlice.h"
|
||||
|
||||
namespace vm {
|
||||
td::Status CellString::store(CellBuilder &cb, td::Slice slice, unsigned int top_bits) {
|
||||
td::uint32 size = td::narrow_cast<td::uint32>(slice.size() * 8);
|
||||
return store(cb, td::BitSlice(slice.ubegin(), size), top_bits);
|
||||
}
|
||||
|
||||
td::Status CellString::store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits) {
|
||||
if (slice.size() > max_bytes * 8) {
|
||||
return td::Status::Error("String is too long (1)");
|
||||
}
|
||||
unsigned int head = td::min(slice.size(), td::min(cb.remaining_bits(), top_bits)) / 8 * 8;
|
||||
auto max_bits = vm::Cell::max_bits / 8 * 8;
|
||||
auto depth = 1 + (slice.size() - head + max_bits - 1) / max_bits;
|
||||
if (depth > max_chain_length) {
|
||||
return td::Status::Error("String is too long (2)");
|
||||
}
|
||||
cb.append_bitslice(slice.subslice(0, head));
|
||||
slice.advance(head);
|
||||
if (slice.size() == 0) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
CellBuilder child_cb;
|
||||
store(child_cb, std::move(slice));
|
||||
cb.store_ref(child_cb.finalize());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void CellString::for_each(F &&f, CellSlice &cs, unsigned int top_bits) {
|
||||
unsigned int head = td::min(cs.size(), top_bits);
|
||||
f(cs.prefetch_bits(head));
|
||||
if (!cs.have_refs()) {
|
||||
return;
|
||||
}
|
||||
auto ref = cs.prefetch_ref();
|
||||
while (true) {
|
||||
auto cs = vm::load_cell_slice(ref);
|
||||
f(cs.prefetch_bits(cs.size()));
|
||||
if (!cs.have_refs()) {
|
||||
return;
|
||||
}
|
||||
ref = cs.prefetch_ref();
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::string> CellString::load(CellSlice &cs, unsigned int top_bits) {
|
||||
unsigned int size = 0;
|
||||
for_each([&](auto slice) { size += slice.size(); }, cs, top_bits);
|
||||
if (size % 8 != 0) {
|
||||
return td::Status::Error("Size is not divisible by 8");
|
||||
}
|
||||
std::string res(size / 8, 0);
|
||||
|
||||
td::BitPtr to(td::MutableSlice(res).ubegin());
|
||||
for_each([&](auto slice) { to.concat(slice); }, cs, top_bits);
|
||||
CHECK(to.offs == (int)size);
|
||||
return res;
|
||||
}
|
||||
} // namespace vm
|
|
@ -1,22 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include "vm/cells/CellBuilder.h"
|
||||
|
||||
namespace vm {
|
||||
class CellString {
|
||||
public:
|
||||
static constexpr unsigned int max_bytes = 1024;
|
||||
static constexpr unsigned int max_chain_length = 16;
|
||||
|
||||
static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits);
|
||||
static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits);
|
||||
static td::Result<td::string> load(CellSlice &cs, unsigned int top_bits = Cell::max_bits);
|
||||
|
||||
private:
|
||||
template <class F>
|
||||
static void for_each(F &&f, CellSlice &cs, unsigned int top_bits = Cell::max_bits);
|
||||
};
|
||||
|
||||
} // namespace vm
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "tonlib/TonlibCallback.h"
|
||||
#include "tonlib/TonlibClient.h"
|
||||
#include "auto/tl/tonlib_api.h"
|
||||
|
||||
namespace tonlinb {
|
||||
class ClientActor : public td::actor::Actor {
|
||||
public:
|
||||
explicit ClientActor(td::unique_ptr<TonlibCallback> callback);
|
||||
void request(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Function> request);
|
||||
static tonlib_api::object_ptr<tonlib_api::Object> execute(tonlib_api::object_ptr<tonlib_api::Function> request);
|
||||
~ClientActor();
|
||||
ClientActor(ClientActor&& other);
|
||||
ClientActor& operator=(ClientActor&& other);
|
||||
|
||||
ClientActor(const ClientActor& other) = delete;
|
||||
ClientActor& operator=(const ClientActor& other) = delete;
|
||||
|
||||
private:
|
||||
td::actor::ActorOwn<TonlibClient> tonlib_;
|
||||
};
|
||||
} // namespace tonlinb
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/utils.h"
|
||||
#include "block/block-auto.h"
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept {
|
||||
return vm::CellBuilder()
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{00110}").move_as_ok())
|
||||
.store_ref(std::move(code))
|
||||
.store_ref(std::move(data))
|
||||
.finalize();
|
||||
}
|
||||
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id,
|
||||
const td::Ref<vm::Cell>& init_state) noexcept {
|
||||
return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/);
|
||||
}
|
||||
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body) noexcept {
|
||||
block::gen::Message::Record message;
|
||||
/*info*/ {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
/* src */
|
||||
tlb::csr_pack(info.src, block::gen::MsgAddressExt::Record_addr_none{});
|
||||
/* dest */ {
|
||||
block::gen::MsgAddressInt::Record_addr_std dest;
|
||||
dest.anycast = vm::CellBuilder().store_zeroes(1).as_cellslice_ref();
|
||||
dest.workchain_id = address.workchain;
|
||||
dest.address = address.addr;
|
||||
|
||||
tlb::csr_pack(info.dest, dest);
|
||||
}
|
||||
/* import_fee */ {
|
||||
vm::CellBuilder cb;
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(0));
|
||||
info.import_fee = cb.as_cellslice_ref();
|
||||
}
|
||||
|
||||
tlb::csr_pack(message.info, info);
|
||||
}
|
||||
/* init */ {
|
||||
if (new_state.not_null()) {
|
||||
// Just(Left(new_state))
|
||||
message.init = vm::CellBuilder()
|
||||
.store_ones(1)
|
||||
.store_zeroes(1)
|
||||
.append_cellslice(vm::load_cell_slice(new_state))
|
||||
.as_cellslice_ref();
|
||||
} else {
|
||||
message.init = vm::CellBuilder().store_zeroes(1).as_cellslice_ref();
|
||||
CHECK(message.init.not_null());
|
||||
}
|
||||
}
|
||||
/* body */ {
|
||||
message.body = vm::CellBuilder().store_zeroes(1).append_cellslice(vm::load_cell_slice_ref(body)).as_cellslice_ref();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> res;
|
||||
tlb::type_pack_cell(res, block::gen::t_Message_Any, message);
|
||||
CHECK(res.not_null());
|
||||
|
||||
return res;
|
||||
}
|
||||
} // namespace tonlib
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
#include "block/block.h"
|
||||
namespace tonlib {
|
||||
class GenericAccount {
|
||||
public:
|
||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept;
|
||||
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) noexcept;
|
||||
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body) noexcept;
|
||||
};
|
||||
} // namespace tonlib
|
|
@ -42,7 +42,11 @@ class KeyValueDir : public KeyValue {
|
|||
}
|
||||
|
||||
td::Status add(td::Slice key, td::Slice value) override {
|
||||
auto path = to_file_path(key.str());
|
||||
auto key_str = key.str();
|
||||
if (!is_valid_key(key_str)) {
|
||||
return td::Status::Error("Invalid key");
|
||||
}
|
||||
auto path = to_file_path(key_str);
|
||||
if (td::stat(path).is_ok()) {
|
||||
return td::Status::Error(PSLICE() << "File " << path << "already exists");
|
||||
}
|
||||
|
@ -50,15 +54,27 @@ class KeyValueDir : public KeyValue {
|
|||
}
|
||||
|
||||
td::Status set(td::Slice key, td::Slice value) override {
|
||||
return td::atomic_write_file(to_file_path(key.str()), value);
|
||||
auto key_str = key.str();
|
||||
if (!is_valid_key(key_str)) {
|
||||
return td::Status::Error("Invalid key");
|
||||
}
|
||||
return td::atomic_write_file(to_file_path(key_str), value);
|
||||
}
|
||||
|
||||
td::Result<td::SecureString> get(td::Slice key) override {
|
||||
return td::read_file_secure(to_file_path(key.str()));
|
||||
auto key_str = key.str();
|
||||
if (!is_valid_key(key_str)) {
|
||||
return td::Status::Error("Invalid key");
|
||||
}
|
||||
return td::read_file_secure(to_file_path(key_str));
|
||||
}
|
||||
|
||||
td::Status erase(td::Slice key) override {
|
||||
return td::unlink(to_file_path(key.str()));
|
||||
auto key_str = key.str();
|
||||
if (!is_valid_key(key_str)) {
|
||||
return td::Status::Error("Invalid key");
|
||||
}
|
||||
return td::unlink(to_file_path(key_str));
|
||||
}
|
||||
|
||||
void foreach_key(std::function<void(td::Slice)> f) override {
|
||||
|
@ -83,6 +99,20 @@ class KeyValueDir : public KeyValue {
|
|||
std::string to_file_path(std::string key) {
|
||||
return directory_ + TD_DIR_SLASH + key;
|
||||
}
|
||||
|
||||
bool is_valid_key(const std::string& key) {
|
||||
if (key.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key.find(TD_DIR_SLASH) != std::string::npos || key.find("..") != std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::all_of(key.begin(), key.end(), [](char c) {
|
||||
return std::isalnum(c) || c == '_' || c == '-' || c == '.';
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class KeyValueInmemory : public KeyValue {
|
||||
|
|
|
@ -32,13 +32,43 @@ void LastBlockStorage::set_key_value(std::shared_ptr<KeyValue> kv) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
std::string buffer_to_hex_nibbles_reversed(td::Slice buffer) {
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
std::string res(2 * buffer.size(), '\0');
|
||||
for (std::size_t i = 0; i < buffer.size(); i++) {
|
||||
unsigned char c = buffer[i];
|
||||
res[2 * i + 1] = hex[c >> 4];
|
||||
res[2 * i] = hex[c & 15];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string get_file_name_depr(td::Slice name) {
|
||||
return buffer_to_hex_nibbles_reversed(name) + ".blkstate";
|
||||
}
|
||||
|
||||
std::string get_file_name(td::Slice name) {
|
||||
return td::buffer_to_hex(name) + ".blkstate";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
td::Result<LastBlockState> LastBlockStorage::get_state(td::Slice name) {
|
||||
TRY_RESULT(data, kv_->get(get_file_name(name)));
|
||||
// This migration addresses an issue in the old version of Tonlib, where the td::buffer_to_hex
|
||||
// incorrectly reversed the order of nibbles in hex representation.
|
||||
auto data_r = kv_->get(get_file_name(name));
|
||||
if (data_r.is_error()) {
|
||||
auto key_depr = get_file_name_depr(name);
|
||||
auto data_depr = kv_->get(key_depr);
|
||||
if (data_depr.is_ok()) {
|
||||
kv_->set(get_file_name(name), data_depr.move_as_ok());
|
||||
kv_->erase(key_depr);
|
||||
data_r = std::move(data_depr);
|
||||
} else {
|
||||
return td::Status::Error("not found");
|
||||
}
|
||||
}
|
||||
|
||||
auto data = data_r.move_as_ok();
|
||||
if (data.size() < 8) {
|
||||
return td::Status::Error("too short");
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace tonlib {
|
||||
const block::StdAddress& TestGiver::address() noexcept {
|
||||
static block::StdAddress res =
|
||||
block::StdAddress::parse("kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash TestGiver::get_init_code_hash() noexcept {
|
||||
return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok());
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept {
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
cb.append_cellslice(binary_bitstring_to_cellslice("b{01}").move_as_ok())
|
||||
.store_long(dest_address.bounceable, 1)
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
||||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
|
||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
|
||||
}
|
||||
} // namespace tonlib
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "block/block.h"
|
||||
#include "CellString.h"
|
||||
namespace tonlib {
|
||||
class TestGiver {
|
||||
public:
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static const block::StdAddress& address() noexcept;
|
||||
static vm::CellHash get_init_code_hash() noexcept;
|
||||
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept;
|
||||
};
|
||||
} // namespace tonlib
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "tonlib/TestWallet.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
auto code = get_init_code();
|
||||
auto data = get_init_data(public_key);
|
||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept {
|
||||
std::string seq_no(4, 0);
|
||||
auto signature =
|
||||
private_key.sign(vm::CellBuilder().store_bytes(seq_no).finalize()->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).store_bytes(seq_no).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept {
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
cb.append_cellslice(binary_bitstring_to_cellslice("b{01}").move_as_ok())
|
||||
.store_long(dest_address.bounceable, 1)
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
||||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
td::int32 send_mode = 3;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
send_mode += 128;
|
||||
}
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
auto message_outer =
|
||||
vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize();
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_code() noexcept {
|
||||
static auto res = [] {
|
||||
auto serialized_code = td::base64_decode(
|
||||
"te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/"
|
||||
"0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA==")
|
||||
.move_as_ok();
|
||||
return vm::std_boc_deserialize(serialized_code).move_as_ok();
|
||||
}();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash TestWallet::get_init_code_hash() noexcept {
|
||||
return get_init_code()->get_hash();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||
}
|
||||
} // namespace tonlib
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block.h"
|
||||
#include "CellString.h"
|
||||
|
||||
namespace tonlib {
|
||||
class TestWallet {
|
||||
public:
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept;
|
||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept;
|
||||
|
||||
static td::Ref<vm::Cell> get_init_code() noexcept;
|
||||
static vm::CellHash get_init_code_hash() noexcept;
|
||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
};
|
||||
} // namespace tonlib
|
|
@ -1227,8 +1227,7 @@ class RemoteRunSmcMethod : public td::actor::Actor {
|
|||
td::Status do_with_last_block(td::Result<LastBlockState> r_last_block) {
|
||||
TRY_RESULT(last_block, std::move(r_last_block));
|
||||
query_.block_id = std::move(last_block.last_block_id);
|
||||
with_block_id();
|
||||
return td::Status::OK();
|
||||
return with_block_id();
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
|
@ -1729,6 +1728,9 @@ class GetShardBlockProof : public td::actor::Actor {
|
|||
auto to_lite_api(const tonlib_api::ton_blockIdExt& blk) -> td::Result<lite_api_ptr<ton::lite_api::tonNode_blockIdExt>>;
|
||||
auto to_tonlib_api(const ton::lite_api::liteServer_transactionId& txid) -> tonlib_api_ptr<tonlib_api::blocks_shortTxId>;
|
||||
|
||||
td::Status check_block_transactions_proof(lite_api_ptr<ton::lite_api::liteServer_blockTransactions>& bTxes, int32_t mode,
|
||||
ton::LogicalTime start_lt, td::Bits256 start_addr, td::Bits256 root_hash, int req_count);
|
||||
|
||||
class RunEmulator : public TonlibQueryActor {
|
||||
public:
|
||||
RunEmulator(ExtClientRef ext_client_ref, int_api::GetAccountStateByTransaction request,
|
||||
|
@ -1778,7 +1780,6 @@ class RunEmulator : public TonlibQueryActor {
|
|||
return td::Status::Error("block header proof is not a valid Merkle proof");
|
||||
}
|
||||
|
||||
ton::RootHash vhash{virt_root->get_hash().bits()};
|
||||
if (ton::RootHash{virt_root->get_hash().bits()} != block_id.root_hash) {
|
||||
return td::Status::Error("block header has incorrect root hash");
|
||||
}
|
||||
|
@ -1837,14 +1838,18 @@ class RunEmulator : public TonlibQueryActor {
|
|||
td::Status get_transactions(std::int64_t lt) {
|
||||
TRY_RESULT(lite_block, to_lite_api(*to_tonlib_api(block_id_.id)));
|
||||
auto after = ton::lite_api::make_object<ton::lite_api::liteServer_transactionId3>(request_.address.addr, lt);
|
||||
auto query = ton::lite_api::liteServer_listBlockTransactions(std::move(lite_block), 0b10100111, 256, std::move(after), false, false);
|
||||
auto mode = 0b10100111;
|
||||
constexpr int req_count = 256;
|
||||
auto query = ton::lite_api::liteServer_listBlockTransactions(std::move(lite_block), mode, req_count, std::move(after), false, true);
|
||||
|
||||
client_.send_query(std::move(query), [self = this](lite_api_ptr<ton::lite_api::liteServer_blockTransactions>&& bTxes) {
|
||||
client_.send_query(std::move(query), [self = this, mode, lt, root_hash = block_id_.id.root_hash, req_count](lite_api_ptr<ton::lite_api::liteServer_blockTransactions>&& bTxes) {
|
||||
if (!bTxes) {
|
||||
self->check(td::Status::Error("liteServer.blockTransactions is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
self->check(check_block_transactions_proof(bTxes, mode, lt, self->request_.address.addr, root_hash, req_count));
|
||||
|
||||
std::int64_t last_lt = 0;
|
||||
for (auto& id : bTxes->ids_) {
|
||||
last_lt = id->lt_;
|
||||
|
@ -2971,7 +2976,7 @@ struct ToRawTransactions {
|
|||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (try_decode_messages_ && body->size() >= 32) {
|
||||
auto type = static_cast<td::uint32>(body.write().fetch_long(32));
|
||||
if (type == 0 || type == 0x2167da4b) {
|
||||
if (type == 0 || type == ton::WalletInterface::EncryptedCommentOp) {
|
||||
td::Status status;
|
||||
|
||||
auto r_body_message = TRY_VM(vm::CellString::load(body.write()));
|
||||
|
@ -4241,8 +4246,7 @@ td::Status TonlibClient::do_request(const tonlib_api::query_send& request,
|
|||
|
||||
td::Status TonlibClient::do_request(tonlib_api::query_forget& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
auto it = queries_.find(request.id_);
|
||||
if (it == queries_.end()) {
|
||||
if (queries_.erase(request.id_) == 0) {
|
||||
return TonlibError::InvalidQueryId();
|
||||
}
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
|
@ -4490,10 +4494,31 @@ void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& v
|
|||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::smc_getLibraries& request,
|
||||
td::Promise<object_ptr<tonlib_api::smc_libraryResult>>&& promise) {
|
||||
if (request.library_list_.size() > 16) {
|
||||
promise.set_error(TonlibError::InvalidField("library_list", ": too many libraries requested, 16 maximum"));
|
||||
}
|
||||
if (query_context_.block_id) {
|
||||
get_libraries(query_context_.block_id.value(), request.library_list_, std::move(promise));
|
||||
} else {
|
||||
client_.with_last_block([this, promise = std::move(promise), library_list = request.library_list_](td::Result<LastBlockState> r_last_block) mutable {
|
||||
if (r_last_block.is_error()) {
|
||||
promise.set_error(r_last_block.move_as_error_prefix(TonlibError::Internal("get last block failed ")));
|
||||
} else {
|
||||
this->get_libraries(r_last_block.move_as_ok().last_block_id, library_list, std::move(promise));
|
||||
}
|
||||
});
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void TonlibClient::get_libraries(ton::BlockIdExt blkid, std::vector<td::Bits256> library_list, td::Promise<object_ptr<tonlib_api::smc_libraryResult>>&& promise) {
|
||||
sort(library_list.begin(), library_list.end());
|
||||
library_list.erase(unique(library_list.begin(), library_list.end()), library_list.end());
|
||||
|
||||
std::vector<object_ptr<tonlib_api::smc_libraryEntry>> result_entries;
|
||||
result_entries.reserve(request.library_list_.size());
|
||||
result_entries.reserve(library_list.size());
|
||||
std::vector<td::Bits256> not_cached_hashes;
|
||||
for (auto& library_hash : request.library_list_) {
|
||||
for (auto& library_hash : library_list) {
|
||||
if (libraries.key_exists(library_hash)) {
|
||||
auto library_content = vm::std_boc_serialize(libraries.lookup_ref(library_hash)).move_as_ok().as_slice().str();
|
||||
result_entries.push_back(tonlib_api::make_object<tonlib_api::smc_libraryEntry>(library_hash, library_content));
|
||||
|
@ -4504,40 +4529,80 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getLibraries& request,
|
|||
|
||||
if (not_cached_hashes.empty()) {
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::smc_libraryResult>(std::move(result_entries)));
|
||||
return td::Status::OK();
|
||||
return;
|
||||
}
|
||||
|
||||
client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(not_cached_hashes)),
|
||||
promise.wrap([self=this, result_entries = std::move(result_entries)]
|
||||
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
|
||||
{
|
||||
if (r_libraries.is_error()) {
|
||||
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
|
||||
} else {
|
||||
auto libraries = r_libraries.move_as_ok();
|
||||
bool updated = false;
|
||||
for (auto& lr : libraries->result_) {
|
||||
auto contents = vm::std_boc_deserialize(lr->data_);
|
||||
if (contents.is_ok() && contents.ok().not_null()) {
|
||||
if (contents.ok()->get_hash().bits().compare(lr->hash_.cbits(), 256)) {
|
||||
LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
|
||||
continue;
|
||||
}
|
||||
result_entries.push_back(tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lr->hash_, lr->data_.as_slice().str()));
|
||||
self->libraries.set_ref(lr->hash_, contents.move_as_ok());
|
||||
updated = true;
|
||||
LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
|
||||
} else {
|
||||
LOG(WARNING) << "failed to deserialize library: " << lr->hash_.to_hex();
|
||||
}
|
||||
if (updated) {
|
||||
self->store_libs_to_disk();
|
||||
}
|
||||
}
|
||||
client_.send_query(ton::lite_api::liteServer_getLibrariesWithProof(ton::create_tl_lite_block_id(blkid), 1, std::move(not_cached_hashes)),
|
||||
promise.wrap([self=this, blkid, result_entries = std::move(result_entries), not_cached_hashes]
|
||||
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResultWithProof>> r_libraries) mutable
|
||||
-> td::Result<tonlib_api::object_ptr<tonlib_api::smc_libraryResult>> {
|
||||
if (r_libraries.is_error()) {
|
||||
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
|
||||
return r_libraries.move_as_error();
|
||||
}
|
||||
|
||||
auto libraries = r_libraries.move_as_ok();
|
||||
auto state = block::check_extract_state_proof(blkid, libraries->state_proof_.as_slice(),
|
||||
libraries->data_proof_.as_slice());
|
||||
if (state.is_error()) {
|
||||
LOG(WARNING) << "cannot check state proof: " << state.move_as_error().to_string();
|
||||
return state.move_as_error();
|
||||
}
|
||||
auto state_root = state.move_as_ok();
|
||||
|
||||
try {
|
||||
block::gen::ShardStateUnsplit::Record state_record;
|
||||
if (!tlb::unpack_cell(state_root, state_record)) {
|
||||
return td::Status::Error("cannot unpack shardchain state");
|
||||
}
|
||||
auto libraries_dict = vm::Dictionary(state_record.r1.libraries->prefetch_ref(), 256);
|
||||
|
||||
for (auto& hash : not_cached_hashes) {
|
||||
auto csr = libraries_dict.lookup(hash.bits(), 256);
|
||||
if (csr.is_null()) {
|
||||
LOG(WARNING) << "library " << hash.to_hex() << " not found in config";
|
||||
if (std::any_of(libraries->result_.begin(), libraries->result_.end(),
|
||||
[&hash](const auto& lib) { return lib->hash_.bits().equals(hash.cbits(), 256); })) {
|
||||
return TonlibError::Internal("library is included in response but it's not found in proof");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
block::gen::LibDescr::Record libdescr;
|
||||
if (!tlb::csr_unpack(csr, libdescr)) {
|
||||
return TonlibError::Internal("cannot unpack LibDescr record");
|
||||
}
|
||||
|
||||
auto lib_it = std::find_if(libraries->result_.begin(), libraries->result_.end(),
|
||||
[&hash](const auto& lib) { return lib->hash_.bits().equals(hash.cbits(), 256); });
|
||||
if (lib_it == libraries->result_.end()) {
|
||||
return TonlibError::Internal("library is found in proof but not in response");
|
||||
}
|
||||
auto& lib = *lib_it;
|
||||
auto contents = vm::std_boc_deserialize(lib->data_);
|
||||
if (!contents.is_ok() || contents.ok().is_null()) {
|
||||
return TonlibError::Internal(PSLICE() << "cannot deserialize library cell " << lib->hash_.to_hex());
|
||||
}
|
||||
|
||||
if (!contents.ok()->get_hash().bits().equals(hash.cbits(), 256)) {
|
||||
return TonlibError::Internal(PSLICE() << "library hash mismatch data " << contents.ok()->get_hash().to_hex() << " != requested " << hash.to_hex());
|
||||
}
|
||||
|
||||
if (contents.ok()->get_hash() != libdescr.lib->get_hash()) {
|
||||
return TonlibError::Internal(PSLICE() << "library hash mismatch data " << lib->hash_.to_hex() << " != proof " << libdescr.lib->get_hash().to_hex());
|
||||
}
|
||||
|
||||
result_entries.push_back(tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lib->hash_, lib->data_.as_slice().str()));
|
||||
self->libraries.set_ref(lib->hash_, contents.move_as_ok());
|
||||
LOG(DEBUG) << "registered library " << lib->hash_.to_hex();
|
||||
}
|
||||
self->store_libs_to_disk();
|
||||
return tonlib_api::make_object<tonlib_api::smc_libraryResult>(std::move(result_entries));
|
||||
}));
|
||||
return td::Status::OK();
|
||||
} catch (vm::VmError& err) {
|
||||
return TonlibError::Internal(PSLICE() << "error while checking getLibrariesWithProof proof: " << err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return TonlibError::Internal(PSLICE() << "virtualization error while checking getLibrariesWithProof proof: " << err.get_msg());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::smc_getLibrariesExt& request,
|
||||
|
@ -5413,53 +5478,247 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getMasterchainInfo&
|
|||
td::Status TonlibClient::do_request(const tonlib_api::blocks_getShards& request,
|
||||
td::Promise<object_ptr<tonlib_api::blocks_shards>>&& promise) {
|
||||
TRY_RESULT(block, to_lite_api(*request.id_))
|
||||
TRY_RESULT(req_blk_id, to_block_id(*request.id_));
|
||||
client_.send_query(ton::lite_api::liteServer_getAllShardsInfo(std::move(block)),
|
||||
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_allShardsInfo>&& all_shards_info)
|
||||
promise.wrap([req_blk_id](lite_api_ptr<ton::lite_api::liteServer_allShardsInfo>&& all_shards_info)
|
||||
-> td::Result<object_ptr<tonlib_api::blocks_shards>> {
|
||||
td::BufferSlice proof = std::move((*all_shards_info).proof_);
|
||||
td::BufferSlice data = std::move((*all_shards_info).data_);
|
||||
if (data.empty()) {
|
||||
return td::Status::Error("shard configuration is empty");
|
||||
} else {
|
||||
auto R = vm::std_boc_deserialize(data.clone());
|
||||
if (R.is_error()) {
|
||||
return R.move_as_error_prefix("cannot deserialize shard configuration: ");
|
||||
}
|
||||
auto root = R.move_as_ok();
|
||||
block::ShardConfig sh_conf;
|
||||
if (!sh_conf.unpack(vm::load_cell_slice_ref(root))) {
|
||||
return td::Status::Error("cannot extract shard block list from shard configuration");
|
||||
} else {
|
||||
auto ids = sh_conf.get_shard_hash_ids(true);
|
||||
tonlib_api::blocks_shards shards;
|
||||
for (auto id : ids) {
|
||||
auto ref = sh_conf.get_shard_hash(ton::ShardIdFull(id));
|
||||
if (ref.not_null()) {
|
||||
shards.shards_.push_back(to_tonlib_api(ref->top_block_id()));
|
||||
}
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::blocks_shards>(std::move(shards));
|
||||
}
|
||||
}
|
||||
auto blk_id = ton::create_block_id(all_shards_info->id_);
|
||||
if (blk_id != req_blk_id) {
|
||||
return td::Status::Error("Liteserver responded with wrong block");
|
||||
}
|
||||
td::BufferSlice proof = std::move((*all_shards_info).proof_);
|
||||
td::BufferSlice data = std::move((*all_shards_info).data_);
|
||||
if (data.empty() || proof.empty()) {
|
||||
return td::Status::Error("Shard configuration or proof is empty");
|
||||
}
|
||||
auto proof_cell = vm::std_boc_deserialize(std::move(proof));
|
||||
if (proof_cell.is_error()) {
|
||||
return proof_cell.move_as_error_prefix("Couldn't deserialize shards proof: ");
|
||||
}
|
||||
auto data_cell = vm::std_boc_deserialize(std::move(data));
|
||||
if (data_cell.is_error()) {
|
||||
return data_cell.move_as_error_prefix("Couldn't deserialize shards data: ");
|
||||
}
|
||||
try {
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_cell.move_as_ok(), 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error("Virt root is null");
|
||||
}
|
||||
if (ton::RootHash{virt_root->get_hash().bits()} != blk_id.root_hash) {
|
||||
return td::Status::Error("Block shards merkle proof has incorrect root hash");
|
||||
}
|
||||
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!tlb::unpack_cell(virt_root, blk) || !tlb::unpack_cell(blk.extra, extra) || !extra.custom->have_refs() ||
|
||||
!tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra)) {
|
||||
return td::Status::Error("cannot unpack block extra of block " + blk_id.to_str());
|
||||
}
|
||||
auto data_csr = vm::load_cell_slice_ref(data_cell.move_as_ok());
|
||||
if (data_csr->prefetch_ref()->get_hash() != mc_extra.shard_hashes->prefetch_ref()->get_hash()) {
|
||||
return td::Status::Error("Block shards data and proof hashes don't match");
|
||||
}
|
||||
|
||||
block::ShardConfig sh_conf;
|
||||
if (!sh_conf.unpack(mc_extra.shard_hashes)) {
|
||||
return td::Status::Error("cannot extract shard block list from shard configuration");
|
||||
}
|
||||
auto ids = sh_conf.get_shard_hash_ids(true);
|
||||
tonlib_api::blocks_shards shards;
|
||||
for (auto& id : ids) {
|
||||
auto ref = sh_conf.get_shard_hash(ton::ShardIdFull(id));
|
||||
if (ref.not_null()) {
|
||||
shards.shards_.push_back(to_tonlib_api(ref->top_block_id()));
|
||||
}
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::blocks_shards>(std::move(shards));
|
||||
} catch (vm::VmError& err) {
|
||||
return err.as_status("Couldn't verify proof: ");
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return err.as_status("Couldn't verify proof: ");
|
||||
} catch (...) {
|
||||
return td::Status::Error("Unknown exception raised while verifying proof");
|
||||
}
|
||||
}));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>& result, int mode, ton::BlockId blkid, ton::BlockIdExt client_mc_blkid, td::uint64 lt, td::uint32 utime);
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& request,
|
||||
td::Promise<object_ptr<tonlib_api::ton_blockIdExt>>&& promise) {
|
||||
client_.send_query(ton::lite_api::liteServer_lookupBlock(
|
||||
request.mode_,
|
||||
ton::lite_api::make_object<ton::lite_api::tonNode_blockId>((*request.id_).workchain_, (*request.id_).shard_, (*request.id_).seqno_),
|
||||
(td::uint64)(request.lt_),
|
||||
(td::uint32)(request.utime_)),
|
||||
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& header) {
|
||||
const auto& id = header->id_;
|
||||
return to_tonlib_api(*id);
|
||||
//tonlib_api::make_object<tonlib_api::ton_blockIdExt>(
|
||||
// ton::tonlib_api::ton_blockIdExt(id->workchain_, id->)
|
||||
//);
|
||||
}));
|
||||
auto lite_block = ton::lite_api::make_object<ton::lite_api::tonNode_blockId>((*request.id_).workchain_, (*request.id_).shard_, (*request.id_).seqno_);
|
||||
auto blkid = ton::BlockId(request.id_->workchain_, request.id_->shard_, request.id_->seqno_);
|
||||
client_.with_last_block(
|
||||
[self = this, blkid, lite_block = std::move(lite_block), mode = request.mode_, lt = (td::uint64)request.lt_,
|
||||
utime = (td::uint32)request.utime_, promise = std::move(promise)](td::Result<LastBlockState> r_last_block) mutable {
|
||||
self->client_.send_query(ton::lite_api::liteServer_lookupBlockWithProof(mode, std::move(lite_block), ton::create_tl_lite_block_id(r_last_block.ok().last_block_id), lt, utime),
|
||||
promise.wrap([blkid, mode, utime, lt, last_block = r_last_block.ok().last_block_id](lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>&& result)
|
||||
-> td::Result<object_ptr<tonlib_api::ton_blockIdExt>> {
|
||||
TRY_STATUS(check_lookup_block_proof(result, mode, blkid, last_block, lt, utime));
|
||||
return to_tonlib_api(*result->id_);
|
||||
})
|
||||
);
|
||||
});
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>& result, int mode, ton::BlockId blkid, ton::BlockIdExt client_mc_blkid, td::uint64 lt, td::uint32 utime) {
|
||||
try {
|
||||
ton::BlockIdExt cur_id = ton::create_block_id(result->mc_block_id_);
|
||||
try {
|
||||
for (auto& link : result->shard_links_) {
|
||||
ton::BlockIdExt prev_id = create_block_id(link->id_);
|
||||
td::BufferSlice proof = std::move(link->proof_);
|
||||
auto R = vm::std_boc_deserialize(proof);
|
||||
if (R.is_error()) {
|
||||
return TonlibError::InvalidBagOfCells("proof");
|
||||
}
|
||||
auto block_root = vm::MerkleProof::virtualize(R.move_as_ok(), 1);
|
||||
if (cur_id.root_hash != block_root->get_hash().bits()) {
|
||||
return td::Status::Error("invalid block hash in proof");
|
||||
}
|
||||
if (cur_id.is_masterchain()) {
|
||||
if (client_mc_blkid != cur_id) {
|
||||
auto state = block::check_extract_state_proof(client_mc_blkid, result->client_mc_state_proof_.as_slice(),
|
||||
result->mc_block_proof_.as_slice());
|
||||
if (state.is_error()) {
|
||||
LOG(WARNING) << "cannot check state proof: " << state.move_as_error().to_string();
|
||||
return state.move_as_error();
|
||||
}
|
||||
auto state_root = state.move_as_ok();
|
||||
auto prev_blocks_dict = block::get_prev_blocks_dict(state_root);
|
||||
if (!prev_blocks_dict) {
|
||||
return td::Status::Error("cannot extract prev blocks dict from state");
|
||||
}
|
||||
|
||||
if (!block::check_old_mc_block_id(*prev_blocks_dict, cur_id)) {
|
||||
return td::Status::Error("couldn't check old mc block id");
|
||||
}
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!tlb::unpack_cell(block_root, blk) || !tlb::unpack_cell(blk.extra, extra) || !extra.custom->have_refs() ||
|
||||
!tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra)) {
|
||||
return td::Status::Error("cannot unpack block header");
|
||||
}
|
||||
block::ShardConfig shards(mc_extra.shard_hashes->prefetch_ref());
|
||||
td::Ref<block::McShardHash> shard_hash = shards.get_shard_hash(prev_id.shard_full(), true);
|
||||
if (shard_hash.is_null() || shard_hash->top_block_id() != prev_id) {
|
||||
return td::Status::Error("invalid proof chain: prev block is not in mc shard list");
|
||||
}
|
||||
} else {
|
||||
std::vector<ton::BlockIdExt> prev;
|
||||
ton::BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
td::Status S = block::unpack_block_prev_blk_try(block_root, cur_id, prev, mc_blkid, after_split);
|
||||
if (S.is_error()) {
|
||||
return S;
|
||||
}
|
||||
CHECK(prev.size() == 1 || prev.size() == 2);
|
||||
bool found = prev_id == prev[0] || (prev.size() == 2 && prev_id == prev[1]);
|
||||
if (!found) {
|
||||
return td::Status::Error("invalid proof chain: prev block is not in prev blocks list");
|
||||
}
|
||||
}
|
||||
cur_id = prev_id;
|
||||
}
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return err.as_status();
|
||||
}
|
||||
if (cur_id.id.workchain != blkid.workchain || !ton::shard_contains(cur_id.id.shard, blkid.shard)) {
|
||||
return td::Status::Error("response block has incorrect workchain/shard");
|
||||
}
|
||||
|
||||
auto header_r = vm::std_boc_deserialize(std::move(result->header_));
|
||||
if (header_r.is_error()) {
|
||||
return TonlibError::InvalidBagOfCells("header");
|
||||
}
|
||||
auto header_root = vm::MerkleProof::virtualize(header_r.move_as_ok(), 1);
|
||||
if (header_root.is_null()) {
|
||||
return td::Status::Error("header_root is null");
|
||||
}
|
||||
if (cur_id.root_hash != header_root->get_hash().bits()) {
|
||||
return td::Status::Error("invalid header hash in proof");
|
||||
}
|
||||
|
||||
std::vector<ton::BlockIdExt> prev;
|
||||
ton::BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
auto R = block::unpack_block_prev_blk_try(header_root, cur_id, prev, mc_blkid, after_split);
|
||||
if (R.is_error()) {
|
||||
return R;
|
||||
}
|
||||
if (cur_id != ton::create_block_id(result->id_)) {
|
||||
return td::Status::Error("response blkid doesn't match header");
|
||||
}
|
||||
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(header_root, blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
return td::Status::Error("block header unpack failed");
|
||||
}
|
||||
|
||||
if (mode & 1) {
|
||||
if (cur_id.seqno() != blkid.seqno) {
|
||||
return td::Status::Error("invalid seqno in proof");
|
||||
}
|
||||
} else if (mode & 6) {
|
||||
auto prev_header_r = vm::std_boc_deserialize(std::move(result->prev_header_));
|
||||
if (prev_header_r.is_error()) {
|
||||
return TonlibError::InvalidBagOfCells("prev_headers");
|
||||
}
|
||||
auto prev_header = prev_header_r.move_as_ok();
|
||||
auto prev_root = vm::MerkleProof::virtualize(prev_header, 1);
|
||||
if (prev_root.is_null()) {
|
||||
return td::Status::Error("prev_root is null");
|
||||
}
|
||||
|
||||
bool prev_valid = false;
|
||||
int prev_idx = -1;
|
||||
for (size_t i = 0; i < prev.size(); i++) {
|
||||
if (prev[i].root_hash == prev_root->get_hash().bits()) {
|
||||
prev_valid = true;
|
||||
prev_idx = i;
|
||||
}
|
||||
}
|
||||
if (!prev_valid) {
|
||||
return td::Status::Error("invalid prev header hash in proof");
|
||||
}
|
||||
if (!ton::shard_contains(prev[prev_idx].id.shard, blkid.shard)) {
|
||||
return td::Status::Error("invalid prev header shard in proof");
|
||||
}
|
||||
|
||||
block::gen::Block::Record prev_blk;
|
||||
block::gen::BlockInfo::Record prev_info;
|
||||
if (!(tlb::unpack_cell(prev_root, prev_blk) && tlb::unpack_cell(prev_blk.info, prev_info))) {
|
||||
return td::Status::Error("prev header unpack failed");
|
||||
}
|
||||
|
||||
if (mode & 2) {
|
||||
if (prev_info.end_lt > lt) {
|
||||
return td::Status::Error("prev header end_lt > lt");
|
||||
}
|
||||
if (info.end_lt < lt) {
|
||||
return td::Status::Error("header end_lt < lt");
|
||||
}
|
||||
} else if (mode & 4) {
|
||||
if (prev_info.gen_utime > utime) {
|
||||
return td::Status::Error("prev header end_lt > lt");
|
||||
}
|
||||
if (info.gen_utime < utime) {
|
||||
return td::Status::Error("header end_lt < lt");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return td::Status::Error(PSLICE() << "error while checking lookupBlock proof: " << err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return td::Status::Error(PSLICE() << "virtualization error while checking lookupBlock proof: " << err.get_msg());
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -5469,13 +5728,95 @@ auto to_tonlib_api(const ton::lite_api::liteServer_transactionId& txid)
|
|||
txid.mode_, txid.account_.as_slice().str(), txid.lt_, txid.hash_.as_slice().str());
|
||||
}
|
||||
|
||||
td::Status check_block_transactions_proof(lite_api_ptr<ton::lite_api::liteServer_blockTransactions>& bTxes, int32_t mode,
|
||||
ton::LogicalTime start_lt, td::Bits256 start_addr, td::Bits256 root_hash, int req_count) {
|
||||
if (mode & ton::lite_api::liteServer_listBlockTransactions::WANT_PROOF_MASK == 0) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
constexpr int max_answer_transactions = 256;
|
||||
bool reverse_mode = mode & ton::lite_api::liteServer_listBlockTransactions::REVERSE_ORDER_MASK;
|
||||
|
||||
try {
|
||||
TRY_RESULT(proof_cell, vm::std_boc_deserialize(std::move(bTxes->proof_)));
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_cell, 1);
|
||||
|
||||
if (root_hash != virt_root->get_hash().bits()) {
|
||||
return td::Status::Error("Invalid block proof root hash");
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(std::move(blk.extra), extra))) {
|
||||
return td::Status::Error("Error unpacking proof cell");
|
||||
}
|
||||
vm::AugmentedDictionary acc_dict{vm::load_cell_slice_ref(extra.account_blocks), 256,
|
||||
block::tlb::aug_ShardAccountBlocks};
|
||||
|
||||
bool eof = false;
|
||||
ton::LogicalTime reverse = reverse_mode ? ~0ULL : 0;
|
||||
ton::LogicalTime trans_lt = static_cast<ton::LogicalTime>(start_lt);
|
||||
td::Bits256 cur_addr = start_addr;
|
||||
bool allow_same = true;
|
||||
int count = 0;
|
||||
while (!eof && count < req_count && count < max_answer_transactions) {
|
||||
auto value = acc_dict.extract_value(
|
||||
acc_dict.vm::DictionaryFixed::lookup_nearest_key(cur_addr.bits(), 256, !reverse, allow_same));
|
||||
if (value.is_null()) {
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
allow_same = false;
|
||||
if (cur_addr != start_addr) {
|
||||
trans_lt = reverse;
|
||||
}
|
||||
|
||||
block::gen::AccountBlock::Record acc_blk;
|
||||
if (!tlb::csr_unpack(std::move(value), acc_blk) || acc_blk.account_addr != cur_addr) {
|
||||
return td::Status::Error("Error unpacking proof account block");
|
||||
}
|
||||
vm::AugmentedDictionary trans_dict{vm::DictNonEmpty(), std::move(acc_blk.transactions), 64,
|
||||
block::tlb::aug_AccountTransactions};
|
||||
td::BitArray<64> cur_trans{(long long)trans_lt};
|
||||
while (count < req_count && count < max_answer_transactions) {
|
||||
auto tvalue = trans_dict.extract_value_ref(
|
||||
trans_dict.vm::DictionaryFixed::lookup_nearest_key(cur_trans.bits(), 64, !reverse));
|
||||
if (tvalue.is_null()) {
|
||||
trans_lt = reverse;
|
||||
break;
|
||||
}
|
||||
if (static_cast<size_t>(count) < bTxes->ids_.size()) {
|
||||
if (mode & 4 && !tvalue->get_hash().bits().equals(bTxes->ids_[count]->hash_.bits(), 256)) {
|
||||
return td::Status::Error("Couldn't verify proof (hash)");
|
||||
}
|
||||
if (mode & 2 && cur_trans != td::BitArray<64>(bTxes->ids_[count]->lt_)) {
|
||||
return td::Status::Error("Couldn't verify proof (lt)");
|
||||
}
|
||||
if (mode & 1 && cur_addr != bTxes->ids_[count]->account_) {
|
||||
return td::Status::Error("Couldn't verify proof (account)");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (static_cast<size_t>(count) != bTxes->ids_.size()) {
|
||||
return td::Status::Error(PSLICE() << "Txs count mismatch in proof (" << count << ") and response (" << bTxes->ids_.size() << ")");
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return err.as_status("Couldn't verify proof: ");
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return err.as_status("Couldn't verify proof: ");
|
||||
} catch (...) {
|
||||
return td::Status::Error("Unknown exception raised while verifying proof");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& request,
|
||||
td::Promise<object_ptr<tonlib_api::blocks_transactions>>&& promise) {
|
||||
TRY_RESULT(block, to_lite_api(*request.id_))
|
||||
auto root_hash = block->root_hash_;
|
||||
bool check_proof = request.mode_ & 32;
|
||||
bool reverse_mode = request.mode_ & 64;
|
||||
bool has_starting_tx = request.mode_ & 128;
|
||||
bool check_proof = request.mode_ & ton::lite_api::liteServer_listBlockTransactions::WANT_PROOF_MASK;
|
||||
bool reverse_mode = request.mode_ & ton::lite_api::liteServer_listBlockTransactions::REVERSE_ORDER_MASK;
|
||||
bool has_starting_tx = request.mode_ & ton::lite_api::liteServer_listBlockTransactions::AFTER_MASK;
|
||||
|
||||
td::Bits256 start_addr;
|
||||
ton::LogicalTime start_lt;
|
||||
|
@ -5502,80 +5843,7 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& re
|
|||
check_proof),
|
||||
promise.wrap([check_proof, reverse_mode, root_hash, req_count = request.count_, start_addr, start_lt, mode = request.mode_]
|
||||
(lite_api_ptr<ton::lite_api::liteServer_blockTransactions>&& bTxes) -> td::Result<object_ptr<tonlib_api::blocks_transactions>> {
|
||||
if (check_proof) {
|
||||
try {
|
||||
constexpr int max_answer_transactions = 256;
|
||||
TRY_RESULT(proof_cell, vm::std_boc_deserialize(std::move(bTxes->proof_)));
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_cell, 1);
|
||||
|
||||
if (root_hash != virt_root->get_hash().bits()) {
|
||||
return td::Status::Error("Invalid block proof root hash");
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(std::move(blk.extra), extra))) {
|
||||
return td::Status::Error("Error unpacking proof cell");
|
||||
}
|
||||
vm::AugmentedDictionary acc_dict{vm::load_cell_slice_ref(extra.account_blocks), 256,
|
||||
block::tlb::aug_ShardAccountBlocks};
|
||||
|
||||
bool eof = false;
|
||||
ton::LogicalTime reverse = reverse_mode ? ~0ULL : 0;
|
||||
ton::LogicalTime trans_lt = static_cast<ton::LogicalTime>(start_lt);
|
||||
td::Bits256 cur_addr = start_addr;
|
||||
bool allow_same = true;
|
||||
int count = 0;
|
||||
while (!eof && count < req_count && count < max_answer_transactions) {
|
||||
auto value = acc_dict.extract_value(
|
||||
acc_dict.vm::DictionaryFixed::lookup_nearest_key(cur_addr.bits(), 256, !reverse, allow_same));
|
||||
if (value.is_null()) {
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
allow_same = false;
|
||||
if (cur_addr != start_addr) {
|
||||
trans_lt = reverse;
|
||||
}
|
||||
|
||||
block::gen::AccountBlock::Record acc_blk;
|
||||
if (!tlb::csr_unpack(std::move(value), acc_blk) || acc_blk.account_addr != cur_addr) {
|
||||
return td::Status::Error("Error unpacking proof account block");
|
||||
}
|
||||
vm::AugmentedDictionary trans_dict{vm::DictNonEmpty(), std::move(acc_blk.transactions), 64,
|
||||
block::tlb::aug_AccountTransactions};
|
||||
td::BitArray<64> cur_trans{(long long)trans_lt};
|
||||
while (count < req_count && count < max_answer_transactions) {
|
||||
auto tvalue = trans_dict.extract_value_ref(
|
||||
trans_dict.vm::DictionaryFixed::lookup_nearest_key(cur_trans.bits(), 64, !reverse));
|
||||
if (tvalue.is_null()) {
|
||||
trans_lt = reverse;
|
||||
break;
|
||||
}
|
||||
if (static_cast<size_t>(count) < bTxes->ids_.size()) {
|
||||
if (mode & 4 && !tvalue->get_hash().bits().equals(bTxes->ids_[count]->hash_.bits(), 256)) {
|
||||
return td::Status::Error("Couldn't verify proof (hash)");
|
||||
}
|
||||
if (mode & 2 && cur_trans != td::BitArray<64>(bTxes->ids_[count]->lt_)) {
|
||||
return td::Status::Error("Couldn't verify proof (lt)");
|
||||
}
|
||||
if (mode & 1 && cur_addr != bTxes->ids_[count]->account_) {
|
||||
return td::Status::Error("Couldn't verify proof (account)");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (static_cast<size_t>(count) != bTxes->ids_.size()) {
|
||||
return td::Status::Error(PSLICE() << "Txs count mismatch in proof (" << count << ") and response (" << bTxes->ids_.size() << ")");
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return err.as_status("Couldn't verify proof: ");
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return err.as_status("Couldn't verify proof: ");
|
||||
} catch (...) {
|
||||
return td::Status::Error("Unknown exception raised while verifying proof");
|
||||
}
|
||||
}
|
||||
TRY_STATUS(check_block_transactions_proof(bTxes, mode, start_lt, start_addr, root_hash, req_count));
|
||||
|
||||
tonlib_api::blocks_transactions r;
|
||||
r.id_ = to_tonlib_api(*bTxes->id_);
|
||||
|
@ -5592,9 +5860,9 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& re
|
|||
td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactionsExt& request,
|
||||
td::Promise<object_ptr<tonlib_api::blocks_transactionsExt>>&& promise) {
|
||||
TRY_RESULT(block, to_lite_api(*request.id_))
|
||||
bool check_proof = request.mode_ & 32;
|
||||
bool reverse_mode = request.mode_ & 64;
|
||||
bool has_starting_tx = request.mode_ & 128;
|
||||
bool check_proof = request.mode_ & ton::lite_api::liteServer_listBlockTransactionsExt::WANT_PROOF_MASK;
|
||||
bool reverse_mode = request.mode_ & ton::lite_api::liteServer_listBlockTransactionsExt::REVERSE_ORDER_MASK;
|
||||
bool has_starting_tx = request.mode_ & ton::lite_api::liteServer_listBlockTransactionsExt::AFTER_MASK;
|
||||
|
||||
td::Bits256 start_addr;
|
||||
ton::LogicalTime start_lt;
|
||||
|
@ -5655,77 +5923,78 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactionsExt&
|
|||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::blocks_getBlockHeader& request,
|
||||
td::Promise<object_ptr<tonlib_api::blocks_header>>&& promise) {
|
||||
TRY_RESULT(block, to_lite_api(*request.id_))
|
||||
TRY_RESULT(lite_block, to_lite_api(*request.id_))
|
||||
TRY_RESULT(req_blk_id, to_block_id(*request.id_));
|
||||
client_.send_query(ton::lite_api::liteServer_getBlockHeader(
|
||||
std::move(block),
|
||||
std::move(lite_block),
|
||||
0xffff),
|
||||
promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& hdr) {
|
||||
promise.wrap([req_blk_id](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& hdr) -> td::Result<tonlib_api::object_ptr<tonlib_api::blocks_header>> {
|
||||
auto blk_id = ton::create_block_id(hdr->id_);
|
||||
auto R = vm::std_boc_deserialize(std::move(hdr->header_proof_));
|
||||
tonlib_api::blocks_header header;
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "R.is_error() ";
|
||||
} else {
|
||||
auto root = R.move_as_ok();
|
||||
try {
|
||||
ton::RootHash vhash{root->get_hash().bits()};
|
||||
auto virt_root = vm::MerkleProof::virtualize(root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
LOG(WARNING) << "virt root is null";
|
||||
} else {
|
||||
std::vector<ton::BlockIdExt> prev;
|
||||
ton::BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
auto res = block::unpack_block_prev_blk_ext(virt_root, blk_id, prev, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
LOG(WARNING) << "res.is_error() ";
|
||||
} else {
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
LOG(WARNING) << "unpack failed";
|
||||
} else {
|
||||
header.id_ = to_tonlib_api(blk_id);
|
||||
header.global_id_ = blk.global_id;
|
||||
header.version_ = info.version;
|
||||
header.flags_ = info.flags;
|
||||
header.after_merge_ = info.after_merge;
|
||||
header.after_split_ = info.after_split;
|
||||
header.before_split_ = info.before_split;
|
||||
header.want_merge_ = info.want_merge;
|
||||
header.want_split_ = info.want_split;
|
||||
header.validator_list_hash_short_ = info.gen_validator_list_hash_short;
|
||||
header.catchain_seqno_ = info.gen_catchain_seqno;
|
||||
header.min_ref_mc_seqno_ = info.min_ref_mc_seqno;
|
||||
header.start_lt_ = info.start_lt;
|
||||
header.end_lt_ = info.end_lt;
|
||||
header.gen_utime_ = info.gen_utime;
|
||||
header.is_key_block_ = info.key_block;
|
||||
header.vert_seqno_ = info.vert_seq_no;
|
||||
if(!info.not_master) {
|
||||
header.prev_key_block_seqno_ = info.prev_key_block_seqno;
|
||||
}
|
||||
for (auto id : prev) {
|
||||
header.prev_blocks_.push_back(to_tonlib_api(id));
|
||||
}
|
||||
//if(info.before_split) {
|
||||
//} else {
|
||||
//}
|
||||
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
auto E = err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
|
||||
LOG(ERROR) << std::move(E);
|
||||
} catch (vm::VmVirtError& err) {
|
||||
auto E = err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
|
||||
LOG(ERROR) << std::move(E);
|
||||
} catch (...) {
|
||||
LOG(WARNING) << "exception catched ";
|
||||
}
|
||||
if (blk_id != req_blk_id) {
|
||||
return td::Status::Error("Liteserver responded with wrong block");
|
||||
}
|
||||
auto R = vm::std_boc_deserialize(std::move(hdr->header_proof_));
|
||||
if (R.is_error()) {
|
||||
return R.move_as_error_prefix("Couldn't deserialize header proof: ");
|
||||
} else {
|
||||
auto root = R.move_as_ok();
|
||||
try {
|
||||
auto virt_root = vm::MerkleProof::virtualize(root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error("Virt root is null");
|
||||
} else {
|
||||
if (ton::RootHash{virt_root->get_hash().bits()} != blk_id.root_hash) {
|
||||
return td::Status::Error("Block header merkle proof has incorrect root hash");
|
||||
}
|
||||
std::vector<ton::BlockIdExt> prev;
|
||||
ton::BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
auto res =
|
||||
block::unpack_block_prev_blk_ext(virt_root, blk_id, prev, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
return td::Status::Error("Unpack failed");
|
||||
} else {
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
return td::Status::Error("Unpack failed");
|
||||
} else {
|
||||
tonlib_api::blocks_header header;
|
||||
header.id_ = to_tonlib_api(blk_id);
|
||||
header.global_id_ = blk.global_id;
|
||||
header.version_ = info.version;
|
||||
header.flags_ = info.flags;
|
||||
header.after_merge_ = info.after_merge;
|
||||
header.after_split_ = info.after_split;
|
||||
header.before_split_ = info.before_split;
|
||||
header.want_merge_ = info.want_merge;
|
||||
header.want_split_ = info.want_split;
|
||||
header.validator_list_hash_short_ = info.gen_validator_list_hash_short;
|
||||
header.catchain_seqno_ = info.gen_catchain_seqno;
|
||||
header.min_ref_mc_seqno_ = info.min_ref_mc_seqno;
|
||||
header.start_lt_ = info.start_lt;
|
||||
header.end_lt_ = info.end_lt;
|
||||
header.gen_utime_ = info.gen_utime;
|
||||
header.is_key_block_ = info.key_block;
|
||||
header.vert_seqno_ = info.vert_seq_no;
|
||||
if (!info.not_master) {
|
||||
header.prev_key_block_seqno_ = info.prev_key_block_seqno;
|
||||
}
|
||||
for (auto& id : prev) {
|
||||
header.prev_blocks_.push_back(to_tonlib_api(id));
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return err.as_status(PSLICE() << "error processing header for " << blk_id.to_str() << " :");
|
||||
} catch (...) {
|
||||
return td::Status::Error("Unhandled exception catched while processing header");
|
||||
}
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::blocks_header>(std::move(header));
|
||||
}));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -5764,14 +6033,14 @@ void TonlibClient::load_libs_from_disk() {
|
|||
}
|
||||
libraries = vm::Dictionary(vm::load_cell_slice(vm::CellBuilder().append_cellslice(vm::load_cell_slice(
|
||||
r_dict.move_as_ok())).finalize()), 256);
|
||||
// int n = 0; for (auto&& lr : libraries) n++;
|
||||
|
||||
LOG(DEBUG) << "loaded libraries from disk cache";
|
||||
}
|
||||
|
||||
void TonlibClient::store_libs_to_disk() { // NB: Dictionary.get_root_cell does not compute_root, and it is protected
|
||||
kv_->set("tonlib.libcache", vm::std_boc_serialize(vm::CellBuilder().append_cellslice(libraries.get_root())
|
||||
.finalize()).move_as_ok().as_slice());
|
||||
// int n = 0; for (auto&& lr : libraries) n++;
|
||||
|
||||
LOG(DEBUG) << "stored libraries to disk cache";
|
||||
}
|
||||
|
||||
|
|
|
@ -330,6 +330,7 @@ class TonlibClient : public td::actor::Actor {
|
|||
|
||||
td::Status do_request(const tonlib_api::smc_getLibraries& request,
|
||||
td::Promise<object_ptr<tonlib_api::smc_libraryResult>>&& promise);
|
||||
void get_libraries(ton::BlockIdExt blkid, std::vector<td::Bits256> library_list_, td::Promise<object_ptr<tonlib_api::smc_libraryResult>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::smc_getLibrariesExt& request,
|
||||
td::Promise<object_ptr<tonlib_api::smc_libraryResultExt>>&& promise);
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "tonlib/Wallet.h"
|
||||
#include "tonlib/CellString.h"
|
||||
#include "tonlib/GenericAccount.h"
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
auto code = get_init_code();
|
||||
auto data = get_init_data(public_key);
|
||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept {
|
||||
td::uint32 seqno = 0;
|
||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max();
|
||||
auto signature =
|
||||
private_key
|
||||
.sign(vm::CellBuilder().store_long(seqno, 32).store_long(valid_until, 32).finalize()->get_hash().as_slice())
|
||||
.move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).store_long(seqno, 32).store_long(valid_until, 32).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept {
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
vm::CellBuilder cb;
|
||||
cb.append_cellslice(binary_bitstring_to_cellslice("b{01}").move_as_ok())
|
||||
.store_long(dest_address.bounceable, 1)
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
||||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
td::int32 send_mode = 3;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
send_mode += 128;
|
||||
}
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
auto message_outer = vm::CellBuilder()
|
||||
.store_long(seqno, 32)
|
||||
.store_long(valid_until, 32)
|
||||
.store_long(send_mode, 8)
|
||||
.store_ref(message_inner)
|
||||
.finalize();
|
||||
std::string seq_no(4, 0);
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_code() noexcept {
|
||||
static auto res = [] {
|
||||
auto serialized_code = td::base64_decode(
|
||||
"te6ccgEEAQEAAAAAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/"
|
||||
"0VExuvKhA/kBVBBC+RDyovgAApMg10qW0wfUAvsA6NGkyMsfy//J7VQ=")
|
||||
.move_as_ok();
|
||||
return vm::std_boc_deserialize(serialized_code).move_as_ok();
|
||||
}();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash Wallet::get_init_code_hash() noexcept {
|
||||
return get_init_code()->get_hash();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||
}
|
||||
} // namespace tonlib
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block.h"
|
||||
#include "CellString.h"
|
||||
|
||||
namespace tonlib {
|
||||
class Wallet {
|
||||
public:
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept;
|
||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept;
|
||||
|
||||
static td::Ref<vm::Cell> get_init_code() noexcept;
|
||||
static vm::CellHash get_init_code_hash() noexcept;
|
||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
};
|
||||
} // namespace tonlib
|
|
@ -233,6 +233,9 @@ void LiteQuery::perform() {
|
|||
[&](lite_api::liteServer_lookupBlock& q) {
|
||||
this->perform_lookupBlock(ton::create_block_id_simple(q.id_), q.mode_, q.lt_, q.utime_);
|
||||
},
|
||||
[&](lite_api::liteServer_lookupBlockWithProof& q) {
|
||||
this->perform_lookupBlockWithProof(ton::create_block_id_simple(q.id_), ton::create_block_id(q.mc_block_id_), q.mode_, q.lt_, q.utime_);
|
||||
},
|
||||
[&](lite_api::liteServer_listBlockTransactions& q) {
|
||||
this->perform_listBlockTransactions(ton::create_block_id(q.id_), q.mode_, q.count_,
|
||||
(q.mode_ & 128) ? q.after_->account_ : td::Bits256::zero(),
|
||||
|
@ -266,6 +269,9 @@ void LiteQuery::perform() {
|
|||
[&](lite_api::liteServer_getLibraries& q) {
|
||||
this->perform_getLibraries(q.library_list_);
|
||||
},
|
||||
[&](lite_api::liteServer_getLibrariesWithProof& q) {
|
||||
this->perform_getLibrariesWithProof(ton::create_block_id(q.id_), q.mode_, q.library_list_);
|
||||
},
|
||||
[&](lite_api::liteServer_getShardBlockProof& q) {
|
||||
this->perform_getShardBlockProof(create_block_id(q.id_));
|
||||
},
|
||||
|
@ -964,6 +970,100 @@ void LiteQuery::continue_getLibraries(Ref<ton::validator::MasterchainState> mc_s
|
|||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
void LiteQuery::perform_getLibrariesWithProof(BlockIdExt blkid, int mode, std::vector<td::Bits256> library_list) {
|
||||
LOG(INFO) << "started a getLibrariesWithProof(<list of " << library_list.size() << " parameters>) liteserver query";
|
||||
if (library_list.size() > 16) {
|
||||
LOG(INFO) << "too many libraries requested, returning only first 16";
|
||||
library_list.resize(16);
|
||||
}
|
||||
sort( library_list.begin(), library_list.end() );
|
||||
library_list.erase( unique( library_list.begin(), library_list.end() ), library_list.end() );
|
||||
|
||||
set_continuation([this, library_list, mode]() -> void { continue_getLibrariesWithProof(library_list, mode); });
|
||||
request_mc_block_data_state(blkid);
|
||||
}
|
||||
|
||||
void LiteQuery::continue_getLibrariesWithProof(std::vector<td::Bits256> library_list, int mode) {
|
||||
LOG(INFO) << "obtained masterchain block = " << base_blk_id_.to_str();
|
||||
CHECK(mc_state_.not_null());
|
||||
|
||||
Ref<vm::Cell> state_proof, data_proof;
|
||||
if (!make_mc_state_root_proof(state_proof)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vm::MerkleProofBuilder pb{mc_state_->root_cell()};
|
||||
block::gen::ShardStateUnsplit::Record state;
|
||||
if (!tlb::unpack_cell(pb.root(), state)) {
|
||||
fatal_error("cannot unpack header of shardchain state "s + base_blk_id_.to_str());
|
||||
}
|
||||
auto libraries_dict = vm::Dictionary(state.r1.libraries->prefetch_ref(), 256);
|
||||
|
||||
std::vector<ton::tl_object_ptr<ton::lite_api::liteServer_libraryEntry>> result;
|
||||
std::vector<td::Bits256> result_hashes;
|
||||
for (const auto& hash : library_list) {
|
||||
LOG(INFO) << "looking for library " << hash.to_hex();
|
||||
|
||||
auto csr = libraries_dict.lookup(hash.bits(), 256);
|
||||
if (csr.is_null() || csr->prefetch_ulong(2) != 0 || !csr->have_refs()) { // shared_lib_descr$00 lib:^Cell
|
||||
continue;
|
||||
}
|
||||
block::gen::LibDescr::Record libdescr;
|
||||
if (!tlb::csr_unpack(csr, libdescr)) {
|
||||
fatal_error("cannot unpack LibDescr record "s + hash.to_hex());
|
||||
return;
|
||||
}
|
||||
if (mode & 1) {
|
||||
// include first 16 publishers in the proof
|
||||
auto publishers_dict = vm::Dictionary{vm::DictNonEmpty(), libdescr.publishers, 256};
|
||||
auto iter = publishers_dict.begin();
|
||||
constexpr int max_publishers = 15; // set to 15 because publishers_dict.begin() counts as the first visit
|
||||
for (int i = 0; i < max_publishers && iter != publishers_dict.end(); ++i, ++iter) {}
|
||||
}
|
||||
|
||||
result_hashes.push_back(hash);
|
||||
}
|
||||
|
||||
auto data_proof_boc = pb.extract_proof_boc();
|
||||
if (data_proof_boc.is_error()) {
|
||||
fatal_error(data_proof_boc.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto state_proof_boc = vm::std_boc_serialize(std::move(state_proof));
|
||||
if (state_proof_boc.is_error()) {
|
||||
fatal_error(state_proof_boc.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& hash : result_hashes) {
|
||||
auto csr = libraries_dict.lookup(hash.bits(), 256);
|
||||
block::gen::LibDescr::Record libdescr;
|
||||
if (!tlb::csr_unpack(csr, libdescr)) {
|
||||
fatal_error("cannot unpack LibDescr record "s + hash.to_hex());
|
||||
return;
|
||||
}
|
||||
if (!libdescr.lib->get_hash().bits().equals(hash.bits(), 256)) {
|
||||
LOG(ERROR) << "public library hash mismatch: expected " << hash.to_hex() << " , found "
|
||||
<< libdescr.lib->get_hash().to_hex();
|
||||
continue;
|
||||
}
|
||||
td::BufferSlice libdata;
|
||||
if (!(mode & 2)) {
|
||||
auto data = vm::std_boc_serialize(libdescr.lib);
|
||||
if (data.is_error()) {
|
||||
LOG(WARNING) << "library serialization failed: " << data.move_as_error().to_string();
|
||||
continue;
|
||||
}
|
||||
libdata = data.move_as_ok();
|
||||
}
|
||||
result.push_back(ton::create_tl_object<ton::lite_api::liteServer_libraryEntry>(hash, std::move(libdata)));
|
||||
}
|
||||
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_libraryResultWithProof>(ton::create_tl_lite_block_id(base_blk_id_), mode, std::move(result),
|
||||
state_proof_boc.move_as_ok(), data_proof_boc.move_as_ok());
|
||||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
void LiteQuery::perform_getOneTransaction(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, LogicalTime lt) {
|
||||
LOG(INFO) << "started a getOneTransaction(" << blkid.to_str() << ", " << workchain << ", " << addr.to_hex() << ","
|
||||
<< lt << ") liteserver query";
|
||||
|
@ -1853,7 +1953,7 @@ void LiteQuery::continue_getConfigParams(int mode, std::vector<int> param_list)
|
|||
void LiteQuery::perform_getAllShardsInfo(BlockIdExt blkid) {
|
||||
LOG(INFO) << "started a getAllShardsInfo(" << blkid.to_str() << ") liteserver query";
|
||||
set_continuation([&]() -> void { continue_getAllShardsInfo(); });
|
||||
request_mc_block_data_state(blkid);
|
||||
request_mc_block_data(blkid);
|
||||
}
|
||||
|
||||
void LiteQuery::continue_getShardInfo(ShardIdFull shard, bool exact) {
|
||||
|
@ -1900,30 +2000,30 @@ void LiteQuery::continue_getShardInfo(ShardIdFull shard, bool exact) {
|
|||
|
||||
void LiteQuery::continue_getAllShardsInfo() {
|
||||
LOG(INFO) << "completing getAllShardsInfo() query";
|
||||
Ref<vm::Cell> proof1, proof2;
|
||||
if (!make_mc_state_root_proof(proof1)) {
|
||||
vm::MerkleProofBuilder mpb{mc_block_->root_cell()};
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!tlb::unpack_cell(mpb.root(), blk) || !tlb::unpack_cell(blk.extra, extra) || !extra.custom->have_refs() ||
|
||||
!tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra)) {
|
||||
fatal_error("cannot unpack header of block "s + mc_block_->block_id().to_str());
|
||||
return;
|
||||
}
|
||||
vm::MerkleProofBuilder mpb{mc_state_->root_cell()};
|
||||
auto shards_dict = block::ShardConfig::extract_shard_hashes_dict(mpb.root());
|
||||
if (!shards_dict) {
|
||||
fatal_error("cannot extract ShardHashes from last mc state");
|
||||
return;
|
||||
}
|
||||
if (!mpb.extract_proof_to(proof2)) {
|
||||
vm::Dictionary shards_dict(std::move(mc_extra.shard_hashes), 32);
|
||||
Ref<vm::Cell> proof;
|
||||
if (!mpb.extract_proof_to(proof)) {
|
||||
fatal_error("cannot construct Merkle proof for all shards dictionary");
|
||||
return;
|
||||
}
|
||||
shards_dict = block::ShardConfig::extract_shard_hashes_dict(mc_state_->root_cell());
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> cell;
|
||||
if (!(std::move(shards_dict)->append_dict_to_bool(cb) && cb.finalize_to(cell))) {
|
||||
fatal_error("cannot store ShardHashes from last mc state into a new cell");
|
||||
auto proof_boc = vm::std_boc_serialize(std::move(proof));
|
||||
if (proof_boc.is_error()) {
|
||||
fatal_error(proof_boc.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
|
||||
if (proof.is_error()) {
|
||||
fatal_error(proof.move_as_error());
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> cell;
|
||||
if (!(shards_dict.append_dict_to_bool(cb) && cb.finalize_to(cell))) {
|
||||
fatal_error("cannot store ShardHashes from last mc block into a new cell");
|
||||
return;
|
||||
}
|
||||
auto data = vm::std_boc_serialize(std::move(cell));
|
||||
|
@ -1933,10 +2033,307 @@ void LiteQuery::continue_getAllShardsInfo() {
|
|||
}
|
||||
LOG(INFO) << "getAllShardInfo() query completed";
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_allShardsInfo>(
|
||||
ton::create_tl_lite_block_id(base_blk_id_), proof.move_as_ok(), data.move_as_ok());
|
||||
ton::create_tl_lite_block_id(base_blk_id_), proof_boc.move_as_ok(), data.move_as_ok());
|
||||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
void LiteQuery::perform_lookupBlockWithProof(BlockId blkid, BlockIdExt mc_blkid, int mode, LogicalTime lt, UnixTime utime) {
|
||||
if (!((1 << (mode & 7)) & 0x16)) {
|
||||
fatal_error("exactly one of mode.0, mode.1 and mode.2 bits must be set");
|
||||
return;
|
||||
}
|
||||
if (!mc_blkid.is_masterchain_ext()) {
|
||||
fatal_error("masterchain block id must be specified");
|
||||
return;
|
||||
}
|
||||
if (!(mode & 1)) {
|
||||
blkid.seqno = 0;
|
||||
}
|
||||
if (!(mode & 2)) {
|
||||
lt = 0;
|
||||
}
|
||||
if (!(mode & 4)) {
|
||||
utime = 0;
|
||||
}
|
||||
mode_ = mode;
|
||||
base_blk_id_ = mc_blkid;
|
||||
LOG(INFO) << "started a lookupBlockWithProof(" << blkid.to_str() << ", " << mc_blkid.to_str() << ", " << mode << ", "
|
||||
<< lt << ", " << utime << ") liteserver query";
|
||||
|
||||
ton::AccountIdPrefixFull pfx{blkid.workchain, blkid.shard};
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[Self = actor_id(this), mc_blkid, manager = manager_, mode, pfx](td::Result<ConstBlockHandle> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto handle = res.move_as_ok();
|
||||
if (!handle->inited_masterchain_ref_block()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, td::Status::Error("block doesn't have masterchain ref"));
|
||||
return;
|
||||
}
|
||||
if (handle->masterchain_ref_block() > mc_blkid.seqno()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, td::Status::Error("specified mc block is older than block's masterchain ref"));
|
||||
return;
|
||||
}
|
||||
LOG(DEBUG) << "requesting data for block " << handle->id().to_str();
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db, handle,
|
||||
[Self, mc_ref_blkid = handle->masterchain_ref_block(), mc_blkid, pfx, mode](td::Result<Ref<BlockData>> 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_lookupBlockWithProof_getHeaderProof, res.move_as_ok(), pfx, mc_ref_blkid);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (mode & 2) {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_lt_from_db_for_litequery, pfx, lt, std::move(P));
|
||||
} else if (mode & 4) {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_unix_time_from_db_for_litequery, pfx, utime, std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_seqno_from_db_for_litequery, pfx, blkid.seqno, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
void LiteQuery::continue_lookupBlockWithProof_getHeaderProof(Ref<ton::validator::BlockData> block, AccountIdPrefixFull req_prefix, BlockSeqno masterchain_ref_seqno) {
|
||||
blk_id_ = block->block_id();
|
||||
LOG(INFO) << "obtained data for getBlockHeader(" << blk_id_.to_str() << ", " << mode_ << ")";
|
||||
CHECK(block.not_null());
|
||||
auto block_root = block->root_cell();
|
||||
if (block_root.is_null()) {
|
||||
fatal_error("block has no valid root cell");
|
||||
return;
|
||||
}
|
||||
|
||||
vm::MerkleProofBuilder mpb{block_root};
|
||||
std::vector<BlockIdExt> prev;
|
||||
BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
td::Status S = block::unpack_block_prev_blk_try(mpb.root(), blk_id_, prev, mc_blkid, after_split);
|
||||
if (S.is_error()) {
|
||||
fatal_error(std::move(S));
|
||||
return;
|
||||
}
|
||||
auto proof_data = mpb.extract_proof_boc();
|
||||
if (proof_data.is_error()) {
|
||||
fatal_error(proof_data.move_as_error());
|
||||
return;
|
||||
}
|
||||
lookup_header_proof_ = proof_data.move_as_ok();
|
||||
|
||||
bool include_prev = mode_ & 6;
|
||||
if (include_prev) {
|
||||
BlockIdExt prev_blkid;
|
||||
for (auto& p : prev) {
|
||||
if (ton::shard_contains(p.shard_full(), req_prefix)) {
|
||||
prev_blkid = p;
|
||||
}
|
||||
}
|
||||
CHECK(prev_blkid.is_valid());
|
||||
get_block_handle_checked(prev_blkid, [Self = actor_id(this), masterchain_ref_seqno, manager = manager_](td::Result<ConstBlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(manager, &ValidatorManager::get_block_data_from_db, R.move_as_ok(),
|
||||
[Self, masterchain_ref_seqno](td::Result<Ref<BlockData>> res) mutable {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(Self, &LiteQuery::continue_lookupBlockWithProof_gotPrevBlockData, res.move_as_ok(), masterchain_ref_seqno);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
continue_lookupBlockWithProof_gotPrevBlockData(Ref<BlockData>(), masterchain_ref_seqno);
|
||||
}
|
||||
}
|
||||
|
||||
void LiteQuery::continue_lookupBlockWithProof_gotPrevBlockData(Ref<BlockData> prev_block, BlockSeqno masterchain_ref_seqno) {
|
||||
if (prev_block.not_null()) {
|
||||
CHECK(prev_block.not_null());
|
||||
if (prev_block->root_cell().is_null()) {
|
||||
fatal_error("block has no valid root cell");
|
||||
return;
|
||||
}
|
||||
vm::MerkleProofBuilder mpb{prev_block->root_cell()};
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(mpb.root(), blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
fatal_error(td::Status::Error("cannot unpack prev block header"));
|
||||
return;
|
||||
}
|
||||
auto proof_data = mpb.extract_proof_boc();
|
||||
if (proof_data.is_error()) {
|
||||
fatal_error(proof_data.move_as_error());
|
||||
return;
|
||||
}
|
||||
lookup_prev_header_proof_ = proof_data.move_as_ok();
|
||||
}
|
||||
|
||||
if (!blk_id_.is_masterchain()) {
|
||||
ton::AccountIdPrefixFull pfx{ton::masterchainId, ton::shardIdAll};
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_by_seqno_from_db, pfx, masterchain_ref_seqno,
|
||||
[manager = manager_, Self = actor_id(this)](td::Result<ConstBlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(manager, &ValidatorManager::get_block_data_from_db, R.move_as_ok(),
|
||||
[Self](td::Result<Ref<BlockData>> res) mutable {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(Self, &LiteQuery::continue_lookupBlockWithProof_buildProofLinks, res.move_as_ok(), std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>>());
|
||||
});
|
||||
});
|
||||
} else {
|
||||
base_blk_id_alt_ = blk_id_;
|
||||
td::actor::send_closure(actor_id(this), &LiteQuery::continue_lookupBlockWithProof_getClientMcBlockDataState, std::vector<std::pair<BlockIdExt, Ref<vm::Cell>>>());
|
||||
}
|
||||
}
|
||||
|
||||
void LiteQuery::continue_lookupBlockWithProof_buildProofLinks(td::Ref<BlockData> cur_block,
|
||||
std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>> result) {
|
||||
BlockIdExt cur_id = cur_block->block_id();
|
||||
BlockIdExt prev_id;
|
||||
vm::MerkleProofBuilder mpb{cur_block->root_cell()};
|
||||
if (cur_id.is_masterchain()) {
|
||||
base_blk_id_alt_ = cur_id;
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!tlb::unpack_cell(mpb.root(), blk) || !tlb::unpack_cell(blk.extra, extra) || !extra.custom->have_refs() ||
|
||||
!tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra)) {
|
||||
fatal_error("cannot unpack header of block "s + cur_id.to_str());
|
||||
return;
|
||||
}
|
||||
block::ShardConfig shards(mc_extra.shard_hashes->prefetch_ref());
|
||||
ShardIdFull shard_id = blk_id_.shard_full();
|
||||
shard_id.shard = (shard_id.shard & ~(1 << (63 - shard_id.pfx_len()))) | 1;
|
||||
Ref<block::McShardHash> shard_hash = shards.get_shard_hash(shard_id, false);
|
||||
if (shard_hash.is_null()) {
|
||||
fatal_error("shard not found");
|
||||
return;
|
||||
}
|
||||
prev_id = shard_hash->top_block_id();
|
||||
} else {
|
||||
std::vector<BlockIdExt> prev;
|
||||
BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
td::Status S = block::unpack_block_prev_blk_try(mpb.root(), cur_id, prev, mc_blkid, after_split);
|
||||
if (S.is_error()) {
|
||||
fatal_error(std::move(S));
|
||||
return;
|
||||
}
|
||||
bool found = false;
|
||||
for (const BlockIdExt& id : prev) {
|
||||
if (shard_intersects(id.shard_full(), blk_id_.shard_full())) {
|
||||
found = true;
|
||||
prev_id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fatal_error("failed to find block chain");
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto proof = mpb.extract_proof();
|
||||
if (proof.is_error()) {
|
||||
fatal_error(proof.move_as_error_prefix("cannot serialize Merkle proof : "));
|
||||
return;
|
||||
}
|
||||
result.emplace_back(prev_id, proof.move_as_ok());
|
||||
|
||||
if (prev_id == blk_id_) {
|
||||
CHECK(base_blk_id_alt_.is_masterchain());
|
||||
if (base_blk_id_alt_ != base_blk_id_) {
|
||||
continue_lookupBlockWithProof_getClientMcBlockDataState(std::move(result));
|
||||
} else {
|
||||
continue_lookupBlockWithProof_getMcBlockPrev(std::move(result));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result.size() == 8) {
|
||||
// Chains of shardblocks between masterchain blocks can't be longer than 8 (see collator.cpp:991)
|
||||
fatal_error("proof chain is too long");
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_data_from_db_short, prev_id,
|
||||
[Self = actor_id(this), result = std::move(result)](td::Result<Ref<BlockData>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::continue_lookupBlockWithProof_buildProofLinks, R.move_as_ok(),
|
||||
std::move(result));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LiteQuery::continue_lookupBlockWithProof_getClientMcBlockDataState(std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>> links) {
|
||||
set_continuation([this, links = std::move(links)]() -> void {
|
||||
continue_lookupBlockWithProof_getMcBlockPrev(std::move(links));
|
||||
});
|
||||
request_mc_block_data_state(base_blk_id_);
|
||||
}
|
||||
|
||||
void LiteQuery::continue_lookupBlockWithProof_getMcBlockPrev(std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>> links) {
|
||||
td::BufferSlice mc_state_proof_buf, client_mc_blk_proof_buf;
|
||||
|
||||
if (base_blk_id_alt_ != base_blk_id_) {
|
||||
vm::MerkleProofBuilder mpb{mc_state_->root_cell()};
|
||||
auto prev_blocks_dict = block::get_prev_blocks_dict(mpb.root());
|
||||
if (!prev_blocks_dict) {
|
||||
fatal_error(td::Status::Error("cannot extract prev_blocks from mc state"));
|
||||
return;
|
||||
}
|
||||
if (!block::check_old_mc_block_id(*prev_blocks_dict, base_blk_id_alt_)) {
|
||||
fatal_error(td::Status::Error("client mc blkid is not in prev_blocks"));
|
||||
return;
|
||||
}
|
||||
auto client_mc_blk_proof = mpb.extract_proof_boc();
|
||||
if (client_mc_blk_proof.is_error()) {
|
||||
fatal_error(client_mc_blk_proof.move_as_error());
|
||||
return;
|
||||
}
|
||||
client_mc_blk_proof_buf = client_mc_blk_proof.move_as_ok();
|
||||
|
||||
Ref<vm::Cell> mc_state_proof;
|
||||
if (!make_mc_state_root_proof(mc_state_proof)) {
|
||||
fatal_error(td::Status::Error("cannot create Merkle proof for mc state"));
|
||||
return;
|
||||
}
|
||||
auto mc_state_proof_boc = vm::std_boc_serialize(std::move(mc_state_proof));
|
||||
if (mc_state_proof_boc.is_error()) {
|
||||
fatal_error(mc_state_proof_boc.move_as_error());
|
||||
return;
|
||||
}
|
||||
mc_state_proof_buf = mc_state_proof_boc.move_as_ok();
|
||||
}
|
||||
|
||||
std::vector<tl_object_ptr<lite_api::liteServer_shardBlockLink>> links_res;
|
||||
for (auto& p : links) {
|
||||
auto prev_block_proof = vm::std_boc_serialize(std::move(p.second));
|
||||
if (prev_block_proof.is_error()) {
|
||||
fatal_error(prev_block_proof.move_as_error());
|
||||
return;
|
||||
}
|
||||
links_res.push_back(
|
||||
create_tl_object<lite_api::liteServer_shardBlockLink>(create_tl_lite_block_id(p.first), prev_block_proof.move_as_ok()));
|
||||
}
|
||||
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_lookupBlockResult>(ton::create_tl_lite_block_id(blk_id_),
|
||||
mode_, ton::create_tl_lite_block_id(base_blk_id_alt_), std::move(mc_state_proof_buf), std::move(client_mc_blk_proof_buf),
|
||||
std::move(links_res), std::move(lookup_header_proof_), std::move(lookup_prev_header_proof_));
|
||||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
|
||||
void LiteQuery::perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, UnixTime utime) {
|
||||
if (!((1 << (mode & 7)) & 0x16)) {
|
||||
fatal_error("exactly one of mode.0, mode.1 and mode.2 bits must be set");
|
||||
|
|
|
@ -69,6 +69,9 @@ class LiteQuery : public td::actor::Actor {
|
|||
std::unique_ptr<block::BlockProofChain> chain_;
|
||||
Ref<vm::Stack> stack_;
|
||||
|
||||
td::BufferSlice lookup_header_proof_;
|
||||
td::BufferSlice lookup_prev_header_proof_;
|
||||
|
||||
public:
|
||||
enum {
|
||||
default_timeout_msec = 4500, // 4.5 seconds
|
||||
|
@ -124,6 +127,8 @@ class LiteQuery : public td::actor::Actor {
|
|||
UnixTime gen_utime, LogicalTime gen_lt);
|
||||
void perform_getLibraries(std::vector<td::Bits256> library_list);
|
||||
void continue_getLibraries(Ref<MasterchainState> mc_state, BlockIdExt blkid, std::vector<td::Bits256> library_list);
|
||||
void perform_getLibrariesWithProof(BlockIdExt blkid, int mode, std::vector<td::Bits256> library_list);
|
||||
void continue_getLibrariesWithProof(std::vector<td::Bits256> library_list, int mode);
|
||||
void perform_getOneTransaction(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, LogicalTime lt);
|
||||
void continue_getOneTransaction();
|
||||
void perform_getTransactions(WorkchainId workchain, StdSmcAddress addr, LogicalTime lt, Bits256 hash, unsigned count);
|
||||
|
@ -138,6 +143,12 @@ class LiteQuery : public td::actor::Actor {
|
|||
void perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list = {});
|
||||
void continue_getConfigParams(int mode, std::vector<int> param_list);
|
||||
void perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, UnixTime utime);
|
||||
void perform_lookupBlockWithProof(BlockId blkid, BlockIdExt client_mc_blkid, int mode, LogicalTime lt, UnixTime utime);
|
||||
void continue_lookupBlockWithProof_getHeaderProof(Ref<ton::validator::BlockData> block, AccountIdPrefixFull req_prefix, BlockSeqno masterchain_ref_seqno);
|
||||
void continue_lookupBlockWithProof_gotPrevBlockData(Ref<BlockData> prev_block, BlockSeqno masterchain_ref_seqno);
|
||||
void continue_lookupBlockWithProof_buildProofLinks(td::Ref<BlockData> cur_block, std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>> result);
|
||||
void continue_lookupBlockWithProof_getClientMcBlockDataState(std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>> links);
|
||||
void continue_lookupBlockWithProof_getMcBlockPrev(std::vector<std::pair<BlockIdExt, td::Ref<vm::Cell>>> links);
|
||||
void perform_listBlockTransactions(BlockIdExt blkid, int mode, int count, Bits256 account, LogicalTime lt);
|
||||
void finish_listBlockTransactions(int mode, int count);
|
||||
void perform_listBlockTransactionsExt(BlockIdExt blkid, int mode, int count, Bits256 account, LogicalTime lt);
|
||||
|
|
Loading…
Reference in a new issue