1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Merge branch 'testnet' into accelerator

This commit is contained in:
SpyCheese 2024-09-19 12:12:46 +03:00
commit 09da42e38f
20 changed files with 798 additions and 19 deletions

View file

@ -28,5 +28,5 @@ jobs:
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@master uses: actions/upload-artifact@master
with: with:
name: tonlib-android name: ton-android-tonlib
path: artifacts path: artifacts

View file

@ -83,6 +83,14 @@ jobs:
workflow_conclusion: success workflow_conclusion: success
skip_unpack: true skip_unpack: true
- name: Download Android Tonlib artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: build-ton-linux-android-tonlib.yml
path: artifacts
workflow_conclusion: success
skip_unpack: true
- name: Show all artifacts - name: Show all artifacts
run: | run: |
tree artifacts tree artifacts
@ -501,3 +509,11 @@ jobs:
file: artifacts/ton-wasm-binaries.zip file: artifacts/ton-wasm-binaries.zip
asset_name: ton-wasm-binaries.zip asset_name: ton-wasm-binaries.zip
tag: ${{ steps.tag.outputs.TAG }} tag: ${{ steps.tag.outputs.TAG }}
- name: Upload Android Tonlib artifacts
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: artifacts/ton-android-tonlib.zip
asset_name: ton-android-tonlib.zip
tag: ${{ steps.tag.outputs.TAG }}

View file

@ -192,8 +192,6 @@ if [ "$with_artifacts" = true ]; then
echo Creating artifacts... echo Creating artifacts...
rm -rf artifacts rm -rf artifacts
mkdir artifacts mkdir artifacts
cp crypto/fift/lib artifacts/
cp -R crypto/smartcont/ artifacts/
cp build/storage/storage-daemon/storage-daemon artifacts/ cp build/storage/storage-daemon/storage-daemon artifacts/
cp build/storage/storage-daemon/storage-daemon-cli artifacts/ cp build/storage/storage-daemon/storage-daemon-cli artifacts/
cp build/blockchain-explorer/blockchain-explorer artifacts/ cp build/blockchain-explorer/blockchain-explorer artifacts/
@ -213,9 +211,9 @@ if [ "$with_artifacts" = true ]; then
cp build/utils/json2tlo artifacts/ cp build/utils/json2tlo artifacts/
cp build/adnl/adnl-proxy artifacts/ cp build/adnl/adnl-proxy artifacts/
cp build/emulator/libemulator.dylib artifacts/ cp build/emulator/libemulator.dylib artifacts/
chmod +x artifacts/*
rsync -r crypto/smartcont artifacts/ rsync -r crypto/smartcont artifacts/
rsync -r crypto/fift/lib artifacts/ rsync -r crypto/fift/lib artifacts/
chmod -R +x artifacts/*
fi fi
if [ "$with_tests" = true ]; then if [ "$with_tests" = true ]; then

View file

@ -140,9 +140,9 @@ if [ "$with_artifacts" = true ]; then
cp build/utils/json2tlo artifacts/ cp build/utils/json2tlo artifacts/
cp build/adnl/adnl-proxy artifacts/ cp build/adnl/adnl-proxy artifacts/
cp build/emulator/libemulator.dylib artifacts/ cp build/emulator/libemulator.dylib artifacts/
chmod +x artifacts/* cp -R crypto/smartcont artifacts/
rsync -r crypto/smartcont artifacts/ cp -R crypto/fift/lib artifacts/
rsync -r crypto/fift/lib artifacts/ chmod -R +x artifacts/*
fi fi
if [ "$with_tests" = true ]; then if [ "$with_tests" = true ]; then

View file

@ -193,8 +193,6 @@ cd ..
if [ "$with_artifacts" = true ]; then if [ "$with_artifacts" = true ]; then
rm -rf artifacts rm -rf artifacts
mkdir artifacts mkdir artifacts
cp crypto/fift/lib artifacts/
cp -R crypto/smartcont/ artifacts/
mv build/tonlib/libtonlibjson.so.0.5 build/tonlib/libtonlibjson.so mv build/tonlib/libtonlibjson.so.0.5 build/tonlib/libtonlibjson.so
cp build/storage/storage-daemon/storage-daemon build/storage/storage-daemon/storage-daemon-cli \ cp build/storage/storage-daemon/storage-daemon build/storage/storage-daemon/storage-daemon-cli \
build/crypto/fift build/crypto/tlbc build/crypto/func build/crypto/create-state build/blockchain-explorer/blockchain-explorer \ build/crypto/fift build/crypto/tlbc build/crypto/func build/crypto/create-state build/blockchain-explorer/blockchain-explorer \
@ -204,9 +202,9 @@ if [ "$with_artifacts" = true ]; then
build/utils/generate-random-id build/utils/json2tlo build/adnl/adnl-proxy build/emulator/libemulator.so \ build/utils/generate-random-id build/utils/json2tlo build/adnl/adnl-proxy build/emulator/libemulator.so \
artifacts artifacts
test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; } test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; }
chmod +x artifacts/*
cp -R crypto/smartcont artifacts cp -R crypto/smartcont artifacts
cp -R crypto/fift/lib artifacts cp -R crypto/fift/lib artifacts
chmod -R +x artifacts/*
fi fi
if [ "$with_tests" = true ]; then if [ "$with_tests" = true ]; then

View file

@ -112,9 +112,9 @@ if [ "$with_artifacts" = true ]; then
build/utils/generate-random-id build/utils/json2tlo build/adnl/adnl-proxy build/emulator/libemulator.so \ build/utils/generate-random-id build/utils/json2tlo build/adnl/adnl-proxy build/emulator/libemulator.so \
artifacts artifacts
test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; } test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; }
chmod +x artifacts/*
cp -R crypto/smartcont artifacts cp -R crypto/smartcont artifacts
cp -R crypto/fift/lib artifacts cp -R crypto/fift/lib artifacts
chmod -R +x artifacts/*
fi fi
if [ "$with_tests" = true ]; then if [ "$with_tests" = true ]; then

View file

@ -35,3 +35,4 @@ cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
cp ./result/lib/libemulator.so artifacts/ cp ./result/lib/libemulator.so artifacts/
cp ./result/lib/fift/* artifacts/lib/ cp ./result/lib/fift/* artifacts/lib/
cp -r ./result/share/ton/smartcont artifacts/ cp -r ./result/share/ton/smartcont artifacts/
chmod -R +x artifacts

View file

@ -35,3 +35,4 @@ cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
cp ./result/lib/libemulator.so artifacts/ cp ./result/lib/libemulator.so artifacts/
cp ./result/lib/fift/* artifacts/lib/ cp ./result/lib/fift/* artifacts/lib/
cp -r ./result/share/ton/smartcont artifacts/ cp -r ./result/share/ton/smartcont artifacts/
chmod -R +x artifacts

View file

@ -35,3 +35,4 @@ cp ./result/lib/libtonlibjson.dylib artifacts/
cp ./result/lib/libemulator.dylib artifacts/ cp ./result/lib/libemulator.dylib artifacts/
cp ./result/lib/fift/* artifacts/lib/ cp ./result/lib/fift/* artifacts/lib/
cp -r ./result/share/ton/smartcont artifacts/ cp -r ./result/share/ton/smartcont artifacts/
chmod -R +x artifacts

View file

@ -433,6 +433,14 @@ if (WINGETOPT_FOUND)
target_link_libraries_system(pow-miner wingetopt) target_link_libraries_system(pow-miner wingetopt)
endif() endif()
add_executable(mintless-proof-generator util/mintless-proof-generator.cpp)
target_link_libraries(mintless-proof-generator PRIVATE ton_crypto ton_block git ${JEMALLOC_LIBRARIES})
if (JEMALLOC_FOUND)
target_include_directories(mintless-proof-generator PRIVATE ${JEMALLOC_INCLUDE_DIR})
target_compile_definitions(mintless-proof-generator PRIVATE -DTON_USE_JEMALLOC=1)
endif()
set(TURN_OFF_LSAN cd .) set(TURN_OFF_LSAN cd .)
if (TON_USE_ASAN AND NOT WIN32) if (TON_USE_ASAN AND NOT WIN32)
set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0) set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0)

View file

@ -0,0 +1,395 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "block-parse.h"
#include "block.h"
#include "td/actor/core/Actor.h"
#include "td/db/utils/BlobView.h"
#include <iostream>
#include "td/utils/OptionParser.h"
#include "td/utils/Time.h"
#include "td/utils/base64.h"
#include "td/utils/filesystem.h"
#include "td/utils/logging.h"
#include "vm/cells/MerkleProof.h"
#include "vm/db/StaticBagOfCellsDb.h"
#include <fstream>
#include <common/delay.h>
const size_t KEY_LEN = 3 + 8 + 256;
void print_help() {
std::cerr << "mintless-proof-generator - generates proofs for mintless jettons. Usage:\n\n";
std::cerr << "mintless-proof-generator generate <input-list> <output-file>\n";
std::cerr << " Generate a full tree for <input-list>, save boc to <output-file>.\n";
std::cerr << " Input format: each line is <address> <amount> <start_from> <expired_at>.\n\n";
std::cerr << "mintless-proof-generator make_proof <input-boc> <address> <output-file>.\n";
std::cerr << " Generate a proof for address <address> from tree <input-boc>, save boc to file <output-file>.\n\n";
std::cerr << "mintless-proof-generator parse <input-boc> <output-file>\n";
std::cerr << " Read a tree from <input-boc> and output it as text to <output-file>.\n";
std::cerr << " Output format: same as input for 'generate'.\n\n";
std::cerr << "mintless-proof-generator make_all_proofs <input-boc> <output-file> [--threads <threads>]\n";
std::cerr << " Read a tree from <input-boc> and output proofs for all accounts to <output-file>.\n";
std::cerr << " Output format: <address>,<proof-base64>\n";
std::cerr << " Default <threads>: 1\n";
exit(2);
}
void log_mem_stat() {
auto r_stat = td::mem_stat();
if (r_stat.is_error()) {
LOG(WARNING) << "Memory: " << r_stat.move_as_error();
return;
}
auto stat = r_stat.move_as_ok();
LOG(WARNING) << "Memory: "
<< "res=" << stat.resident_size_ << " (peak=" << stat.resident_size_peak_
<< ") virt=" << stat.virtual_size_ << " (peak=" << stat.virtual_size_peak_ << ")";
}
td::BitArray<KEY_LEN> address_to_key(const block::StdAddress &address) {
// addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256 = MsgAddressInt;
vm::CellBuilder cb;
cb.store_long(0b100, 3);
cb.store_long(address.workchain, 8);
cb.store_bits(address.addr.as_bitslice());
return cb.data_bits();
}
block::StdAddress key_to_address(const td::BitArray<KEY_LEN> &key) {
block::StdAddress addr;
td::ConstBitPtr ptr = key.bits();
LOG_CHECK(ptr.get_uint(3) == 0b100) << "Invalid address";
ptr.advance(3);
addr.workchain = (ton::WorkchainId)ptr.get_int(8);
ptr.advance(8);
addr.addr = ptr;
return addr;
}
struct Entry {
block::StdAddress address;
td::RefInt256 amount;
td::uint64 start_from = 0, expired_at = 0;
td::BitArray<KEY_LEN> get_key() const {
return address_to_key(address);
}
td::Ref<vm::CellSlice> get_value() const {
// _ amount:Coins start_from:uint48 expired_at:uint48 = AirdropItem;
vm::CellBuilder cb;
bool ok = block::tlb::t_Grams.store_integer_value(cb, *amount) && cb.store_ulong_rchk_bool(start_from, 48) &&
cb.store_ulong_rchk_bool(expired_at, 48);
LOG_CHECK(ok) << "Failed to serialize AirdropItem";
return cb.as_cellslice_ref();
}
static Entry parse(const td::BitArray<KEY_LEN> &key, vm::CellSlice value) {
Entry e;
e.address = key_to_address(key);
bool ok = block::tlb::t_Grams.as_integer_skip_to(value, e.amount) && value.fetch_uint_to(48, e.start_from) &&
value.fetch_uint_to(48, e.expired_at) && value.empty_ext();
LOG_CHECK(ok) << "Failed to parse AirdropItem";
return e;
}
};
bool read_entry(std::istream &f, Entry &entry) {
std::string line;
while (std::getline(f, line)) {
std::vector<std::string> v = td::full_split(line, ' ');
if (v.empty()) {
continue;
}
auto S = [&]() -> td::Status {
if (v.size() != 4) {
return td::Status::Error("Invalid line in input");
}
TRY_RESULT_PREFIX_ASSIGN(entry.address, block::StdAddress::parse(v[0]), "Invalid address in input: ");
entry.amount = td::string_to_int256(v[1]);
if (entry.amount.is_null() || !entry.amount->is_valid() || entry.amount->sgn() < 0) {
return td::Status::Error(PSTRING() << "Invalid amount in input: " << v[1]);
}
TRY_RESULT_PREFIX_ASSIGN(entry.start_from, td::to_integer_safe<td::uint64>(v[2]),
"Invalid start_from in input: ");
TRY_RESULT_PREFIX_ASSIGN(entry.expired_at, td::to_integer_safe<td::uint64>(v[3]),
"Invalid expired_at in input: ");
return td::Status::OK();
}();
S.ensure();
return true;
}
return false;
}
td::Status run_generate(std::string in_filename, std::string out_filename) {
LOG(INFO) << "Generating tree from " << in_filename;
std::ifstream in_file{in_filename};
LOG_CHECK(in_file.is_open()) << "Cannot open file " << in_filename;
Entry entry;
vm::Dictionary dict{KEY_LEN};
td::uint64 count = 0;
td::Timestamp log_at = td::Timestamp::in(5.0);
while (read_entry(in_file, entry)) {
++count;
bool ok = dict.set(entry.get_key(), entry.get_value(), vm::DictionaryBase::SetMode::Add);
LOG_CHECK(ok) << "Failed to add entry " << entry.address.rserialize() << " (line #" << count << ")";
if (log_at.is_in_past()) {
LOG(INFO) << "Added " << count << " entries";
log_at = td::Timestamp::in(5.0);
}
}
LOG_CHECK(in_file.eof()) << "Failed to read file " << in_filename;
in_file.close();
LOG_CHECK(count != 0) << "Input is empty";
td::Ref<vm::Cell> root = dict.get_root_cell();
LOG(INFO) << "Total: " << count << " entries, root hash: " << root->get_hash().to_hex();
vm::BagOfCells boc;
boc.add_root(root);
TRY_STATUS(boc.import_cells());
LOG(INFO) << "Writing to " << out_filename;
TRY_RESULT(fd, td::FileFd::open(out_filename, td::FileFd::Write | td::FileFd::Truncate | td::FileFd::Create));
TRY_STATUS(boc.serialize_to_file(fd, 31));
TRY_STATUS(fd.sync());
fd.close();
log_mem_stat();
return td::Status::OK();
}
td::Status run_make_proof(std::string in_filename, std::string s_address, std::string out_filename) {
LOG(INFO) << "Generating proof for " << s_address << ", input file is " << in_filename;
TRY_RESULT(address, block::StdAddress::parse(s_address));
TRY_RESULT(blob_view, td::FileBlobView::create(in_filename));
TRY_RESULT(boc, vm::StaticBagOfCellsDbLazy::create(std::move(blob_view)));
TRY_RESULT(root, boc->get_root_cell(0));
vm::MerkleProofBuilder mpb{root};
vm::Dictionary dict{mpb.root(), KEY_LEN};
auto key = address_to_key(address);
td::Ref<vm::CellSlice> value = dict.lookup(key);
LOG_CHECK(value.not_null()) << "No entry for address " << s_address;
Entry e = Entry::parse(key, *value);
LOG(INFO) << "Entry: address=" << e.address.workchain << ":" << e.address.addr.to_hex()
<< " amount=" << e.amount->to_dec_string() << " start_from=" << e.start_from
<< " expire_at=" << e.expired_at;
TRY_RESULT(proof, mpb.extract_proof_boc());
LOG(INFO) << "Writing proof to " << out_filename << " (" << td::format::as_size(proof.size()) << ")";
TRY_STATUS(td::write_file(out_filename, proof));
log_mem_stat();
return td::Status::OK();
}
td::Status run_parse(std::string in_filename, std::string out_filename) {
LOG(INFO) << "Parsing " << in_filename;
std::ofstream out_file{out_filename};
LOG_CHECK(out_file.is_open()) << "Cannot open file " << out_filename;
TRY_RESULT(blob_view, td::FileBlobView::create(in_filename));
TRY_RESULT(boc, vm::StaticBagOfCellsDbLazy::create(std::move(blob_view)));
TRY_RESULT(root, boc->get_root_cell(0));
LOG(INFO) << "Root hash = " << root->get_hash().to_hex();
vm::Dictionary dict{root, KEY_LEN};
td::Timestamp log_at = td::Timestamp::in(5.0);
td::uint64 count = 0;
bool ok = dict.check_for_each([&](td::Ref<vm::CellSlice> value, td::ConstBitPtr key, int key_len) {
CHECK(key_len == KEY_LEN);
Entry e = Entry::parse(key, *value);
out_file << e.address.workchain << ":" << e.address.addr.to_hex() << " " << e.amount->to_dec_string() << " "
<< e.start_from << " " << e.expired_at << "\n";
LOG_CHECK(!out_file.fail()) << "Failed to write to " << out_filename;
++count;
if (log_at.is_in_past()) {
LOG(INFO) << "Parsed " << count << " entries";
log_at = td::Timestamp::in(5.0);
}
return true;
});
LOG_CHECK(ok) << "Failed to parse dictionary";
out_file.close();
LOG_CHECK(!out_file.fail()) << "Failed to write to " << out_filename;
LOG(INFO) << "Written " << count << " entries to " << out_filename;
log_mem_stat();
return td::Status::OK();
}
class MakeAllProofsActor : public td::actor::core::Actor {
public:
MakeAllProofsActor(std::string in_filename, std::string out_filename, int max_workers)
: in_filename_(in_filename), out_filename_(out_filename), max_workers_(max_workers) {
}
void start_up() override {
auto S = [&]() -> td::Status {
out_file_.open(out_filename_);
LOG_CHECK(out_file_.is_open()) << "Cannot open file " << out_filename_;
LOG(INFO) << "Reading " << in_filename_;
TRY_RESULT(blob_view, td::FileBlobView::create(in_filename_));
TRY_RESULT(boc, vm::StaticBagOfCellsDbLazy::create(std::move(blob_view)));
TRY_RESULT(root, boc->get_root_cell(0));
LOG(INFO) << "Root hash = " << root->get_hash().to_hex();
dict_ = vm::Dictionary{root, KEY_LEN};
return td::Status::OK();
}();
S.ensure();
run();
alarm_timestamp() = td::Timestamp::in(5.0);
}
void alarm() override {
alarm_timestamp() = td::Timestamp::in(5.0);
LOG(INFO) << "Processed " << written_count_ << " entries";
}
void run() {
for (auto it = pending_results_.begin(); it != pending_results_.end() && !it->second.empty();) {
out_file_ << it->second << "\n";
LOG_CHECK(!out_file_.fail()) << "Failed to write to " << out_filename_;
it = pending_results_.erase(it);
++written_count_;
}
while (active_workers_ < max_workers_ && !eof_) {
td::Ref<vm::CellSlice> value = dict_.lookup_nearest_key(current_key_, true, current_idx_ == 0);
if (value.is_null()) {
eof_ = true;
break;
}
run_worker(current_key_, current_idx_);
++current_idx_;
++active_workers_;
}
if (eof_ && active_workers_ == 0) {
out_file_.close();
LOG_CHECK(!out_file_.fail()) << "Failed to write to " << out_filename_;
LOG(INFO) << "Written " << written_count_ << " entries to " << out_filename_;
stop();
td::actor::SchedulerContext::get()->stop();
}
}
void run_worker(td::BitArray<KEY_LEN> key, td::uint64 idx) {
pending_results_[idx] = "";
ton::delay_action(
[SelfId = actor_id(this), key, idx, root = dict_.get_root_cell()]() {
vm::MerkleProofBuilder mpb{root};
CHECK(vm::Dictionary(mpb.root(), KEY_LEN).lookup(key).not_null());
auto r_proof = mpb.extract_proof_boc();
r_proof.ensure();
block::StdAddress addr = key_to_address(key);
std::string result = PSTRING() << addr.workchain << ":" << addr.addr.to_hex() << ","
<< td::base64_encode(r_proof.move_as_ok());
td::actor::send_closure(SelfId, &MakeAllProofsActor::on_result, idx, std::move(result));
},
td::Timestamp::now());
}
void on_result(td::uint64 idx, std::string result) {
pending_results_[idx] = std::move(result);
--active_workers_;
run();
}
private:
std::string in_filename_, out_filename_;
int max_workers_;
std::ofstream out_file_;
vm::Dictionary dict_{KEY_LEN};
td::BitArray<KEY_LEN> current_key_ = td::BitArray<KEY_LEN>::zero();
td::uint64 current_idx_ = 0;
bool eof_ = false;
int active_workers_ = 0;
std::map<td::uint64, std::string> pending_results_;
td::uint64 written_count_ = 0;
};
td::Status run_make_all_proofs(std::string in_filename, std::string out_filename, int threads) {
td::actor::Scheduler scheduler({(size_t)threads});
scheduler.run_in_context(
[&] { td::actor::create_actor<MakeAllProofsActor>("proofs", in_filename, out_filename, threads).release(); });
while (scheduler.run(1)) {
}
log_mem_stat();
return td::Status::OK();
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_log_fatal_error_callback([](td::CSlice) { exit(2); });
if (argc <= 1) {
print_help();
return 2;
}
std::string command = argv[1];
try {
if (command == "generate") {
if (argc != 4) {
print_help();
}
run_generate(argv[2], argv[3]).ensure();
return 0;
}
if (command == "make_proof") {
if (argc != 5) {
print_help();
}
run_make_proof(argv[2], argv[3], argv[4]).ensure();
return 0;
}
if (command == "parse") {
if (argc != 4) {
print_help();
}
run_parse(argv[2], argv[3]).ensure();
return 0;
}
if (command == "make_all_proofs") {
std::vector<std::string> args;
int threads = 1;
for (int i = 2; i < argc; ++i) {
if (!strcmp(argv[i], "--threads")) {
++i;
auto r = td::to_integer_safe<int>(td::as_slice(argv[i]));
LOG_CHECK(r.is_ok() && r.ok() >= 1 && r.ok() <= 127) << "<threads> should be in [1..127]";
threads = r.move_as_ok();
} else {
args.push_back(argv[i]);
}
}
if (args.size() != 2) {
print_help();
}
run_make_all_proofs(args[0], args[1], threads).ensure();
return 0;
}
} catch (vm::VmError &e) {
LOG(FATAL) << "VM error: " << e.get_msg();
} catch (vm::VmVirtError &e) {
LOG(FATAL) << "VM error: " << e.get_msg();
}
LOG(FATAL) << "Unknown command '" << command << "'";
}

View file

@ -167,7 +167,7 @@ td::Result<Ref<Cell>> StaticBagOfCellsDb::create_ext_cell(Cell::LevelMask level_
// //
class StaticBagOfCellsDbBaselineImpl : public StaticBagOfCellsDb { class StaticBagOfCellsDbBaselineImpl : public StaticBagOfCellsDb {
public: public:
StaticBagOfCellsDbBaselineImpl(std::vector<Ref<Cell>> roots) : roots_(std::move(roots)) { explicit StaticBagOfCellsDbBaselineImpl(std::vector<Ref<Cell>> roots) : roots_(std::move(roots)) {
} }
td::Result<size_t> get_root_count() override { td::Result<size_t> get_root_count() override {
return roots_.size(); return roots_.size();
@ -233,7 +233,7 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
return create_root_cell(std::move(data_cell)); return create_root_cell(std::move(data_cell));
}; };
~StaticBagOfCellsDbLazyImpl() { ~StaticBagOfCellsDbLazyImpl() override {
//LOG(ERROR) << deserialize_cell_cnt_ << " " << deserialize_cell_hash_cnt_; //LOG(ERROR) << deserialize_cell_cnt_ << " " << deserialize_cell_hash_cnt_;
get_thread_safe_counter().add(-1); get_thread_safe_counter().add(-1);
} }
@ -314,11 +314,11 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
td::RwMutex::ReadLock guard; td::RwMutex::ReadLock guard;
if (info_.has_index) { if (info_.has_index) {
TRY_RESULT(new_offset_view, data_.view(td::MutableSlice(arr, info_.offset_byte_size), TRY_RESULT(new_offset_view, data_.view(td::MutableSlice(arr, info_.offset_byte_size),
info_.index_offset + idx * info_.offset_byte_size)); info_.index_offset + (td::int64)idx * info_.offset_byte_size));
offset_view = new_offset_view; offset_view = new_offset_view;
} else { } else {
guard = index_data_rw_mutex_.lock_read().move_as_ok(); guard = index_data_rw_mutex_.lock_read().move_as_ok();
offset_view = td::Slice(index_data_).substr(idx * info_.offset_byte_size, info_.offset_byte_size); offset_view = td::Slice(index_data_).substr((td::int64)idx * info_.offset_byte_size, info_.offset_byte_size);
} }
CHECK(offset_view.size() == (size_t)info_.offset_byte_size); CHECK(offset_view.size() == (size_t)info_.offset_byte_size);
@ -332,7 +332,7 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
} }
char arr[8]; char arr[8];
TRY_RESULT(idx_view, data_.view(td::MutableSlice(arr, info_.ref_byte_size), TRY_RESULT(idx_view, data_.view(td::MutableSlice(arr, info_.ref_byte_size),
info_.roots_offset + root_i * info_.ref_byte_size)); info_.roots_offset + (td::int64)root_i * info_.ref_byte_size));
CHECK(idx_view.size() == (size_t)info_.ref_byte_size); CHECK(idx_view.size() == (size_t)info_.ref_byte_size);
return info_.read_ref(idx_view.ubegin()); return info_.read_ref(idx_view.ubegin());
} }

View file

@ -957,6 +957,11 @@ bool TestNode::show_help(std::string command) {
"into files <filename-pfx><complaint-hash>.boc\n" "into files <filename-pfx><complaint-hash>.boc\n"
"complaintprice <expires-in> <complaint-boc>\tComputes the price (in nanograms) for creating a complaint\n" "complaintprice <expires-in> <complaint-boc>\tComputes the price (in nanograms) for creating a complaint\n"
"msgqueuesizes\tShows current sizes of outbound message queues in all shards\n" "msgqueuesizes\tShows current sizes of outbound message queues in all shards\n"
"dispatchqueueinfo <block-id>\tShows list of account dispatch queue of a block\n"
"dispatchqueuemessages <block-id> <addr> [<after-lt>]\tShows deferred messages from account <addr>, lt > "
"<after_lt>\n"
"dispatchqueuemessagesall <block-id> [<after-addr> [<after-lt>]]\tShows messages from dispatch queue of a "
"block, starting after <after_addr>, <after-lt>\n"
"known\tShows the list of all known block ids\n" "known\tShows the list of all known block ids\n"
"knowncells\tShows the list of hashes of all known (cached) cells\n" "knowncells\tShows the list of hashes of all known (cached) cells\n"
"dumpcell <hex-hash-pfx>\nDumps a cached cell by a prefix of its hash\n" "dumpcell <hex-hash-pfx>\nDumps a cached cell by a prefix of its hash\n"
@ -971,9 +976,9 @@ bool TestNode::show_help(std::string command) {
bool TestNode::do_parse_line() { bool TestNode::do_parse_line() {
ton::WorkchainId workchain = ton::masterchainId; // change to basechain later ton::WorkchainId workchain = ton::masterchainId; // change to basechain later
int addr_ext = 0; int addr_ext = 0;
ton::StdSmcAddress addr{}; ton::StdSmcAddress addr = ton::StdSmcAddress::zero();
ton::BlockIdExt blkid{}; ton::BlockIdExt blkid{};
ton::LogicalTime lt{}; ton::LogicalTime lt = 0;
ton::Bits256 hash{}; ton::Bits256 hash{};
ton::ShardIdFull shard{}; ton::ShardIdFull shard{};
ton::BlockSeqno seqno{}; ton::BlockSeqno seqno{};
@ -1101,6 +1106,16 @@ bool TestNode::do_parse_line() {
set_error(get_complaint_price(expire_in, filename)); set_error(get_complaint_price(expire_in, filename));
} else if (word == "msgqueuesizes") { } else if (word == "msgqueuesizes") {
return get_msg_queue_sizes(); return get_msg_queue_sizes();
} else if (word == "dispatchqueueinfo") {
return parse_block_id_ext(blkid) && seekeoln() && get_dispatch_queue_info(blkid);
} else if (word == "dispatchqueuemessages" || word == "dispatchqueuemessagesall") {
bool one_account = word == "dispatchqueuemessages";
if (!parse_block_id_ext(blkid)) {
return false;
}
workchain = blkid.id.workchain;
return ((!one_account && seekeoln()) || parse_account_addr(workchain, addr)) && (seekeoln() || parse_lt(lt)) &&
seekeoln() && get_dispatch_queue_messages(blkid, workchain, addr, lt, one_account);
} else if (word == "known") { } else if (word == "known") {
return eoln() && show_new_blkids(true); return eoln() && show_new_blkids(true);
} else if (word == "knowncells") { } else if (word == "knowncells") {
@ -1628,6 +1643,81 @@ void TestNode::got_msg_queue_sizes(ton::tl_object_ptr<ton::lite_api::liteServer_
td::TerminalIO::out() << "External message queue size limit: " << f->ext_msg_queue_size_limit_ << std::endl; td::TerminalIO::out() << "External message queue size limit: " << f->ext_msg_queue_size_limit_ << std::endl;
} }
bool TestNode::get_dispatch_queue_info(ton::BlockIdExt block_id) {
td::TerminalIO::out() << "Dispatch queue in block: " << block_id.id.to_str() << std::endl;
return get_dispatch_queue_info_cont(block_id, true, td::Bits256::zero());
}
bool TestNode::get_dispatch_queue_info_cont(ton::BlockIdExt block_id, bool first, td::Bits256 after_addr) {
auto q = ton::create_serialize_tl_object<ton::lite_api::liteServer_getDispatchQueueInfo>(
first ? 0 : 2, ton::create_tl_lite_block_id(block_id), after_addr, 32, false);
return envelope_send_query(std::move(q), [=, Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
if (res.is_error()) {
LOG(ERROR) << "liteServer.getDispatchQueueInfo error: " << res.move_as_error();
return;
}
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_dispatchQueueInfo>(res.move_as_ok(), true);
if (F.is_error()) {
LOG(ERROR) << "cannot parse answer to liteServer.getDispatchQueueInfo";
return;
}
td::actor::send_closure_later(Self, &TestNode::got_dispatch_queue_info, block_id, F.move_as_ok());
});
}
void TestNode::got_dispatch_queue_info(ton::BlockIdExt block_id,
ton::tl_object_ptr<ton::lite_api::liteServer_dispatchQueueInfo> info) {
for (auto& acc : info->account_dispatch_queues_) {
td::TerminalIO::out() << block_id.id.workchain << ":" << acc->addr_.to_hex() << " : size=" << acc->size_
<< " lt=" << acc->min_lt_ << ".." << acc->max_lt_ << std::endl;
}
if (info->complete_) {
td::TerminalIO::out() << "Done" << std::endl;
return;
}
get_dispatch_queue_info_cont(block_id, false, info->account_dispatch_queues_.back()->addr_);
}
bool TestNode::get_dispatch_queue_messages(ton::BlockIdExt block_id, ton::WorkchainId wc, ton::StdSmcAddress addr,
ton::LogicalTime lt, bool one_account) {
if (wc != block_id.id.workchain) {
return set_error("workchain mismatch");
}
auto q = ton::create_serialize_tl_object<ton::lite_api::liteServer_getDispatchQueueMessages>(
one_account ? 2 : 0, ton::create_tl_lite_block_id(block_id), addr, lt, 64, false, one_account, false);
return envelope_send_query(std::move(q), [=, Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
if (res.is_error()) {
LOG(ERROR) << "liteServer.getDispatchQueueMessages error: " << res.move_as_error();
return;
}
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_dispatchQueueMessages>(res.move_as_ok(), true);
if (F.is_error()) {
LOG(ERROR) << "cannot parse answer to liteServer.getDispatchQueueMessages";
return;
}
td::actor::send_closure_later(Self, &TestNode::got_dispatch_queue_messages, F.move_as_ok());
});
}
void TestNode::got_dispatch_queue_messages(ton::tl_object_ptr<ton::lite_api::liteServer_dispatchQueueMessages> msgs) {
td::TerminalIO::out() << "Dispatch queue messages (" << msgs->messages_.size() << "):\n";
int count = 0;
for (auto& m : msgs->messages_) {
auto& meta = m->metadata_;
td::TerminalIO::out() << "Msg #" << ++count << ": " << msgs->id_->workchain_ << ":" << m->addr_.to_hex() << " "
<< m->lt_ << " : "
<< (meta->initiator_->workchain_ == ton::workchainInvalid
? "[ no metadata ]"
: block::MsgMetadata{(td::uint32)meta->depth_, meta->initiator_->workchain_,
meta->initiator_->id_, (ton::LogicalTime)meta->initiator_lt_}
.to_str())
<< "\n";
}
if (!msgs->complete_) {
td::TerminalIO::out() << "(incomplete list)\n";
}
}
bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
std::string domain, td::Bits256 cat, int mode) { std::string domain, td::Bits256 cat, int mode) {
if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') { if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') {

View file

@ -305,6 +305,13 @@ class TestNode : public td::actor::Actor {
unsigned refs, td::Bits256 chash, std::string filename); unsigned refs, td::Bits256 chash, std::string filename);
bool get_msg_queue_sizes(); bool get_msg_queue_sizes();
void got_msg_queue_sizes(ton::tl_object_ptr<ton::lite_api::liteServer_outMsgQueueSizes> f); void got_msg_queue_sizes(ton::tl_object_ptr<ton::lite_api::liteServer_outMsgQueueSizes> f);
bool get_dispatch_queue_info(ton::BlockIdExt block_id);
bool get_dispatch_queue_info_cont(ton::BlockIdExt block_id, bool first, td::Bits256 after_addr);
void got_dispatch_queue_info(ton::BlockIdExt block_id,
ton::tl_object_ptr<ton::lite_api::liteServer_dispatchQueueInfo> info);
bool get_dispatch_queue_messages(ton::BlockIdExt block_id, ton::WorkchainId wc, ton::StdSmcAddress addr,
ton::LogicalTime lt, bool one_account);
void got_dispatch_queue_messages(ton::tl_object_ptr<ton::lite_api::liteServer_dispatchQueueMessages> msgs);
bool cache_cell(Ref<vm::Cell> cell); bool cache_cell(Ref<vm::Cell> cell);
bool list_cached_cells() const; bool list_cached_cells() const;
bool dump_cached_cell(td::Slice hash_pfx, td::Slice type_name = {}); bool dump_cached_cell(td::Slice hash_pfx, td::Slice type_name = {});

View file

@ -80,7 +80,7 @@
TRY_RESULT_PREFIX_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result, prefix) TRY_RESULT_PREFIX_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result, prefix)
#define TRY_RESULT_PREFIX_ASSIGN(name, result, prefix) \ #define TRY_RESULT_PREFIX_ASSIGN(name, result, prefix) \
TRY_RESULT_PREFIX_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result, prefix) TRY_RESULT_PREFIX_IMPL(TD_CONCAT(r_response, __LINE__), name, result, prefix)
#define TRY_RESULT_PROMISE_PREFIX(promise_name, name, result, prefix) \ #define TRY_RESULT_PROMISE_PREFIX(promise_name, name, result, prefix) \
TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result, prefix) TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result, prefix)

View file

@ -160,6 +160,8 @@ std::string lite_query_name_by_id(int id) {
{lite_api::liteServer_getShardBlockProof::ID, "getShardBlockProof"}, {lite_api::liteServer_getShardBlockProof::ID, "getShardBlockProof"},
{lite_api::liteServer_getOutMsgQueueSizes::ID, "getOutMsgQueueSizes"}, {lite_api::liteServer_getOutMsgQueueSizes::ID, "getOutMsgQueueSizes"},
{lite_api::liteServer_getBlockOutMsgQueueSize::ID, "getBlockOutMsgQueueSize"}, {lite_api::liteServer_getBlockOutMsgQueueSize::ID, "getBlockOutMsgQueueSize"},
{lite_api::liteServer_getDispatchQueueInfo::ID, "getDispatchQueueInfo"},
{lite_api::liteServer_getDispatchQueueMessages::ID, "getDispatchQueueMessages"},
{lite_api::liteServer_nonfinal_getCandidate::ID, "nonfinal.getCandidate"}, {lite_api::liteServer_nonfinal_getCandidate::ID, "nonfinal.getCandidate"},
{lite_api::liteServer_nonfinal_getValidatorGroups::ID, "nonfinal.getValidatorGroups"}}; {lite_api::liteServer_nonfinal_getValidatorGroups::ID, "nonfinal.getValidatorGroups"}};
auto it = names.find(id); auto it = names.find(id);

View file

@ -61,6 +61,11 @@ liteServer.lookupBlockResult id:tonNode.blockIdExt mode:# mc_block_id:tonNode.bl
liteServer.outMsgQueueSize id:tonNode.blockIdExt size:int = liteServer.OutMsgQueueSize; liteServer.outMsgQueueSize id:tonNode.blockIdExt size:int = liteServer.OutMsgQueueSize;
liteServer.outMsgQueueSizes shards:(vector liteServer.outMsgQueueSize) ext_msg_queue_size_limit:int = liteServer.OutMsgQueueSizes; liteServer.outMsgQueueSizes shards:(vector liteServer.outMsgQueueSize) ext_msg_queue_size_limit:int = liteServer.OutMsgQueueSizes;
liteServer.blockOutMsgQueueSize mode:# id:tonNode.blockIdExt size:long proof:mode.0?bytes = liteServer.BlockOutMsgQueueSize; liteServer.blockOutMsgQueueSize mode:# id:tonNode.blockIdExt size:long proof:mode.0?bytes = liteServer.BlockOutMsgQueueSize;
liteServer.accountDispatchQueueInfo addr:int256 size:long min_lt:long max_lt:long = liteServer.AccountDispatchQueueInfo;
liteServer.dispatchQueueInfo mode:# id:tonNode.blockIdExt account_dispatch_queues:(vector liteServer.accountDispatchQueueInfo) complete:Bool proof:mode.0?bytes = liteServer.DispatchQueueInfo;
liteServer.dispatchQueueMessage addr:int256 lt:long hash:int256 metadata:liteServer.transactionMetadata = liteServer.DispatchQueueMessage;
liteServer.dispatchQueueMessages mode:# id:tonNode.blockIdExt messages:(vector liteServer.dispatchQueueMessage) complete:Bool
proof:mode.0?bytes messages_boc:mode.2?bytes = liteServer.DispatchQueueMessages;
liteServer.debug.verbosity value:int = liteServer.debug.Verbosity; liteServer.debug.verbosity value:int = liteServer.debug.Verbosity;
@ -100,6 +105,9 @@ liteServer.getLibrariesWithProof id:tonNode.blockIdExt mode:# library_list:(vect
liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof; liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof;
liteServer.getOutMsgQueueSizes mode:# wc:mode.0?int shard:mode.0?long = liteServer.OutMsgQueueSizes; liteServer.getOutMsgQueueSizes mode:# wc:mode.0?int shard:mode.0?long = liteServer.OutMsgQueueSizes;
liteServer.getBlockOutMsgQueueSize mode:# id:tonNode.blockIdExt want_proof:mode.0?true = liteServer.BlockOutMsgQueueSize; liteServer.getBlockOutMsgQueueSize mode:# id:tonNode.blockIdExt want_proof:mode.0?true = liteServer.BlockOutMsgQueueSize;
liteServer.getDispatchQueueInfo mode:# id:tonNode.blockIdExt after_addr:mode.1?int256 max_accounts:int want_proof:mode.0?true = liteServer.DispatchQueueInfo;
liteServer.getDispatchQueueMessages mode:# id:tonNode.blockIdExt addr:int256 after_lt:long max_messages:int
want_proof:mode.0?true one_account:mode.1?true messages_boc:mode.2?true = liteServer.DispatchQueueMessages;
liteServer.nonfinal.getValidatorGroups mode:# wc:mode.0?int shard:mode.0?long = liteServer.nonfinal.ValidatorGroups; liteServer.nonfinal.getValidatorGroups mode:# wc:mode.0?int shard:mode.0?long = liteServer.nonfinal.ValidatorGroups;
liteServer.nonfinal.getCandidate id:liteServer.nonfinal.candidateId = liteServer.nonfinal.Candidate; liteServer.nonfinal.getCandidate id:liteServer.nonfinal.candidateId = liteServer.nonfinal.Candidate;

Binary file not shown.

View file

@ -290,6 +290,13 @@ void LiteQuery::perform() {
[&](lite_api::liteServer_getBlockOutMsgQueueSize& q) { [&](lite_api::liteServer_getBlockOutMsgQueueSize& q) {
this->perform_getBlockOutMsgQueueSize(q.mode_, create_block_id(q.id_)); this->perform_getBlockOutMsgQueueSize(q.mode_, create_block_id(q.id_));
}, },
[&](lite_api::liteServer_getDispatchQueueInfo& q) {
this->perform_getDispatchQueueInfo(q.mode_, create_block_id(q.id_), q.after_addr_, q.max_accounts_);
},
[&](lite_api::liteServer_getDispatchQueueMessages& q) {
this->perform_getDispatchQueueMessages(q.mode_, create_block_id(q.id_), q.addr_,
std::max<td::int64>(q.after_lt_, 0), q.max_messages_);
},
[&](auto& obj) { this->abort_query(td::Status::Error(ErrorCode::protoviolation, "unknown query")); })); [&](auto& obj) { this->abort_query(td::Status::Error(ErrorCode::protoviolation, "unknown query")); }));
} }
@ -3432,6 +3439,248 @@ void LiteQuery::finish_getBlockOutMsgQueueSize() {
finish_query(std::move(b)); finish_query(std::move(b));
} }
void LiteQuery::perform_getDispatchQueueInfo(int mode, BlockIdExt blkid, StdSmcAddress after_addr, int max_accounts) {
LOG(INFO) << "started a getDispatchQueueInfo(" << blkid.to_str() << ", " << mode << ") liteserver query";
mode_ = mode;
if (!blkid.is_valid_full()) {
fatal_error("invalid BlockIdExt");
return;
}
if (max_accounts <= 0) {
fatal_error("invalid max_accounts");
return;
}
set_continuation([=]() -> void { finish_getDispatchQueueInfo(after_addr, max_accounts); });
request_block_data_state(blkid);
}
void LiteQuery::finish_getDispatchQueueInfo(StdSmcAddress after_addr, int max_accounts) {
LOG(INFO) << "completing getDispatchQueueInfo() query";
bool with_proof = mode_ & 1;
Ref<vm::Cell> state_root = state_->root_cell();
vm::MerkleProofBuilder pb;
if (with_proof) {
pb = vm::MerkleProofBuilder{state_root};
state_root = pb.root();
}
std::unique_ptr<vm::AugmentedDictionary> dispatch_queue;
block::gen::ShardStateUnsplit::Record sstate;
block::gen::OutMsgQueueInfo::Record out_msg_queue_info;
block::gen::OutMsgQueueExtra::Record out_msg_queue_extra;
if (!tlb::unpack_cell(state_root, sstate) || !tlb::unpack_cell(sstate.out_msg_queue_info, out_msg_queue_info)) {
fatal_error("cannot unpack shard state");
return;
}
vm::CellSlice& extra_slice = out_msg_queue_info.extra.write();
if (extra_slice.fetch_long(1)) {
if (!tlb::unpack(extra_slice, out_msg_queue_extra)) {
fatal_error("cannot unpack OutMsgQueueExtra");
return;
}
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(out_msg_queue_extra.dispatch_queue, 256,
block::tlb::aug_DispatchQueue);
} else {
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(256, block::tlb::aug_DispatchQueue);
}
int remaining = std::min(max_accounts, 64);
bool complete = false;
std::vector<tl_object_ptr<lite_api::liteServer_accountDispatchQueueInfo>> result;
bool allow_eq;
if (mode_ & 2) {
allow_eq = false;
} else {
allow_eq = true;
after_addr = td::Bits256::zero();
}
while (true) {
auto value = dispatch_queue->extract_value(dispatch_queue->lookup_nearest_key(after_addr, true, allow_eq));
allow_eq = false;
if (value.is_null()) {
complete = true;
break;
}
if (remaining == 0) {
break;
}
--remaining;
StdSmcAddress addr = after_addr;
vm::Dictionary dict{64};
td::uint64 dict_size;
if (!block::unpack_account_dispatch_queue(value, dict, dict_size)) {
fatal_error(PSTRING() << "invalid account dispatch queue for account " << addr.to_hex());
return;
}
CHECK(dict_size > 0);
td::BitArray<64> min_lt, max_lt;
dict.get_minmax_key(min_lt.bits(), 64, false, false);
dict.get_minmax_key(max_lt.bits(), 64, true, false);
result.push_back(create_tl_object<lite_api::liteServer_accountDispatchQueueInfo>(addr, dict_size, min_lt.to_ulong(),
max_lt.to_ulong()));
}
td::BufferSlice proof;
if (with_proof) {
Ref<vm::Cell> proof1, proof2;
if (!make_state_root_proof(proof1)) {
return;
}
if (!pb.extract_proof_to(proof2)) {
fatal_error("unknown error creating Merkle proof");
return;
}
auto r_proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
if (r_proof.is_error()) {
fatal_error(r_proof.move_as_error());
return;
}
proof = r_proof.move_as_ok();
}
LOG(INFO) << "getDispatchQueueInfo(" << blk_id_.to_str() << ", " << mode_ << ") query completed";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_dispatchQueueInfo>(
mode_, ton::create_tl_lite_block_id(blk_id_), std::move(result), complete, std::move(proof));
finish_query(std::move(b));
}
void LiteQuery::perform_getDispatchQueueMessages(int mode, BlockIdExt blkid, StdSmcAddress addr, LogicalTime lt,
int max_messages) {
LOG(INFO) << "started a getDispatchQueueMessages(" << blkid.to_str() << ", " << mode << ") liteserver query";
mode_ = mode;
if (!blkid.is_valid_full()) {
fatal_error("invalid BlockIdExt");
return;
}
if (max_messages <= 0) {
fatal_error("invalid max_messages");
return;
}
set_continuation([=]() -> void { finish_getDispatchQueueMessages(addr, lt, max_messages); });
request_block_data_state(blkid);
}
void LiteQuery::finish_getDispatchQueueMessages(StdSmcAddress addr, LogicalTime lt, int max_messages) {
LOG(INFO) << "completing getDispatchQueueMessages() query";
bool with_proof = mode_ & lite_api::liteServer_getDispatchQueueMessages::WANT_PROOF_MASK;
bool one_account = mode_ & lite_api::liteServer_getDispatchQueueMessages::ONE_ACCOUNT_MASK;
bool with_messages_boc = mode_ & lite_api::liteServer_getDispatchQueueMessages::MESSAGES_BOC_MASK;
Ref<vm::Cell> state_root = state_->root_cell();
vm::MerkleProofBuilder pb;
if (with_proof) {
pb = vm::MerkleProofBuilder{state_root};
state_root = pb.root();
}
std::unique_ptr<vm::AugmentedDictionary> dispatch_queue;
block::gen::ShardStateUnsplit::Record sstate;
block::gen::OutMsgQueueInfo::Record out_msg_queue_info;
block::gen::OutMsgQueueExtra::Record out_msg_queue_extra;
if (!tlb::unpack_cell(state_root, sstate) || !tlb::unpack_cell(sstate.out_msg_queue_info, out_msg_queue_info)) {
fatal_error("cannot unpack shard state");
return;
}
vm::CellSlice& extra_slice = out_msg_queue_info.extra.write();
if (extra_slice.fetch_long(1)) {
if (!tlb::unpack(extra_slice, out_msg_queue_extra)) {
fatal_error("cannot unpack OutMsgQueueExtra");
return;
}
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(out_msg_queue_extra.dispatch_queue, 256,
block::tlb::aug_DispatchQueue);
} else {
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(256, block::tlb::aug_DispatchQueue);
}
int remaining = std::min(max_messages, with_messages_boc ? 16 : 64);
bool complete = false;
std::vector<tl_object_ptr<lite_api::liteServer_dispatchQueueMessage>> result;
std::vector<td::Ref<vm::Cell>> message_roots;
td::Bits256 orig_addr = addr;
bool first = true;
while (remaining > 0) {
auto value = dispatch_queue->extract_value(dispatch_queue->lookup_nearest_key(addr, true, first));
if (value.is_null() || (one_account && addr != orig_addr)) {
complete = true;
break;
}
vm::Dictionary account_queue{64};
td::uint64 dict_size;
if (!block::unpack_account_dispatch_queue(value, account_queue, dict_size)) {
fatal_error(PSTRING() << "invalid account dispatch queue for account " << addr.to_hex());
return;
}
CHECK(dict_size > 0);
while (true) {
td::BitArray<64> lt_key;
lt_key.store_ulong(lt);
auto value2 = account_queue.lookup_nearest_key(lt_key, true, false);
if (value2.is_null()) {
break;
}
lt = lt_key.to_ulong();
if (remaining == 0) {
break;
}
--remaining;
auto msg_env = value2->prefetch_ref();
block::tlb::MsgEnvelope::Record_std env;
if (msg_env.is_null() || !tlb::unpack_cell(msg_env, env)) {
fatal_error(PSTRING() << "invalid message in dispatch queue for account " << addr.to_hex() << ", lt " << lt);
return;
}
message_roots.push_back(env.msg);
tl_object_ptr<lite_api::liteServer_transactionMetadata> metadata_tl;
if (env.metadata) {
auto& metadata = env.metadata.value();
metadata_tl = create_tl_object<lite_api::liteServer_transactionMetadata>(
0, metadata.depth,
create_tl_object<lite_api::liteServer_accountId>(metadata.initiator_wc, metadata.initiator_addr),
metadata.initiator_lt);
} else {
metadata_tl = create_tl_object<lite_api::liteServer_transactionMetadata>(
0, -1, create_tl_object<lite_api::liteServer_accountId>(workchainInvalid, td::Bits256::zero()), -1);
}
result.push_back(create_tl_object<lite_api::liteServer_dispatchQueueMessage>(addr, lt, env.msg->get_hash().bits(),
std::move(metadata_tl)));
}
first = false;
lt = 0;
}
td::BufferSlice proof;
if (with_proof) {
Ref<vm::Cell> proof1, proof2;
if (!make_state_root_proof(proof1)) {
return;
}
if (!pb.extract_proof_to(proof2)) {
fatal_error("unknown error creating Merkle proof");
return;
}
auto r_proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
if (r_proof.is_error()) {
fatal_error(r_proof.move_as_error());
return;
}
proof = r_proof.move_as_ok();
}
td::BufferSlice messages_boc;
if (with_messages_boc) {
auto r_messages_boc = vm::std_boc_serialize_multi(std::move(message_roots));
if (r_messages_boc.is_error()) {
fatal_error(r_messages_boc.move_as_error());
return;
}
messages_boc = std::move(messages_boc);
}
LOG(INFO) << "getDispatchQueueMessages(" << blk_id_.to_str() << ", " << mode_ << ") query completed";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_dispatchQueueMessages>(
mode_, ton::create_tl_lite_block_id(blk_id_), std::move(result), complete, std::move(proof),
std::move(messages_boc));
finish_query(std::move(b));
}
void LiteQuery::perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash) { void LiteQuery::perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash) {
LOG(INFO) << "started a nonfinal.getCandidate liteserver query"; LOG(INFO) << "started a nonfinal.getCandidate liteserver query";

View file

@ -172,6 +172,11 @@ class LiteQuery : public td::actor::Actor {
void continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Ref<MasterchainState> state); void continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Ref<MasterchainState> state);
void perform_getBlockOutMsgQueueSize(int mode, BlockIdExt blkid); void perform_getBlockOutMsgQueueSize(int mode, BlockIdExt blkid);
void finish_getBlockOutMsgQueueSize(); void finish_getBlockOutMsgQueueSize();
void perform_getDispatchQueueInfo(int mode, BlockIdExt blkid, StdSmcAddress after_addr, int max_accounts);
void finish_getDispatchQueueInfo(StdSmcAddress after_addr, int max_accounts);
void perform_getDispatchQueueMessages(int mode, BlockIdExt blkid, StdSmcAddress addr, LogicalTime lt,
int max_messages);
void finish_getDispatchQueueMessages(StdSmcAddress addr, LogicalTime lt, int max_messages);
void perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash); void perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash);
void perform_nonfinal_getValidatorGroups(int mode, ShardIdFull shard); void perform_nonfinal_getValidatorGroups(int mode, ShardIdFull shard);