mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-15 04:32:21 +00:00
Merge branch 'testnet' into accelerator
This commit is contained in:
commit
09da42e38f
20 changed files with 798 additions and 19 deletions
|
@ -28,5 +28,5 @@ jobs:
|
|||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: tonlib-android
|
||||
name: ton-android-tonlib
|
||||
path: artifacts
|
||||
|
|
16
.github/workflows/create-release.yml
vendored
16
.github/workflows/create-release.yml
vendored
|
@ -83,6 +83,14 @@ jobs:
|
|||
workflow_conclusion: success
|
||||
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
|
||||
run: |
|
||||
tree artifacts
|
||||
|
@ -501,3 +509,11 @@ jobs:
|
|||
file: artifacts/ton-wasm-binaries.zip
|
||||
asset_name: ton-wasm-binaries.zip
|
||||
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 }}
|
||||
|
|
|
@ -192,8 +192,6 @@ if [ "$with_artifacts" = true ]; then
|
|||
echo Creating artifacts...
|
||||
rm -rf 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-cli artifacts/
|
||||
cp build/blockchain-explorer/blockchain-explorer artifacts/
|
||||
|
@ -213,9 +211,9 @@ if [ "$with_artifacts" = true ]; then
|
|||
cp build/utils/json2tlo artifacts/
|
||||
cp build/adnl/adnl-proxy artifacts/
|
||||
cp build/emulator/libemulator.dylib artifacts/
|
||||
chmod +x artifacts/*
|
||||
rsync -r crypto/smartcont artifacts/
|
||||
rsync -r crypto/fift/lib artifacts/
|
||||
chmod -R +x artifacts/*
|
||||
fi
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
|
|
|
@ -140,9 +140,9 @@ if [ "$with_artifacts" = true ]; then
|
|||
cp build/utils/json2tlo artifacts/
|
||||
cp build/adnl/adnl-proxy artifacts/
|
||||
cp build/emulator/libemulator.dylib artifacts/
|
||||
chmod +x artifacts/*
|
||||
rsync -r crypto/smartcont artifacts/
|
||||
rsync -r crypto/fift/lib artifacts/
|
||||
cp -R crypto/smartcont artifacts/
|
||||
cp -R crypto/fift/lib artifacts/
|
||||
chmod -R +x artifacts/*
|
||||
fi
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
|
|
|
@ -193,8 +193,6 @@ cd ..
|
|||
if [ "$with_artifacts" = true ]; then
|
||||
rm -rf artifacts
|
||||
mkdir artifacts
|
||||
cp crypto/fift/lib artifacts/
|
||||
cp -R crypto/smartcont/ artifacts/
|
||||
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 \
|
||||
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 \
|
||||
artifacts
|
||||
test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; }
|
||||
chmod +x artifacts/*
|
||||
cp -R crypto/smartcont artifacts
|
||||
cp -R crypto/fift/lib artifacts
|
||||
chmod -R +x artifacts/*
|
||||
fi
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
|
|
|
@ -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 \
|
||||
artifacts
|
||||
test $? -eq 0 || { echo "Can't copy final binaries"; exit 1; }
|
||||
chmod +x artifacts/*
|
||||
cp -R crypto/smartcont artifacts
|
||||
cp -R crypto/fift/lib artifacts
|
||||
chmod -R +x artifacts/*
|
||||
fi
|
||||
|
||||
if [ "$with_tests" = true ]; then
|
||||
|
|
|
@ -35,3 +35,4 @@ cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
|
|||
cp ./result/lib/libemulator.so artifacts/
|
||||
cp ./result/lib/fift/* artifacts/lib/
|
||||
cp -r ./result/share/ton/smartcont artifacts/
|
||||
chmod -R +x artifacts
|
||||
|
|
|
@ -35,3 +35,4 @@ cp ./result/lib/libtonlibjson.so.0.5 artifacts/libtonlibjson.so
|
|||
cp ./result/lib/libemulator.so artifacts/
|
||||
cp ./result/lib/fift/* artifacts/lib/
|
||||
cp -r ./result/share/ton/smartcont artifacts/
|
||||
chmod -R +x artifacts
|
||||
|
|
|
@ -35,3 +35,4 @@ cp ./result/lib/libtonlibjson.dylib artifacts/
|
|||
cp ./result/lib/libemulator.dylib artifacts/
|
||||
cp ./result/lib/fift/* artifacts/lib/
|
||||
cp -r ./result/share/ton/smartcont artifacts/
|
||||
chmod -R +x artifacts
|
||||
|
|
|
@ -433,6 +433,14 @@ if (WINGETOPT_FOUND)
|
|||
target_link_libraries_system(pow-miner wingetopt)
|
||||
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 .)
|
||||
if (TON_USE_ASAN AND NOT WIN32)
|
||||
set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0)
|
||||
|
|
395
crypto/util/mintless-proof-generator.cpp
Normal file
395
crypto/util/mintless-proof-generator.cpp
Normal 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 << "'";
|
||||
}
|
|
@ -167,7 +167,7 @@ td::Result<Ref<Cell>> StaticBagOfCellsDb::create_ext_cell(Cell::LevelMask level_
|
|||
//
|
||||
class StaticBagOfCellsDbBaselineImpl : public StaticBagOfCellsDb {
|
||||
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 {
|
||||
return roots_.size();
|
||||
|
@ -233,7 +233,7 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
return create_root_cell(std::move(data_cell));
|
||||
};
|
||||
|
||||
~StaticBagOfCellsDbLazyImpl() {
|
||||
~StaticBagOfCellsDbLazyImpl() override {
|
||||
//LOG(ERROR) << deserialize_cell_cnt_ << " " << deserialize_cell_hash_cnt_;
|
||||
get_thread_safe_counter().add(-1);
|
||||
}
|
||||
|
@ -314,11 +314,11 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
td::RwMutex::ReadLock guard;
|
||||
if (info_.has_index) {
|
||||
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;
|
||||
} else {
|
||||
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);
|
||||
|
@ -332,7 +332,7 @@ class StaticBagOfCellsDbLazyImpl : public StaticBagOfCellsDb {
|
|||
}
|
||||
char arr[8];
|
||||
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);
|
||||
return info_.read_ref(idx_view.ubegin());
|
||||
}
|
||||
|
|
|
@ -957,6 +957,11 @@ bool TestNode::show_help(std::string command) {
|
|||
"into files <filename-pfx><complaint-hash>.boc\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"
|
||||
"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"
|
||||
"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"
|
||||
|
@ -971,9 +976,9 @@ bool TestNode::show_help(std::string command) {
|
|||
bool TestNode::do_parse_line() {
|
||||
ton::WorkchainId workchain = ton::masterchainId; // change to basechain later
|
||||
int addr_ext = 0;
|
||||
ton::StdSmcAddress addr{};
|
||||
ton::StdSmcAddress addr = ton::StdSmcAddress::zero();
|
||||
ton::BlockIdExt blkid{};
|
||||
ton::LogicalTime lt{};
|
||||
ton::LogicalTime lt = 0;
|
||||
ton::Bits256 hash{};
|
||||
ton::ShardIdFull shard{};
|
||||
ton::BlockSeqno seqno{};
|
||||
|
@ -1101,6 +1106,16 @@ bool TestNode::do_parse_line() {
|
|||
set_error(get_complaint_price(expire_in, filename));
|
||||
} else if (word == "msgqueuesizes") {
|
||||
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") {
|
||||
return eoln() && show_new_blkids(true);
|
||||
} 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;
|
||||
}
|
||||
|
||||
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,
|
||||
std::string domain, td::Bits256 cat, int mode) {
|
||||
if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') {
|
||||
|
|
|
@ -305,6 +305,13 @@ class TestNode : public td::actor::Actor {
|
|||
unsigned refs, td::Bits256 chash, std::string filename);
|
||||
bool get_msg_queue_sizes();
|
||||
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 list_cached_cells() const;
|
||||
bool dump_cached_cell(td::Slice hash_pfx, td::Slice type_name = {});
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
TRY_RESULT_PREFIX_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto 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) \
|
||||
TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result, prefix)
|
||||
|
|
|
@ -160,6 +160,8 @@ std::string lite_query_name_by_id(int id) {
|
|||
{lite_api::liteServer_getShardBlockProof::ID, "getShardBlockProof"},
|
||||
{lite_api::liteServer_getOutMsgQueueSizes::ID, "getOutMsgQueueSizes"},
|
||||
{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_getValidatorGroups::ID, "nonfinal.getValidatorGroups"}};
|
||||
auto it = names.find(id);
|
||||
|
|
|
@ -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.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.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;
|
||||
|
||||
|
@ -100,6 +105,9 @@ liteServer.getLibrariesWithProof id:tonNode.blockIdExt mode:# library_list:(vect
|
|||
liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof;
|
||||
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.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.getCandidate id:liteServer.nonfinal.candidateId = liteServer.nonfinal.Candidate;
|
||||
|
|
Binary file not shown.
|
@ -290,6 +290,13 @@ void LiteQuery::perform() {
|
|||
[&](lite_api::liteServer_getBlockOutMsgQueueSize& q) {
|
||||
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")); }));
|
||||
}
|
||||
|
||||
|
@ -3432,6 +3439,248 @@ void LiteQuery::finish_getBlockOutMsgQueueSize() {
|
|||
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) {
|
||||
LOG(INFO) << "started a nonfinal.getCandidate liteserver query";
|
||||
|
|
|
@ -172,6 +172,11 @@ class LiteQuery : public td::actor::Actor {
|
|||
void continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Ref<MasterchainState> state);
|
||||
void perform_getBlockOutMsgQueueSize(int mode, BlockIdExt blkid);
|
||||
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_getValidatorGroups(int mode, ShardIdFull shard);
|
||||
|
|
Loading…
Reference in a new issue