mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-14 12:12:21 +00:00
updated block header
1. Updated block header, proofs now contain more data Notice, that old proofs may become invalid in the future 2. Fixed message routing 3. Fixed block creator id in block header 4. Support for full proofs in tonlib 5. Support for partial state download 6. Some other bugfixes
This commit is contained in:
parent
bce33f588a
commit
13140ddf29
73 changed files with 2084 additions and 304 deletions
|
@ -9,6 +9,7 @@ set(TON_CRYPTO_SOURCE
|
|||
common/bigint.cpp
|
||||
common/refcnt.cpp
|
||||
common/refint.cpp
|
||||
common/bigexp.cpp
|
||||
common/bitstring.cpp
|
||||
common/util.cpp
|
||||
ellcurve/Ed25519.cpp
|
||||
|
@ -42,6 +43,7 @@ set(TON_CRYPTO_SOURCE
|
|||
common/bitstring.h
|
||||
common/refcnt.hpp
|
||||
common/refint.h
|
||||
common/bigexp.h
|
||||
common/util.h
|
||||
|
||||
ellcurve/Ed25519.h
|
||||
|
@ -227,7 +229,7 @@ target_link_libraries(ton_crypto PUBLIC ${OPENSSL_CRYPTO_LIBRARY} tdutils)
|
|||
if (NOT WIN32)
|
||||
target_link_libraries(ton_crypto PUBLIC dl z)
|
||||
endif()
|
||||
target_include_directories(ton_crypto SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
target_include_directories(ton_crypto SYSTEM PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
|
||||
|
||||
add_library(ton_db STATIC ${TON_DB_SOURCE})
|
||||
target_include_directories(ton_db PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
|
@ -324,10 +326,10 @@ if (WINGETOPT_FOUND)
|
|||
target_link_libraries_system(create-state wingetopt)
|
||||
endif()
|
||||
|
||||
add_executable(test-block block/test-block.cpp)
|
||||
target_include_directories(test-block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
add_executable(dump-block block/dump-block.cpp)
|
||||
target_include_directories(dump-block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(test-block PUBLIC ton_crypto fift-lib ton_block)
|
||||
target_link_libraries(dump-block PUBLIC ton_crypto fift-lib ton_block)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(test-block wingetopt)
|
||||
target_link_libraries_system(dump-block wingetopt)
|
||||
endif()
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "block/block-auto.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "common/bigexp.h"
|
||||
#include "common/util.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/tl_storers.h"
|
||||
|
@ -367,14 +368,14 @@ std::unique_ptr<MsgProcessedUptoCollection> MsgProcessedUptoCollection::unpack(t
|
|||
return v && v->valid ? std::move(v) : std::unique_ptr<MsgProcessedUptoCollection>{};
|
||||
}
|
||||
|
||||
bool MsgProcessedUpto::contains(const MsgProcessedUpto& other) const& {
|
||||
bool MsgProcessedUpto::contains(const MsgProcessedUpto& other) const & {
|
||||
return ton::shard_is_ancestor(shard, other.shard) && mc_seqno >= other.mc_seqno &&
|
||||
(last_inmsg_lt > other.last_inmsg_lt ||
|
||||
(last_inmsg_lt == other.last_inmsg_lt && !(last_inmsg_hash < other.last_inmsg_hash)));
|
||||
}
|
||||
|
||||
bool MsgProcessedUpto::contains(ton::ShardId other_shard, ton::LogicalTime other_lt, td::ConstBitPtr other_hash,
|
||||
ton::BlockSeqno other_mc_seqno) const& {
|
||||
ton::BlockSeqno other_mc_seqno) const & {
|
||||
return ton::shard_is_ancestor(shard, other_shard) && mc_seqno >= other_mc_seqno &&
|
||||
(last_inmsg_lt > other_lt || (last_inmsg_lt == other_lt && !(last_inmsg_hash < other_hash)));
|
||||
}
|
||||
|
@ -788,6 +789,14 @@ td::Status ShardState::unpack_state(ton::BlockIdExt blkid, Ref<vm::Cell> prev_st
|
|||
if (!global_balance_.validate_unpack(extra.global_balance)) {
|
||||
return td::Status::Error(-666, "ShardState of "s + id_.to_str() + " does not contain a valid global_balance");
|
||||
}
|
||||
if (extra.r1.flags & 1) {
|
||||
if (extra.r1.block_create_stats->prefetch_ulong(8) != 0x17) {
|
||||
return td::Status::Error(-666, "ShardState of "s + id_.to_str() + " does not contain a valid BlockCreateStats");
|
||||
}
|
||||
block_create_stats_ = std::make_unique<vm::Dictionary>(extra.r1.block_create_stats->prefetch_ref(), 256);
|
||||
} else {
|
||||
block_create_stats_ = std::make_unique<vm::Dictionary>(256);
|
||||
}
|
||||
}
|
||||
return unpack_out_msg_queue_info(std::move(state.out_msg_queue_info));
|
||||
}
|
||||
|
@ -1387,6 +1396,114 @@ std::ostream& operator<<(std::ostream& os, const ValueFlow& vflow) {
|
|||
return os;
|
||||
}
|
||||
|
||||
bool DiscountedCounter::increase_by(unsigned count, ton::UnixTime now) {
|
||||
if (!validate()) {
|
||||
return false;
|
||||
}
|
||||
td::uint64 scaled = (td::uint64(count) << 32);
|
||||
if (!total) {
|
||||
last_updated = now;
|
||||
total = count;
|
||||
cnt2048 = scaled;
|
||||
cnt65536 = scaled;
|
||||
return true;
|
||||
}
|
||||
if (count > ~total || cnt2048 > ~scaled || cnt65536 > ~scaled) {
|
||||
return false /* invalidate() */; // overflow
|
||||
}
|
||||
unsigned dt = (now >= last_updated ? now - last_updated : 0);
|
||||
if (dt > 0) {
|
||||
// more precise version of cnt2048 = llround(cnt2048 * exp(-dt / 2048.));
|
||||
// (rounding error has absolute value < 1)
|
||||
cnt2048 = (dt >= 48 * 2048 ? 0 : td::umulnexps32(cnt2048, dt << 5));
|
||||
// more precise version of cnt65536 = llround(cnt65536 * exp(-dt / 65536.));
|
||||
// (rounding error has absolute value < 1)
|
||||
cnt65536 = td::umulnexps32(cnt65536, dt);
|
||||
}
|
||||
total += count;
|
||||
cnt2048 += scaled;
|
||||
cnt65536 += scaled;
|
||||
last_updated = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiscountedCounter::validate() {
|
||||
if (!is_valid()) {
|
||||
return false;
|
||||
}
|
||||
if (!total) {
|
||||
if (cnt2048 | cnt65536) {
|
||||
return invalidate();
|
||||
}
|
||||
} else if (!last_updated) {
|
||||
return invalidate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiscountedCounter::fetch(vm::CellSlice& cs) {
|
||||
valid = (cs.fetch_uint_to(32, last_updated) && cs.fetch_uint_to(64, total) && cs.fetch_uint_to(64, cnt2048) &&
|
||||
cs.fetch_uint_to(64, cnt65536));
|
||||
return validate() || invalidate();
|
||||
}
|
||||
|
||||
bool DiscountedCounter::unpack(Ref<vm::CellSlice> csr) {
|
||||
return (csr.not_null() && fetch(csr.write()) && csr->empty_ext()) || invalidate();
|
||||
}
|
||||
|
||||
bool DiscountedCounter::store(vm::CellBuilder& cb) const {
|
||||
return is_valid() && cb.store_long_bool(last_updated, 32) && cb.store_long_bool(total, 64) &&
|
||||
cb.store_long_bool(cnt2048, 64) && cb.store_long_bool(cnt65536, 64);
|
||||
}
|
||||
|
||||
Ref<vm::CellSlice> DiscountedCounter::pack() const {
|
||||
vm::CellBuilder cb;
|
||||
if (store(cb)) {
|
||||
return vm::load_cell_slice_ref(cb.finalize());
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool DiscountedCounter::show(std::ostream& os) const {
|
||||
if (!is_valid()) {
|
||||
os << "<invalid-counter>";
|
||||
return false;
|
||||
}
|
||||
os << "(counter last_updated:" << last_updated << " total:" << total << " cnt2048: " << (double)cnt2048 / (1LL << 32)
|
||||
<< " cnt65536: " << (double)cnt65536 / (1LL << 32) << ")";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string DiscountedCounter::to_str() const {
|
||||
std::ostringstream stream;
|
||||
if (show(stream)) {
|
||||
return stream.str();
|
||||
} else {
|
||||
return "<invalid-counter>";
|
||||
}
|
||||
}
|
||||
|
||||
bool fetch_CreatorStats(vm::CellSlice& cs, DiscountedCounter& mc_cnt, DiscountedCounter& shard_cnt) {
|
||||
return cs.fetch_ulong(4) == 4 // creator_info#4
|
||||
&& mc_cnt.fetch(cs) // mc_blocks:Counters
|
||||
&& shard_cnt.fetch(cs); // shard_blocks:Counters
|
||||
}
|
||||
|
||||
bool store_CreatorStats(vm::CellBuilder& cb, const DiscountedCounter& mc_cnt, const DiscountedCounter& shard_cnt) {
|
||||
return cb.store_long_bool(4, 4) // creator_info#4
|
||||
&& mc_cnt.store(cb) // mc_blocks:Counters
|
||||
&& shard_cnt.store(cb); // shard_blocks:Counters
|
||||
}
|
||||
|
||||
bool unpack_CreatorStats(Ref<vm::CellSlice> cs, DiscountedCounter& mc_cnt, DiscountedCounter& shard_cnt) {
|
||||
if (cs.is_null()) {
|
||||
return mc_cnt.set_zero() && shard_cnt.set_zero();
|
||||
} else {
|
||||
return fetch_CreatorStats(cs.write(), mc_cnt, shard_cnt) && cs->empty_ext();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Other block-related functions
|
||||
|
@ -1565,8 +1682,8 @@ std::pair<int, int> perform_hypercube_routing(ton::AccountIdPrefixFull src, ton:
|
|||
if (!ton::shard_contains(cur, transit)) {
|
||||
return {-1, -1};
|
||||
}
|
||||
if (transit.account_id_prefix == dest.account_id_prefix || ton::shard_contains(cur, dest)) {
|
||||
// if destination is already reached, or is in this shard, set cur:=next_hop:=dest
|
||||
if (ton::shard_contains(cur, dest)) {
|
||||
// if destination is in this shard, set cur:=next_hop:=dest
|
||||
return {96, 96};
|
||||
}
|
||||
if (transit.workchain == ton::masterchainId || dest.workchain == ton::masterchainId) {
|
||||
|
|
|
@ -159,12 +159,12 @@ struct MsgProcessedUpto {
|
|||
MsgProcessedUpto(ton::ShardId _shard, ton::BlockSeqno _mcseqno, ton::LogicalTime _lt, td::ConstBitPtr _hash)
|
||||
: shard(_shard), mc_seqno(_mcseqno), last_inmsg_lt(_lt), last_inmsg_hash(_hash) {
|
||||
}
|
||||
bool operator<(const MsgProcessedUpto& other) const& {
|
||||
bool operator<(const MsgProcessedUpto& other) const & {
|
||||
return shard < other.shard || (shard == other.shard && mc_seqno < other.mc_seqno);
|
||||
}
|
||||
bool contains(const MsgProcessedUpto& other) const&;
|
||||
bool contains(const MsgProcessedUpto& other) const &;
|
||||
bool contains(ton::ShardId other_shard, ton::LogicalTime other_lt, td::ConstBitPtr other_hash,
|
||||
ton::BlockSeqno other_mc_seqno) const&;
|
||||
ton::BlockSeqno other_mc_seqno) const &;
|
||||
// NB: this is for checking whether we have already imported an internal message
|
||||
bool already_processed(const EnqueuedMsgDescr& msg) const;
|
||||
};
|
||||
|
@ -392,6 +392,7 @@ struct ShardState {
|
|||
CurrencyCollection total_balance_, total_validator_fees_, global_balance_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> out_msg_queue_;
|
||||
std::unique_ptr<vm::Dictionary> ihr_pending_;
|
||||
std::unique_ptr<vm::Dictionary> block_create_stats_;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> processed_upto_;
|
||||
|
||||
bool is_valid() const {
|
||||
|
@ -467,6 +468,67 @@ struct ValueFlow {
|
|||
|
||||
std::ostream& operator<<(std::ostream& os, const ValueFlow& vflow);
|
||||
|
||||
struct DiscountedCounter {
|
||||
struct SetZero {};
|
||||
bool valid;
|
||||
ton::UnixTime last_updated;
|
||||
td::uint64 total;
|
||||
td::uint64 cnt2048;
|
||||
td::uint64 cnt65536;
|
||||
DiscountedCounter() : valid(false) {
|
||||
}
|
||||
DiscountedCounter(SetZero) : valid(true), last_updated(0), total(0), cnt2048(0), cnt65536(0) {
|
||||
}
|
||||
DiscountedCounter(ton::UnixTime _lastupd, td::uint64 _total, td::uint64 _cnt2048, td::uint64 _cnt65536)
|
||||
: valid(true), last_updated(_lastupd), total(_total), cnt2048(_cnt2048), cnt65536(_cnt65536) {
|
||||
}
|
||||
static DiscountedCounter Zero() {
|
||||
return SetZero();
|
||||
}
|
||||
bool is_valid() const {
|
||||
return valid;
|
||||
}
|
||||
bool invalidate() {
|
||||
return (valid = false);
|
||||
}
|
||||
bool set_zero() {
|
||||
last_updated = 0;
|
||||
total = cnt2048 = cnt65536 = 0;
|
||||
return (valid = true);
|
||||
}
|
||||
bool is_zero() const {
|
||||
return !total;
|
||||
}
|
||||
bool almost_zero() const {
|
||||
return (cnt2048 | cnt65536) <= 1;
|
||||
}
|
||||
bool operator==(const DiscountedCounter& other) const {
|
||||
return last_updated == other.last_updated && total == other.total && cnt2048 == other.cnt2048 &&
|
||||
cnt65536 == other.cnt65536;
|
||||
}
|
||||
bool almost_equals(const DiscountedCounter& other) const {
|
||||
return last_updated == other.last_updated && total == other.total && cnt2048 <= other.cnt2048 + 1 &&
|
||||
other.cnt2048 <= cnt2048 + 1 && cnt65536 <= other.cnt65536 + 1 && other.cnt65536 <= cnt65536 + 1;
|
||||
}
|
||||
bool validate();
|
||||
bool increase_by(unsigned count, ton::UnixTime now);
|
||||
bool fetch(vm::CellSlice& cs);
|
||||
bool unpack(Ref<vm::CellSlice> csr);
|
||||
bool store(vm::CellBuilder& cb) const;
|
||||
Ref<vm::CellSlice> pack() const;
|
||||
bool show(std::ostream& os) const;
|
||||
std::string to_str() const;
|
||||
};
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, const DiscountedCounter& dcount) {
|
||||
dcount.show(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
bool fetch_CreatorStats(vm::CellSlice& cs, DiscountedCounter& mc_cnt, DiscountedCounter& shard_cnt);
|
||||
bool store_CreatorStats(vm::CellBuilder& cb, const DiscountedCounter& mc_cnt, const DiscountedCounter& shard_cnt);
|
||||
bool unpack_CreatorStats(Ref<vm::CellSlice> cs, DiscountedCounter& mc_cnt, DiscountedCounter& shard_cnt);
|
||||
|
||||
struct BlockProofLink {
|
||||
ton::BlockIdExt from, to;
|
||||
bool is_key{false}, is_fwd{false};
|
||||
|
|
|
@ -499,14 +499,20 @@ _ key:Bool blk_ref:ExtBlkRef = KeyExtBlkRef;
|
|||
|
||||
_ (HashmapAugE 32 KeyExtBlkRef KeyMaxLt) = OldMcBlocksInfo;
|
||||
|
||||
|
||||
counters#_ last_updated:uint32 total:uint64 cnt2048:uint64 cnt65536:uint64 = Counters;
|
||||
creator_info#4 mc_blocks:Counters shard_blocks:Counters = CreatorStats;
|
||||
block_create_stats#17 counters:(HashmapE 256 CreatorStats) = BlockCreateStats;
|
||||
|
||||
masterchain_state_extra#cc26
|
||||
shard_hashes:ShardHashes
|
||||
config:ConfigParams
|
||||
^[ flags:(## 16) { flags = 0 }
|
||||
^[ flags:(## 16) { flags <= 1 }
|
||||
validator_info:ValidatorInfo
|
||||
prev_blocks:OldMcBlocksInfo
|
||||
after_key_block:Bool
|
||||
last_key_block:(Maybe ExtBlkRef) ]
|
||||
last_key_block:(Maybe ExtBlkRef)
|
||||
block_create_stats:(flags . 0)?BlockCreateStats ]
|
||||
global_balance:CurrencyCollection
|
||||
= McStateExtra;
|
||||
|
||||
|
|
|
@ -80,4 +80,15 @@ struct TransactionList {
|
|||
td::Result<Info> validate() const;
|
||||
};
|
||||
|
||||
struct BlockChain {
|
||||
ton::BlockIdExt from;
|
||||
ton::BlockIdExt to;
|
||||
td::int32 mode;
|
||||
td::BufferSlice proof;
|
||||
|
||||
using Info = std::unique_ptr<block::BlockProofChain>;
|
||||
|
||||
td::Result<Info> validate() const;
|
||||
};
|
||||
|
||||
} // namespace block
|
||||
|
|
252
crypto/block/dump-block.cpp
Normal file
252
crypto/block/dump-block.cpp
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "block/block.h"
|
||||
#include "vm/boc.h"
|
||||
#include <iostream>
|
||||
#include "block-db.h"
|
||||
#include "block-auto.h"
|
||||
#include "block-parse.h"
|
||||
#include "vm/cp0.h"
|
||||
#include <getopt.h>
|
||||
|
||||
using td::Ref;
|
||||
|
||||
int verbosity;
|
||||
|
||||
struct IntError {
|
||||
std::string err_msg;
|
||||
IntError(std::string _msg) : err_msg(_msg) {
|
||||
}
|
||||
IntError(const char* _msg) : err_msg(_msg) {
|
||||
}
|
||||
};
|
||||
|
||||
td::Ref<vm::Cell> load_boc(std::string filename) {
|
||||
std::cerr << "loading bag-of-cell file " << filename << std::endl;
|
||||
auto bytes_res = block::load_binary_file(filename);
|
||||
if (bytes_res.is_error()) {
|
||||
throw IntError{PSTRING() << "cannot load file `" << filename << "` : " << bytes_res.move_as_error()};
|
||||
}
|
||||
vm::BagOfCells boc;
|
||||
auto res = boc.deserialize(bytes_res.move_as_ok());
|
||||
if (res.is_error()) {
|
||||
throw IntError{PSTRING() << "cannot deserialize bag-of-cells " << res.move_as_error()};
|
||||
}
|
||||
if (res.move_as_ok() <= 0 || boc.get_root_cell().is_null()) {
|
||||
throw IntError{"cannot deserialize bag-of-cells "};
|
||||
}
|
||||
return boc.get_root_cell();
|
||||
}
|
||||
|
||||
void test1() {
|
||||
block::ShardId id{ton::masterchainId}, id2{ton::basechainId, 0x11efULL << 48};
|
||||
std::cout << '[' << id << "][" << id2 << ']' << std::endl;
|
||||
vm::CellBuilder cb;
|
||||
cb << id << id2;
|
||||
std::cout << "ShardIdent.pack() = " << block::tlb::t_ShardIdent.pack(cb, {12, 3, 0x3aeULL << 52}) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
auto cref = cb.finalize();
|
||||
td::Ref<vm::CellSlice> cs{true, cref}, cs2;
|
||||
block::ShardId id3{cs.write()}, id4, id5;
|
||||
cs >> id4 >> id5;
|
||||
std::cout << '[' << id3 << "][" << id4 << "][" << id5 << ']' << std::endl;
|
||||
vm::CellSlice csl{std::move(cref)};
|
||||
std::cout << "ShardIdent.get_size() = " << block::tlb::t_ShardIdent.get_size(csl) << std::endl;
|
||||
std::cout << "MsgAddress.get_size() = " << block::tlb::t_MsgAddress.get_size(csl) << std::endl;
|
||||
std::cout << "Grams.get_size() = " << block::tlb::t_Grams.get_size(csl) << std::endl;
|
||||
std::cout << "Grams.as_integer() = " << block::tlb::t_Grams.as_integer(csl) << std::endl;
|
||||
(csl + 8).print_rec(std::cout);
|
||||
std::cout << "Grams.get_size() = " << block::tlb::t_Grams.get_size(csl + 8) << std::endl;
|
||||
std::cout << "Grams.as_integer() = " << block::tlb::t_Grams.as_integer(csl + 8) << std::endl;
|
||||
|
||||
vm::CellSlice csl2{csl};
|
||||
block::gen::ShardIdent::Record sh_id;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::cout << csl2 << std::endl;
|
||||
bool ok = tlb::unpack(csl2, sh_id);
|
||||
std::cout << "block::gen::ShardIdent.unpack() = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " (shard_ident shard_pfx_bits:" << sh_id.shard_pfx_bits << " workchain_id:" << sh_id.workchain_id
|
||||
<< " shard_prefix:" << std::hex << sh_id.shard_prefix << std::dec << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
block::tlb::ShardIdent::Record shard_id;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::cout << "ShardIdent.validate() = " << block::tlb::t_ShardIdent.validate(csl) << std::endl;
|
||||
csl.print_rec(std::cerr);
|
||||
csl.dump(std::cerr, 7);
|
||||
std::cout << "ShardIdent.unpack() = " << block::tlb::t_ShardIdent.unpack(csl, shard_id) << std::endl;
|
||||
if (shard_id.is_valid()) {
|
||||
std::cout << "shard_pfx_bits:" << shard_id.shard_pfx_bits << " workchain_id:" << shard_id.workchain_id
|
||||
<< " shard_prefix:" << shard_id.shard_prefix << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
using namespace td::literals;
|
||||
std::cout << "Grams.store_intval(239) = " << block::tlb::t_Grams.store_integer_value(cb, "239"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(17239) = " << block::tlb::t_Grams.store_integer_value(cb, "17239"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(-17) = " << block::tlb::t_Grams.store_integer_value(cb, "-17"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(0) = " << block::tlb::t_Grams.store_integer_value(cb, "0"_i256) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
cs = td::Ref<vm::CellSlice>{true, cb.finalize()};
|
||||
std::cout << "Grams.store_intval(666) = " << block::tlb::t_Grams.store_integer_value(cb, "666"_i256) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
cs2 = td::Ref<vm::CellSlice>{true, cb.finalize()};
|
||||
std::cout << "Grams.validate(cs) = " << block::tlb::t_Grams.validate(*cs) << std::endl;
|
||||
std::cout << "Grams.validate(cs2) = " << block::tlb::t_Grams.validate(*cs2) << std::endl;
|
||||
//
|
||||
block::gen::SplitMergeInfo::Record data;
|
||||
block::gen::Grams::Record data2;
|
||||
std::cout << "block::gen::Grams.validate(cs) = " << block::gen::t_Grams.validate(*cs) << std::endl;
|
||||
std::cout << "block::gen::Grams.validate(cs2) = " << block::gen::t_Grams.validate(*cs2) << std::endl;
|
||||
std::cout << "[cs = " << cs << "]" << std::endl;
|
||||
bool ok = tlb::csr_unpack_inexact(cs, data);
|
||||
std::cout << "block::gen::SplitMergeInfo.unpack(cs, data) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " cur_shard_pfx_len = " << data.cur_shard_pfx_len << "; acc_split_depth = " << data.acc_split_depth
|
||||
<< "; this_addr = " << data.this_addr << "; sibling_addr = " << data.sibling_addr << std::endl;
|
||||
}
|
||||
ok = tlb::csr_unpack_inexact(cs, data2);
|
||||
std::cout << "block::gen::Grams.unpack(cs, data2) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " amount = " << data2.amount << std::endl;
|
||||
block::gen::VarUInteger::Record data3;
|
||||
ok = tlb::csr_type_unpack(data2.amount, block::gen::t_VarUInteger_16, data3);
|
||||
std::cout << " block::gen::VarUInteger16.unpack(amount, data3) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " len = " << data3.len << "; value = " << data3.value << std::endl;
|
||||
vm::CellBuilder cb;
|
||||
std::cout << " block::gen::VarUInteger16.pack(cb, data3) = "
|
||||
<< tlb::type_pack(cb, block::gen::t_VarUInteger_16, data3) << std::endl;
|
||||
std::cout << " cb = " << cb.finalize() << std::endl;
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
vm::CellBuilder cb;
|
||||
td::BitArray<256> hash;
|
||||
std::memset(hash.data(), 0x69, 32);
|
||||
bool ok = tlb::pack(
|
||||
cb, block::gen::Test::Record{1000000000000, {170239, -888, {239017, "1000000000000000000"_ri256}, hash}, 17});
|
||||
std::cout << " block::gen::Test::pack(cb, {1000000000000, ...}) = " << ok << std::endl;
|
||||
std::cout << " cb = " << cb << std::endl;
|
||||
auto cell = cb.finalize();
|
||||
vm::CellSlice cs{cell};
|
||||
cs.print_rec(std::cout);
|
||||
block::gen::Test::Record data;
|
||||
std::cout << " block::gen::Test::validate_ref(cell) = " << block::gen::t_Test.validate_ref(cell) << std::endl;
|
||||
ok = tlb::unpack(cs, data);
|
||||
std::cout << " block::gen::Test::unpack(cs, data) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << "a:" << data.a << " b:" << data.r1.b << " c:" << data.r1.c << " d:" << data.r1.r1.d
|
||||
<< " e:" << data.r1.r1.e << " f:" << data.r1.f << " g:" << data.g << std::endl;
|
||||
}
|
||||
std::cout << " block::gen::Test::print_ref(cell) = ";
|
||||
block::gen::t_Test.print_ref(std::cout, cell, 2);
|
||||
block::gen::t_CurrencyCollection.print_ref(std::cout, cell, 2);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
*/
|
||||
std::cout << "Grams.add_values() = " << block::tlb::t_Grams.add_values(cb, cs.write(), cs2.write()) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
std::cout << "block::gen::t_HashmapAug_64_...print_type() = "
|
||||
<< block::gen::t_HashmapAug_64_Ref_Transaction_CurrencyCollection << std::endl;
|
||||
}
|
||||
|
||||
void test2(vm::CellSlice& cs) {
|
||||
std::cout << "Bool.validate() = " << block::tlb::t_Bool.validate(cs) << std::endl;
|
||||
std::cout << "UInt16.validate() = " << block::tlb::t_uint16.validate(cs) << std::endl;
|
||||
std::cout << "HashmapE(32,UInt16).validate() = " << block::tlb::HashmapE(32, block::tlb::t_uint16).validate(cs)
|
||||
<< std::endl;
|
||||
std::cout << "block::gen::HashmapE(32,UInt16).validate() = "
|
||||
<< block::gen::HashmapE{32, block::gen::t_uint16}.validate(cs) << std::endl;
|
||||
}
|
||||
|
||||
void usage() {
|
||||
std::cout << "usage: test-block [-S][<boc-file>]\n\tor test-block -h\n\tDumps specified blockchain block or state "
|
||||
"from <boc-file>, or runs some tests\n\t-S\tDump a blockchain state\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char* const argv[]) {
|
||||
int i;
|
||||
int new_verbosity_level = VERBOSITY_NAME(INFO);
|
||||
bool dump_state = false;
|
||||
auto zerostate = std::make_unique<block::ZerostateInfo>();
|
||||
while ((i = getopt(argc, argv, "Shv:")) != -1) {
|
||||
switch (i) {
|
||||
case 'S':
|
||||
dump_state = true;
|
||||
break;
|
||||
case 'v':
|
||||
new_verbosity_level = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer<int>(td::Slice(optarg)));
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
std::exit(2);
|
||||
default:
|
||||
usage();
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
SET_VERBOSITY_LEVEL(new_verbosity_level);
|
||||
try {
|
||||
bool done = false;
|
||||
while (optind < argc) {
|
||||
auto boc = load_boc(argv[optind++]);
|
||||
if (boc.is_null()) {
|
||||
std::cerr << "(invalid boc)" << std::endl;
|
||||
std::exit(2);
|
||||
} else {
|
||||
done = true;
|
||||
vm::CellSlice cs{vm::NoVm(), boc};
|
||||
cs.print_rec(std::cout);
|
||||
std::cout << std::endl;
|
||||
auto& type = dump_state ? (const tlb::TLB&)block::gen::t_ShardStateUnsplit : block::gen::t_Block;
|
||||
std::string type_name = dump_state ? "ShardState" : "Block";
|
||||
type.print_ref(std::cout, boc);
|
||||
std::cout << std::endl;
|
||||
bool ok = type.validate_ref(boc);
|
||||
std::cout << "(" << (ok ? "" : "in") << "valid " << type_name << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
test1();
|
||||
}
|
||||
} catch (IntError& err) {
|
||||
std::cerr << "caught internal error " << err.err_msg << std::endl;
|
||||
return 1;
|
||||
} catch (vm::VmError& err) {
|
||||
std::cerr << "caught vm error " << err.get_msg() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -260,6 +260,22 @@ td::Status Config::unpack() {
|
|||
workchains_ = std::move(pair.first);
|
||||
workchains_dict_ = std::move(pair.second);
|
||||
}
|
||||
if (mode & needCapabilities) {
|
||||
auto cell = get_config_param(8);
|
||||
if (cell.is_null()) {
|
||||
version_ = 0;
|
||||
capabilities_ = 0;
|
||||
} else {
|
||||
block::gen::GlobalVersion::Record gv;
|
||||
if (!tlb::unpack_cell(std::move(cell), gv)) {
|
||||
return td::Status::Error(
|
||||
"cannot extract global blockchain version and capabilities from GlobalVersion in configuration parameter "
|
||||
"#8");
|
||||
}
|
||||
version_ = gv.version;
|
||||
capabilities_ = gv.capabilities;
|
||||
}
|
||||
}
|
||||
// ...
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -339,7 +355,7 @@ bool ConfigInfo::get_last_key_block(ton::BlockIdExt& blkid, ton::LogicalTime& bl
|
|||
blkid = block_id;
|
||||
blklt = lt;
|
||||
}
|
||||
return blkid.is_valid() && blkid.seqno();
|
||||
return blkid.is_valid();
|
||||
}
|
||||
|
||||
td::Result<std::pair<WorkchainSet, std::unique_ptr<vm::Dictionary>>> Config::unpack_workchain_list_ext(
|
||||
|
|
|
@ -441,7 +441,7 @@ class Config {
|
|||
};
|
||||
|
||||
public:
|
||||
enum { needValidatorSet = 16, needSpecialSmc = 32, needWorkchainInfo = 256 };
|
||||
enum { needValidatorSet = 16, needSpecialSmc = 32, needWorkchainInfo = 256, needCapabilities = 512 };
|
||||
int mode{0};
|
||||
ton::BlockIdExt block_id;
|
||||
|
||||
|
@ -452,6 +452,8 @@ class Config {
|
|||
std::unique_ptr<ValidatorSet> cur_validators_;
|
||||
std::unique_ptr<vm::Dictionary> workchains_dict_;
|
||||
WorkchainSet workchains_;
|
||||
int version_{-1};
|
||||
long long capabilities_{-1};
|
||||
|
||||
protected:
|
||||
std::unique_ptr<vm::Dictionary> special_smc_dict;
|
||||
|
@ -474,6 +476,24 @@ class Config {
|
|||
bool is_masterchain() const {
|
||||
return block_id.is_masterchain();
|
||||
}
|
||||
bool has_capabilities() const {
|
||||
return capabilities_ >= 0;
|
||||
}
|
||||
long long get_capabilities() const {
|
||||
return capabilities_;
|
||||
}
|
||||
int get_global_version() const {
|
||||
return version_;
|
||||
}
|
||||
bool has_capability(long long cap_set) const {
|
||||
return has_capabilities() && (capabilities_ & cap_set) == cap_set;
|
||||
}
|
||||
bool ihr_enabled() const {
|
||||
return has_capability(ton::capIhrEnabled);
|
||||
}
|
||||
bool create_stats_enabled() const {
|
||||
return has_capability(ton::capCreateStatsEnabled);
|
||||
}
|
||||
bool set_block_id_ext(const ton::BlockIdExt& block_id_ext);
|
||||
td::Result<std::vector<ton::StdSmcAddress>> get_special_smartcontracts(bool without_config = false) const;
|
||||
bool is_special_smartcontract(const ton::StdSmcAddress& addr) const;
|
||||
|
|
261
crypto/common/bigexp.cpp
Normal file
261
crypto/common/bigexp.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "bigexp.h"
|
||||
#include "td/utils/bits.h"
|
||||
#include "td/utils/as.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
bool NegExpBinTable::init() {
|
||||
init_one();
|
||||
int k;
|
||||
for (k = minpw2; k <= 0; k++) {
|
||||
exp_pw2_table.emplace_back(series_exp(-k));
|
||||
exp_pw2_ref_table.emplace_back(true, exp_pw2_table.back());
|
||||
}
|
||||
for (; k < maxpw2; k++) {
|
||||
td::BigIntG<257 * 2> tmp{0};
|
||||
auto& x = exp_pw2_table.back();
|
||||
tmp.add_mul(x, x).rshift(precision, 0).normalize();
|
||||
exp_pw2_table.emplace_back(tmp);
|
||||
exp_pw2_ref_table.emplace_back(true, exp_pw2_table.back());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NegExpBinTable::adjust_precision(int new_precision, int rmode) {
|
||||
if (new_precision <= 0 || new_precision > precision) {
|
||||
return false;
|
||||
}
|
||||
if (new_precision == precision) {
|
||||
return true;
|
||||
}
|
||||
int s = precision - new_precision;
|
||||
for (auto& x : exp_pw2_table) {
|
||||
x.rshift(s, rmode).normalize();
|
||||
}
|
||||
for (auto& x : exp_pw2_ref_table) {
|
||||
x.write().rshift(s, rmode).normalize();
|
||||
}
|
||||
precision = new_precision;
|
||||
return init_one();
|
||||
}
|
||||
|
||||
bool NegExpBinTable::init_one() {
|
||||
One.set_pow2(precision);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NegExpBinTable::nexpf(td::BigInt256& res, long long x, int k) const { // res := 2^precision * exp(-x * 2^k)
|
||||
if (!x) {
|
||||
res.set_pow2(precision);
|
||||
return true;
|
||||
}
|
||||
if (x < 0) {
|
||||
return false;
|
||||
}
|
||||
int s = td::count_trailing_zeroes64(x);
|
||||
x >>= s;
|
||||
k -= s;
|
||||
if (k + minpw2 > 0) {
|
||||
return false;
|
||||
}
|
||||
int t = 63 - td::count_leading_zeroes64(x);
|
||||
if (t - k >= maxpw2) {
|
||||
return false;
|
||||
}
|
||||
res.set_pow2(precision);
|
||||
while (true) {
|
||||
td::BigIntG<257 * 2> tmp{0};
|
||||
tmp.add_mul(res, exp_pw2_table.at(t - k - minpw2)).rshift(precision, 0).normalize();
|
||||
res = tmp;
|
||||
x -= (1LL << t);
|
||||
if (!x) {
|
||||
return true;
|
||||
}
|
||||
t = 63 - td::count_leading_zeroes64(x);
|
||||
}
|
||||
}
|
||||
|
||||
td::RefInt256 NegExpBinTable::nexpf(long long x, int k) const {
|
||||
td::RefInt256 res{true};
|
||||
if (nexpf(res.unique_write(), x, k)) {
|
||||
return res;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
td::BigInt256 NegExpBinTable::series_exp(int k) const { // returns 2^precision * exp(-2^(-k)), k >= 0
|
||||
td::BigIntG<257 * 2> s{0}, q;
|
||||
const int prec = 52 * 6;
|
||||
q.set_pow2(prec);
|
||||
int i = 0;
|
||||
do {
|
||||
s += q;
|
||||
--i;
|
||||
q.rshift(k).add_tiny(i / 2).divmod_short(i);
|
||||
q.normalize();
|
||||
} while (q.sgn());
|
||||
s.rshift(prec - precision).normalize();
|
||||
return s;
|
||||
}
|
||||
|
||||
NegExpInt64Table::NegExpInt64Table() {
|
||||
NegExpBinTable t{252, 8, -32};
|
||||
CHECK(t.is_valid());
|
||||
table0[0] = 0;
|
||||
table0_shift[0] = 0;
|
||||
for (int i = 1; i <= max_exp; i++) {
|
||||
SuperFloat v(*t.nexpf(i, 0)); // compute exp(-i)
|
||||
CHECK(!v.is_nan());
|
||||
if (v.is_zero()) {
|
||||
table0[i] = 0;
|
||||
table0_shift[i] = 0;
|
||||
} else {
|
||||
CHECK(v.normalize());
|
||||
int k = v.s + 64 - 252;
|
||||
CHECK(k <= -64);
|
||||
if (k > -128) {
|
||||
table0[i] = v.top();
|
||||
table0_shift[i] = td::narrow_cast<unsigned char>(-k - 1);
|
||||
} else {
|
||||
table0[i] = 0;
|
||||
table0_shift[i] = 0;
|
||||
}
|
||||
}
|
||||
// std::cerr << "table0[" << i << "] = exp(-" << i << ") : " << table0[i] << " / 2^" << table0_shift[i] + 1 << std::endl;
|
||||
}
|
||||
td::BigInt256 One;
|
||||
One.set_pow2(252);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
td::BigInt256 x;
|
||||
CHECK(t.nexpf(x, i, 8));
|
||||
(x.negate() += One).rshift(252 - 64, 0).normalize();
|
||||
table1[i] = SuperFloat::as_uint64(x);
|
||||
// std::cerr << "table1[" << i << "] = 1 - exp(-" << i << "/256) : " << table1[i] << " / 2^64" << std::endl;
|
||||
}
|
||||
for (int i = 0; i < 256; i++) {
|
||||
td::BigInt256 x;
|
||||
CHECK(t.nexpf(x, i, 16));
|
||||
(x.negate() += One).rshift(252 - 64 - 8, 0).normalize();
|
||||
table2[i] = SuperFloat::as_uint64(x);
|
||||
// std::cerr << "table2[" << i << "] = 1 - exp(-" << i << "/2^16) : " << table2[i] << " / 2^72" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
td::uint64 NegExpInt64Table::umulnexps32(td::uint64 x, unsigned k, bool trunc) const { // compute x * exp(-k / 2^16)
|
||||
if (!k || !x) {
|
||||
return x;
|
||||
}
|
||||
unsigned k0 = (k >> 16);
|
||||
if (k0 > max_exp) {
|
||||
return 0;
|
||||
}
|
||||
unsigned s = td::count_leading_zeroes_non_zero64(x);
|
||||
x <<= s;
|
||||
unsigned k1 = (k >> 8) & 0xff;
|
||||
unsigned k2 = k & 0xff;
|
||||
if (k2) {
|
||||
x -= ((td::uint128::from_unsigned(x).mult(table2[k2]).rounded_hi() + 0x80) >> 8);
|
||||
}
|
||||
if (k1) {
|
||||
x -= td::uint128::from_unsigned(x).mult(table1[k1]).rounded_hi();
|
||||
}
|
||||
if (k0) {
|
||||
if (trunc) {
|
||||
return td::uint128::from_unsigned(x).mult(table0[k0]).shr(table0_shift[k0] + s + 1).lo();
|
||||
} else {
|
||||
return (td::uint128::from_unsigned(x).mult(table0[k0]).shr(table0_shift[k0] + s).lo() + 1) >> 1;
|
||||
}
|
||||
}
|
||||
if (!s) {
|
||||
return x;
|
||||
} else if (trunc) {
|
||||
return x >> s;
|
||||
} else {
|
||||
return ((x >> (s - 1)) + 1) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
td::int64 NegExpInt64Table::mulnexps32(td::int64 x, unsigned k, bool trunc) const {
|
||||
return x >= 0 ? umulnexps32(x, k, trunc) : -umulnexps32(-x, k, trunc);
|
||||
}
|
||||
|
||||
const NegExpInt64Table& NegExpInt64Table::table() {
|
||||
static NegExpInt64Table tab;
|
||||
return tab;
|
||||
}
|
||||
|
||||
td::uint64 umulnexps32(td::uint64 x, unsigned k, bool trunc) { // compute x * exp(-k / 2^16)
|
||||
return NegExpInt64Table::table().umulnexps32(x, k, trunc);
|
||||
}
|
||||
|
||||
td::int64 mulnexps32(td::int64 x, unsigned k, bool trunc) {
|
||||
return NegExpInt64Table::table().mulnexps32(x, k, trunc);
|
||||
}
|
||||
|
||||
td::uint128 SuperFloat::as_uint128(const td::BigInt256& x) {
|
||||
td::uint64 t[2];
|
||||
if (!x.export_bytes_lsb((unsigned char*)(void*)t, sizeof(t), false)) {
|
||||
return {std::numeric_limits<uint64>::max(), 0};
|
||||
} else {
|
||||
return {t[1], t[0]};
|
||||
}
|
||||
}
|
||||
|
||||
td::uint64 SuperFloat::as_uint64(const td::BigInt256& x) {
|
||||
td::uint64 t;
|
||||
if (!x.export_bytes_lsb((unsigned char*)&t, sizeof(t), false)) {
|
||||
return std::numeric_limits<uint64>::max();
|
||||
} else {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
SuperFloat::SuperFloat(td::BigInt256 x) {
|
||||
if (x.unsigned_fits_bits(128)) {
|
||||
m = as_uint128(x);
|
||||
s = 0;
|
||||
} else if (x.sgn() == 1) {
|
||||
s = x.bit_size(false) - 128;
|
||||
x.rshift(s, 0).normalize();
|
||||
m = as_uint128(x);
|
||||
} else {
|
||||
set_nan();
|
||||
}
|
||||
}
|
||||
|
||||
bool SuperFloat::normalize() {
|
||||
if (is_nan()) {
|
||||
return false;
|
||||
}
|
||||
if (is_zero()) {
|
||||
s = 0;
|
||||
return true;
|
||||
}
|
||||
auto hi = m.hi();
|
||||
int t = (hi ? td::count_leading_zeroes_non_zero64(hi) : 64 + td::count_leading_zeroes_non_zero64(m.lo()));
|
||||
m.shl(t);
|
||||
s -= t;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace td
|
145
crypto/common/bigexp.h
Normal file
145
crypto/common/bigexp.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/refint.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
class NegExpBinTable {
|
||||
int precision, maxpw2, minpw2;
|
||||
std::vector<td::BigInt256> exp_pw2_table; // table of 2^precision * exp(- 2^k) for k = max_pw2-1 .. min_pw2
|
||||
std::vector<td::RefInt256> exp_pw2_ref_table; // same data
|
||||
td::BigInt256 One;
|
||||
|
||||
public:
|
||||
NegExpBinTable(int _precision, int _maxpw2, int _minpw2) : precision(255), maxpw2(_maxpw2), minpw2(_minpw2) {
|
||||
(_precision > 0 && _precision < 256 && _minpw2 <= 0 && _maxpw2 > 0 && _maxpw2 <= 256 && _minpw2 >= -256 && init() &&
|
||||
adjust_precision(_precision)) ||
|
||||
invalidate();
|
||||
}
|
||||
bool is_valid() const {
|
||||
return minpw2 < maxpw2;
|
||||
}
|
||||
int get_precision() const {
|
||||
return precision;
|
||||
}
|
||||
int get_exponent_precision() const {
|
||||
return -minpw2;
|
||||
}
|
||||
int get_exponent_max_log2() const {
|
||||
return maxpw2;
|
||||
}
|
||||
const td::BigInt256* exp_pw2(int k) const { // returns 2^precision * exp(-2^k) or null
|
||||
return (k >= minpw2 && k < maxpw2) ? &exp_pw2_table[k - minpw2] : nullptr;
|
||||
}
|
||||
td::RefInt256 exp_pw2_ref(int k) const {
|
||||
if (k >= minpw2 && k < maxpw2) {
|
||||
return exp_pw2_ref_table[k - minpw2];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
bool nexpf(td::BigInt256& res, long long x, int k) const; // res := 2^precision * exp(-x * 2^k)
|
||||
td::RefInt256 nexpf(long long x, int k) const;
|
||||
|
||||
private:
|
||||
bool init();
|
||||
bool init_one();
|
||||
bool adjust_precision(int new_precision, int rmode = 0);
|
||||
bool invalidate() {
|
||||
minpw2 = maxpw2 = 0;
|
||||
return false;
|
||||
}
|
||||
td::BigInt256 series_exp(int k) const; // returns 2^precision * exp(-2^(-k)), k >= 0
|
||||
};
|
||||
|
||||
struct SuperFloat {
|
||||
struct SetZero {};
|
||||
struct SetOne {};
|
||||
struct SetNan {};
|
||||
td::uint128 m;
|
||||
int s;
|
||||
SuperFloat() = default;
|
||||
SuperFloat(SetZero) : m(0, 0), s(0) {
|
||||
}
|
||||
SuperFloat(SetOne) : m(0, 1), s(0) {
|
||||
}
|
||||
SuperFloat(SetNan) : m(0, 0), s(std::numeric_limits<int>::min()) {
|
||||
}
|
||||
SuperFloat(td::uint128 _m, int _s = 0) : m(_m), s(_s) {
|
||||
}
|
||||
SuperFloat(td::uint64 _m, int _s = 0) : m(0, _m), s(_s) {
|
||||
}
|
||||
explicit SuperFloat(BigInt256 x);
|
||||
static SuperFloat Zero() {
|
||||
return SetZero{};
|
||||
}
|
||||
static SuperFloat One() {
|
||||
return SetOne{};
|
||||
}
|
||||
static SuperFloat NaN() {
|
||||
return SetNan{};
|
||||
}
|
||||
void set_zero() {
|
||||
m = td::uint128(0, 0);
|
||||
s = 0;
|
||||
}
|
||||
void set_one() {
|
||||
m = td::uint128(0, 1);
|
||||
s = 0;
|
||||
}
|
||||
void set_nan() {
|
||||
s = std::numeric_limits<int>::min();
|
||||
}
|
||||
bool is_nan() const {
|
||||
return s == std::numeric_limits<int>::min();
|
||||
}
|
||||
bool is_zero() const {
|
||||
return m.is_zero();
|
||||
}
|
||||
bool normalize();
|
||||
td::uint64 top() const {
|
||||
return m.rounded_hi();
|
||||
}
|
||||
static td::uint128 as_uint128(const td::BigInt256& x);
|
||||
static td::uint64 as_uint64(const td::BigInt256& x);
|
||||
};
|
||||
|
||||
class NegExpInt64Table {
|
||||
enum { max_exp = 45 };
|
||||
unsigned char table0_shift[max_exp + 1];
|
||||
td::uint64 table0[max_exp + 1], table1[256], table2[256];
|
||||
|
||||
public:
|
||||
NegExpInt64Table();
|
||||
// compute x * exp(-k / 2^16);
|
||||
// more precisely: computes 0 <= y <= x for 0 <= x < 2^60, s.that |y - x * exp(-k / 2^16)| < 1
|
||||
// two different implementations of this functions would return values differing by at most one
|
||||
td::uint64 umulnexps32(td::uint64 x, unsigned k, bool trunc = false) const;
|
||||
td::int64 mulnexps32(td::int64 x, unsigned k, bool trunc = false) const;
|
||||
static const NegExpInt64Table& table();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
td::uint64 umulnexps32(td::uint64 x, unsigned k, bool trunc = false); // compute x * exp(-k / 2^16)
|
||||
td::int64 mulnexps32(td::int64 x, unsigned k, bool trunc = false);
|
||||
|
||||
} // namespace td
|
|
@ -128,6 +128,9 @@ struct BitPtrGen {
|
|||
std::size_t scan(bool value, std::size_t len) const {
|
||||
return bitstring::bits_memscan(*this, len, value);
|
||||
}
|
||||
bool is_zero(std::size_t len) const {
|
||||
return scan(false, len) == len;
|
||||
}
|
||||
long long get_int(unsigned bits) const {
|
||||
return bitstring::bits_load_long(*this, bits);
|
||||
}
|
||||
|
@ -279,7 +282,7 @@ class BitSliceGen {
|
|||
ensure_throw(set_size_bool(bits));
|
||||
return *this;
|
||||
}
|
||||
BitSliceGen subslice(unsigned from, unsigned bits) const & {
|
||||
BitSliceGen subslice(unsigned from, unsigned bits) const& {
|
||||
return BitSliceGen(*this, from, bits);
|
||||
}
|
||||
BitSliceGen subslice(unsigned from, unsigned bits) && {
|
||||
|
@ -467,7 +470,7 @@ class BitArray {
|
|||
unsigned char* data() {
|
||||
return bytes.data();
|
||||
}
|
||||
unsigned size() const {
|
||||
static unsigned size() {
|
||||
return n;
|
||||
}
|
||||
const byte_array_t& as_array() const {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// { bl word (forget) } : forget
|
||||
{ bl word 1 ' (forget) } :: [forget]
|
||||
{ char " word 1 ' type } ::_ ."
|
||||
{ char } word x>B 1 'nop } ::_ B{
|
||||
{ swap ({) over 2+ -roll swap (compile) (}) } : does
|
||||
{ 1 'nop does create } : constant
|
||||
{ 2 'nop does create } : 2constant
|
||||
|
|
|
@ -625,14 +625,69 @@ void interpret_bytes_len(vm::Stack& stack) {
|
|||
stack.push_smallint((long long)stack.pop_bytes().size());
|
||||
}
|
||||
|
||||
void interpret_bytes_hex_print_raw(IntCtx& ctx) {
|
||||
const char hex_digits[] = "0123456789ABCDEF";
|
||||
const char hex_digits[] = "0123456789abcdef";
|
||||
const char HEX_digits[] = "0123456789ABCDEF";
|
||||
|
||||
static inline const char* hex_digits_table(bool upcase) {
|
||||
return upcase ? HEX_digits : hex_digits;
|
||||
}
|
||||
|
||||
void interpret_bytes_hex_print_raw(IntCtx& ctx, bool upcase) {
|
||||
auto hex_digits = hex_digits_table(upcase);
|
||||
std::string str = ctx.stack.pop_bytes();
|
||||
for (unsigned c : str) {
|
||||
*ctx.output_stream << hex_digits[(c >> 4) & 15] << hex_digits[c & 15];
|
||||
}
|
||||
}
|
||||
|
||||
void interpret_bytes_to_hex(vm::Stack& stack, bool upcase) {
|
||||
auto hex_digits = hex_digits_table(upcase);
|
||||
std::string str = stack.pop_bytes();
|
||||
std::string t(str.size() * 2, 0);
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
unsigned c = str[i];
|
||||
t[2 * i] = hex_digits[(c >> 4) & 15];
|
||||
t[2 * i + 1] = hex_digits[c & 15];
|
||||
}
|
||||
stack.push_string(std::move(t));
|
||||
}
|
||||
|
||||
void interpret_hex_to_bytes(vm::Stack& stack, bool partial) {
|
||||
std::string str = stack.pop_string(), t;
|
||||
if (!partial) {
|
||||
if (str.size() & 1) {
|
||||
throw IntError{"not a hex string"};
|
||||
}
|
||||
t.reserve(str.size() >> 1);
|
||||
}
|
||||
std::size_t i;
|
||||
unsigned f = 0;
|
||||
for (i = 0; i < str.size(); i++) {
|
||||
int c = str[i];
|
||||
if (c >= '0' && c <= '9') {
|
||||
c -= '0';
|
||||
} else {
|
||||
c |= 0x20;
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
c -= 'a' - 10;
|
||||
} else {
|
||||
if (!partial) {
|
||||
throw IntError{"not a hex string"};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
f = (f << 4) + c;
|
||||
if (i & 1) {
|
||||
t += (char)(f & 0xff);
|
||||
}
|
||||
}
|
||||
stack.push_bytes(t);
|
||||
if (partial) {
|
||||
stack.push_smallint(i & -2);
|
||||
}
|
||||
}
|
||||
|
||||
void interpret_bytes_split(vm::Stack& stack) {
|
||||
stack.check_underflow(2);
|
||||
unsigned sz = stack.pop_smallint_range(0x7fffffff);
|
||||
|
@ -1525,39 +1580,6 @@ void interpret_pfx_dict_get(vm::Stack& stack) {
|
|||
}
|
||||
}
|
||||
|
||||
void interpret_bytes_hex_literal(IntCtx& ctx) {
|
||||
auto s = ctx.scan_word_to('}');
|
||||
std::string t;
|
||||
t.reserve(s.size() >> 1);
|
||||
int v = 1;
|
||||
for (char c : s) {
|
||||
if (c == ' ' || c == '\t') {
|
||||
continue;
|
||||
}
|
||||
v <<= 4;
|
||||
if (c >= '0' && c <= '9') {
|
||||
v += c - '0';
|
||||
} else {
|
||||
c |= 0x20;
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
v += c - ('a' - 10);
|
||||
} else {
|
||||
v = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (v & 0x100) {
|
||||
t.push_back((char)v);
|
||||
v = 1;
|
||||
}
|
||||
}
|
||||
if (v != 1) {
|
||||
throw IntError{"Invalid bytes hexstring constant"};
|
||||
}
|
||||
ctx.stack.push_bytes(std::move(t));
|
||||
push_argcount(ctx.stack, 1);
|
||||
}
|
||||
|
||||
void interpret_bitstring_hex_literal(IntCtx& ctx) {
|
||||
auto s = ctx.scan_word_to('}');
|
||||
unsigned char buff[128];
|
||||
|
@ -2430,7 +2452,11 @@ void init_words_common(Dictionary& d) {
|
|||
d.def_stack_word("-trailing0 ", std::bind(interpret_str_remove_trailing_int, _1, '0'));
|
||||
d.def_stack_word("$len ", interpret_str_len);
|
||||
d.def_stack_word("Blen ", interpret_bytes_len);
|
||||
d.def_ctx_word("Bx. ", interpret_bytes_hex_print_raw);
|
||||
d.def_ctx_word("Bx. ", std::bind(interpret_bytes_hex_print_raw, _1, true));
|
||||
d.def_stack_word("B>X ", std::bind(interpret_bytes_to_hex, _1, true));
|
||||
d.def_stack_word("B>x ", std::bind(interpret_bytes_to_hex, _1, false));
|
||||
d.def_stack_word("x>B ", std::bind(interpret_hex_to_bytes, _1, false));
|
||||
d.def_stack_word("x>B? ", std::bind(interpret_hex_to_bytes, _1, true));
|
||||
d.def_stack_word("B| ", interpret_bytes_split);
|
||||
d.def_stack_word("B+ ", interpret_bytes_concat);
|
||||
d.def_stack_word("B= ", interpret_bytes_equal);
|
||||
|
@ -2542,7 +2568,6 @@ void init_words_common(Dictionary& d) {
|
|||
d.def_ctx_word("dictmerge ", interpret_dict_merge);
|
||||
d.def_ctx_word("dictdiff ", interpret_dict_diff);
|
||||
// slice/bitstring constants
|
||||
d.def_active_word("B{", interpret_bytes_hex_literal);
|
||||
d.def_active_word("x{", interpret_bitstring_hex_literal);
|
||||
d.def_active_word("b{", interpret_bitstring_binary_literal);
|
||||
// boxes/holes/variables
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <openssl/bn.h>
|
||||
#include "td/utils/bits.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
namespace arith {
|
||||
struct dec_string {
|
||||
|
@ -36,6 +37,12 @@ struct hex_string {
|
|||
explicit hex_string(const std::string& s) : str(s) {
|
||||
}
|
||||
};
|
||||
|
||||
struct bin_string {
|
||||
std::string str;
|
||||
explicit bin_string(const std::string& s) : str(s) {
|
||||
}
|
||||
};
|
||||
} // namespace arith
|
||||
|
||||
namespace arith {
|
||||
|
@ -70,6 +77,10 @@ class Bignum {
|
|||
~Bignum() {
|
||||
BN_free(val);
|
||||
}
|
||||
Bignum(const bin_string& bs) {
|
||||
val = BN_new();
|
||||
set_dec_str(bs.str);
|
||||
}
|
||||
Bignum(const dec_string& ds) {
|
||||
val = BN_new();
|
||||
set_dec_str(ds.str);
|
||||
|
@ -150,6 +161,11 @@ class Bignum {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Bignum& set_raw_bytes(std::string s) {
|
||||
CHECK(BN_bin2bn(reinterpret_cast<const td::uint8*>(s.c_str()), td::narrow_cast<td::uint32>(s.size()), val));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bignum& set_hex_str(std::string s) {
|
||||
bn_assert(BN_hex2bn(&val, s.c_str()));
|
||||
return *this;
|
||||
|
|
|
@ -35,6 +35,11 @@
|
|||
|
||||
{ (configdict) 0= abort"Configuration dictionary is empty" } : configdict
|
||||
|
||||
// version capabilities --
|
||||
{ <b x{c4} s, rot 32 u, swap 64 u, b> 8 config! } : config.version!
|
||||
1 constant capIhr
|
||||
2 constant capCreateStats
|
||||
|
||||
// max-validators masterchain-validators min-validators --
|
||||
{ swap rot <b swap 16 u, swap 16 u, swap 16 u, b> 16 config! } : config.validator_num!
|
||||
|
||||
|
|
|
@ -150,6 +150,8 @@ Masterchain swap
|
|||
* Configuration Parameters
|
||||
*
|
||||
*/
|
||||
// version capabilities
|
||||
0 capCreateStats config.version!
|
||||
// max-validators max-main-validators min-validators
|
||||
// 9 4 1 config.validator_num!
|
||||
1000 100 5 config.validator_num!
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "common/refcnt.hpp"
|
||||
#include "common/bigint.hpp"
|
||||
#include "common/refint.h"
|
||||
#include "common/bigexp.h"
|
||||
#include "common/bitstring.h"
|
||||
#include "common/util.h"
|
||||
#include "vm/cells.h"
|
||||
|
@ -569,3 +570,87 @@ TEST(bits256_scan, main) {
|
|||
os << "bits256_scan test OK";
|
||||
REGRESSION_VERIFY(os.str());
|
||||
}
|
||||
|
||||
bool check_exp(std::ostream& stream, const td::NegExpBinTable& tab, double x) {
|
||||
long long xx = lround(x * (1LL << 52));
|
||||
td::BigInt256 yy;
|
||||
if (!tab.nexpf(yy, -xx, 52)) {
|
||||
stream << "cannot compute exp(" << x << ") = exp(" << xx << " * 2^(-52))" << std::endl;
|
||||
return false;
|
||||
}
|
||||
double y = yy.to_double() * exp2(-252);
|
||||
double y0 = exp(x);
|
||||
bool ok = (abs(y - y0) < 1e-15);
|
||||
if (!ok) {
|
||||
stream << "exp(" << x << ") = exp(" << xx << " * 2^(-52)) = " << yy << " / 2^252 = " << y << " (correct value is "
|
||||
<< y0 << ") " << (ok ? "match" : "incorrect") << std::endl;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
TEST(bigexp, main) {
|
||||
os = create_ss();
|
||||
td::NegExpBinTable tab(252, 32, -128);
|
||||
bool ok = true;
|
||||
if (!tab.is_valid()) {
|
||||
os << "cannot initialize td::NegExpBinTable(252, 32, -128)" << std::endl;
|
||||
ok = false;
|
||||
} else {
|
||||
// for (int i = -128; i < 32; i++) {
|
||||
// os << "exp(-2^" << i << ") = " << tab.exp_pw2_ref(i) << " / 2^252 = " << tab.exp_pw2_ref(i)->to_double() * exp2(-252) << " (correct value is " << exp(-exp2(i)) << ")" << std::endl;
|
||||
// }
|
||||
ok &= check_exp(os, tab, -2.39);
|
||||
ok &= check_exp(os, tab, 0);
|
||||
ok &= check_exp(os, tab, -1);
|
||||
ok &= check_exp(os, tab, -2);
|
||||
ok &= check_exp(os, tab, -16);
|
||||
ok &= check_exp(os, tab, -17);
|
||||
ok &= check_exp(os, tab, -0.5);
|
||||
ok &= check_exp(os, tab, -0.25);
|
||||
ok &= check_exp(os, tab, -3.1415926535);
|
||||
ok &= check_exp(os, tab, -1e-9);
|
||||
}
|
||||
if (ok) {
|
||||
os << "bigexp test OK\n";
|
||||
} else {
|
||||
os << "bigexp test FAILED\n";
|
||||
}
|
||||
REGRESSION_VERIFY(os.str());
|
||||
}
|
||||
|
||||
bool check_intexp(std::ostream& stream, td::uint64 x, unsigned k, td::uint64 yc = 0) {
|
||||
td::uint64 y = td::umulnexps32(x, k);
|
||||
long long delta = (long long)(y - yc);
|
||||
bool ok = (y <= x && std::abs(delta) <= 1);
|
||||
if (!ok) {
|
||||
stream << x << "*exp(-" << k << "/65536) = " << y << " (correct value " << yc << ", delta = " << delta << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
TEST(uint64_exp, main) {
|
||||
os = create_ss();
|
||||
bool ok = true;
|
||||
ok &= check_intexp(os, 3167801306015831286, 4003, 2980099890648636481);
|
||||
ok &= check_intexp(os, 1583900653007915643, 4003, 1490049945324318240);
|
||||
ok &= check_intexp(os, 9094494907266047891, 17239, 6990995826652297465);
|
||||
ok &= check_intexp(os, 5487867407433215099, 239017, 143048684491504152);
|
||||
ok &= check_intexp(os, 46462010749955243, 239017, 1211095134625318); // up
|
||||
ok &= check_intexp(os, 390263500024095125, 2700001, 1);
|
||||
ok &= check_intexp(os, 390263500024095124, 2700001, 1);
|
||||
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952601, 1);
|
||||
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952696, 1);
|
||||
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952697, 0);
|
||||
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952800, 0);
|
||||
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 295269700, 0);
|
||||
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2000018, 1028453);
|
||||
ok &= check_intexp(os, 1ULL << 60, 2770991, 1);
|
||||
ok &= check_intexp(os, 1ULL << 60, 2770992, 0);
|
||||
if (ok) {
|
||||
os << "uint64_exp test OK\n";
|
||||
} else {
|
||||
os << "uint64_exp test FAILED\n";
|
||||
}
|
||||
REGRESSION_VERIFY(os.str());
|
||||
}
|
||||
|
|
|
@ -30,7 +30,19 @@ struct Type;
|
|||
struct Constructor;
|
||||
|
||||
struct TypeExpr {
|
||||
enum { te_Unknown, te_Type, te_Param, te_Apply, te_Add, te_MulConst, te_IntConst, te_Tuple, te_Ref, te_CondType };
|
||||
enum {
|
||||
te_Unknown,
|
||||
te_Type,
|
||||
te_Param,
|
||||
te_Apply,
|
||||
te_Add,
|
||||
te_GetBit,
|
||||
te_MulConst,
|
||||
te_IntConst,
|
||||
te_Tuple,
|
||||
te_Ref,
|
||||
te_CondType
|
||||
};
|
||||
enum { max_const_expr = 100000, const_htable_size = 170239 };
|
||||
int tp;
|
||||
int value;
|
||||
|
|
|
@ -1464,6 +1464,28 @@ void CppTypeCode::output_cpp_expr(std::ostream& os, const TypeExpr* expr, int pr
|
|||
os << ")";
|
||||
}
|
||||
return;
|
||||
case TypeExpr::te_GetBit:
|
||||
if (prio > 0) {
|
||||
os << "(";
|
||||
}
|
||||
output_cpp_expr(os, expr->args[0], 5);
|
||||
os << " & ";
|
||||
if (expr->args[1]->tp == TypeExpr::te_IntConst && (unsigned)expr->args[1]->value <= 31) {
|
||||
int v = expr->args[1]->value;
|
||||
if (v > 1024) {
|
||||
os << "0x" << std::hex << (1 << v) << std::dec;
|
||||
} else {
|
||||
os << (1 << v);
|
||||
}
|
||||
} else {
|
||||
os << "(1 << ";
|
||||
output_cpp_expr(os, expr->args[1], 5);
|
||||
os << ")";
|
||||
}
|
||||
if (prio > 0) {
|
||||
os << ")";
|
||||
}
|
||||
return;
|
||||
case TypeExpr::te_IntConst:
|
||||
os << expr->value;
|
||||
return;
|
||||
|
|
|
@ -81,6 +81,7 @@ void define_keywords() {
|
|||
.add_kw_char('=')
|
||||
.add_kw_char('_')
|
||||
.add_kw_char('?')
|
||||
.add_kw_char('.')
|
||||
.add_kw_char('~')
|
||||
.add_kw_char('^');
|
||||
|
||||
|
@ -1128,6 +1129,19 @@ void TypeExpr::show(std::ostream& os, const Constructor* cs, int prio, int mode)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case te_GetBit: {
|
||||
assert(args.size() == 2);
|
||||
if (prio > 97) {
|
||||
os << '(';
|
||||
}
|
||||
args[0]->show(os, cs, 98, mode);
|
||||
os << "."; // priority 20
|
||||
args[1]->show(os, cs, 98, mode);
|
||||
if (prio > 97) {
|
||||
os << ')';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case te_IntConst: {
|
||||
assert(args.empty());
|
||||
os << value;
|
||||
|
@ -1202,11 +1216,12 @@ int abstract_nat_const(int value) {
|
|||
}
|
||||
|
||||
unsigned char abstract_add_base_table[4][4] = {{0, 1, 2, 3}, {1, 2, 3, 2}, {2, 3, 2, 3}, {3, 2, 3, 2}};
|
||||
|
||||
unsigned char abstract_mul_base_table[4][4] = {{0, 0, 0, 0}, {0, 1, 2, 3}, {0, 2, 2, 2}, {0, 3, 2, 3}};
|
||||
unsigned char abstract_getbit_b_table[4][4] = {{1, 1, 1, 1}, {2, 1, 1, 1}, {1, 3, 3, 3}, {2, 3, 3, 3}};
|
||||
|
||||
unsigned char abstract_add_table[16][16];
|
||||
unsigned char abstract_mul_table[16][16];
|
||||
unsigned char abstract_getbit_table[16][16];
|
||||
|
||||
void compute_semilat_table(unsigned char table[16][16], const unsigned char base_table[4][4]) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
|
@ -1226,9 +1241,28 @@ void compute_semilat_table(unsigned char table[16][16], const unsigned char base
|
|||
}
|
||||
}
|
||||
|
||||
void compute_semilat_b_table(unsigned char table[16][16], const unsigned char b_table[4][4]) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
int res = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((x >> i) & 1) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if ((y >> j) & 1) {
|
||||
res |= b_table[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
table[x][y] = (unsigned char)res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_abstract_tables() {
|
||||
compute_semilat_table(abstract_add_table, abstract_add_base_table);
|
||||
compute_semilat_table(abstract_mul_table, abstract_mul_base_table);
|
||||
compute_semilat_b_table(abstract_getbit_table, abstract_getbit_b_table);
|
||||
}
|
||||
|
||||
int abstract_add(int x, int y) {
|
||||
|
@ -1239,6 +1273,10 @@ int abstract_mul(int x, int y) {
|
|||
return abstract_mul_table[x & 15][y & 15];
|
||||
}
|
||||
|
||||
int abstract_getbit(int x, int y) {
|
||||
return abstract_getbit_table[x & 15][y & 15];
|
||||
}
|
||||
|
||||
int TypeExpr::abstract_interpret_nat() const {
|
||||
if (!is_nat || tchk_only) {
|
||||
return 0;
|
||||
|
@ -1249,6 +1287,9 @@ int TypeExpr::abstract_interpret_nat() const {
|
|||
case te_Add:
|
||||
assert(args.size() == 2);
|
||||
return abstract_add(args[0]->abstract_interpret_nat(), args[1]->abstract_interpret_nat());
|
||||
case te_GetBit:
|
||||
assert(args.size() == 2);
|
||||
return abstract_getbit(args[0]->abstract_interpret_nat(), args[1]->abstract_interpret_nat());
|
||||
case te_IntConst:
|
||||
return abstract_nat_const(value);
|
||||
case te_MulConst:
|
||||
|
@ -1464,6 +1505,11 @@ void TypeExpr::const_type_name(std::ostream& os) const {
|
|||
os << "_plus";
|
||||
args[1]->const_type_name(os);
|
||||
return;
|
||||
case te_GetBit:
|
||||
args[0]->const_type_name(os);
|
||||
os << "_bit";
|
||||
args[1]->const_type_name(os);
|
||||
return;
|
||||
case te_IntConst:
|
||||
os << "_" << value;
|
||||
return;
|
||||
|
@ -1573,6 +1619,13 @@ bool TypeExpr::bind_value(bool value_negated, Constructor& cs, bool checking_typ
|
|||
args[0]->bind_value(value_negated, cs);
|
||||
return true;
|
||||
}
|
||||
case te_GetBit: {
|
||||
assert(is_nat && args.size() == 2 && !args[0]->negated && !args[1]->negated);
|
||||
assert(!negated);
|
||||
args[0]->bind_value(false, cs);
|
||||
args[1]->bind_value(false, cs);
|
||||
return true;
|
||||
}
|
||||
case te_Type: {
|
||||
assert(!is_nat && !negated);
|
||||
return true;
|
||||
|
@ -2057,10 +2110,34 @@ TypeExpr* parse_term(Lexer& lex, Constructor& cs, int mode) {
|
|||
}
|
||||
}
|
||||
|
||||
// E ? E [ : E ]
|
||||
|
||||
TypeExpr* parse_expr95(Lexer& lex, Constructor& cs, int mode) {
|
||||
// E[.E]
|
||||
TypeExpr* parse_expr97(Lexer& lex, Constructor& cs, int mode) {
|
||||
TypeExpr* expr = parse_term(lex, cs, mode | 3);
|
||||
if (lex.tp() == '.') {
|
||||
src::SrcLocation where = lex.cur().loc;
|
||||
expr->close(lex.cur().loc);
|
||||
// std::cerr << "parse ., mode " << mode << std::endl;
|
||||
if (!(mode & 2)) {
|
||||
throw src::ParseError{where, "bitfield expression cannot be used instead of a type expression"};
|
||||
}
|
||||
if (!expr->is_nat) {
|
||||
throw src::ParseError{where, "cannot apply bit selection operator `.` to types"};
|
||||
}
|
||||
lex.next();
|
||||
TypeExpr* expr2 = parse_term(lex, cs, mode & ~1);
|
||||
expr2->close(lex.cur().loc);
|
||||
if (expr->negated || expr2->negated) {
|
||||
throw src::ParseError{where, "cannot apply bit selection operator `.` to values of negative polarity"};
|
||||
}
|
||||
expr = TypeExpr::mk_apply(where, TypeExpr::te_GetBit, expr, expr2);
|
||||
}
|
||||
expr->check_mode(lex.cur().loc, mode);
|
||||
return expr;
|
||||
}
|
||||
|
||||
// E ? E [ : E ]
|
||||
TypeExpr* parse_expr95(Lexer& lex, Constructor& cs, int mode) {
|
||||
TypeExpr* expr = parse_expr97(lex, cs, mode | 3);
|
||||
if (lex.tp() != '?') {
|
||||
expr->check_mode(lex.cur().loc, mode);
|
||||
return expr;
|
||||
|
|
|
@ -34,7 +34,7 @@ cd build-$ARCH
|
|||
|
||||
|
||||
cmake .. \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_SDK_ROOT}/ndk-bundle/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DANDROID_ABI=${ABI} -DOPENSSL_ROOT_DIR=/Users/arseny30/Code/td_android/libtd/src/main/jni/third_party/crypto/${ARCH} -DTON_ARCH="" -DTON_USE_ABSEIL=OFF || exit 1
|
||||
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DANDROID_ABI=${ABI} -DOPENSSL_ROOT_DIR=/Users/arseny30/Code/td_android/libtd/src/main/jni/third_party/crypto/${ARCH} -DTON_ARCH="" -DTON_USE_ABSEIL=OFF || exit 1
|
||||
ninja native-lib || exit 1
|
||||
popd
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
add_executable(lite-client lite-client.cpp lite-client.h)
|
||||
target_link_libraries(lite-client tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block terminal)
|
||||
add_library(lite-client-common lite-client-common.cpp lite-client-common.h)
|
||||
target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block)
|
||||
|
||||
add_executable(lite-client lite-client.cpp lite-client.h)
|
||||
target_link_libraries(lite-client tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block
|
||||
terminal lite-client-common)
|
||||
|
|
77
lite-client/lite-client-common.cpp
Normal file
77
lite-client/lite-client-common.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "lite-client-common.h"
|
||||
|
||||
#include "auto/tl/lite_api.hpp"
|
||||
#include "tl-utils/lite-utils.hpp"
|
||||
#include "ton/lite-tl.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
namespace liteclient {
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> deserialize_proof_chain(
|
||||
ton::lite_api::object_ptr<ton::lite_api::liteServer_partialBlockProof> f) {
|
||||
// deserialize proof chain
|
||||
auto chain = std::make_unique<block::BlockProofChain>(ton::create_block_id(f->from_), ton::create_block_id(f->to_));
|
||||
chain->complete = f->complete_;
|
||||
for (auto& s : f->steps_) {
|
||||
bool ok = false;
|
||||
td::BufferSlice dest_proof, proof, state_proof;
|
||||
ton::lite_api::downcast_call(
|
||||
*s,
|
||||
td::overloaded(
|
||||
[&](ton::lite_api::liteServer_blockLinkBack& s) {
|
||||
auto& link = chain->new_link(ton::create_block_id(s.from_), ton::create_block_id(s.to_), s.to_key_block_);
|
||||
link.is_fwd = false;
|
||||
// dest_proof:bytes state_proof:bytes proof:bytes
|
||||
dest_proof = std::move(s.dest_proof_);
|
||||
state_proof = std::move(s.state_proof_);
|
||||
proof = std::move(s.proof_);
|
||||
ok = true;
|
||||
},
|
||||
[&](ton::lite_api::liteServer_blockLinkForward& s) {
|
||||
auto& link = chain->new_link(ton::create_block_id(s.from_), ton::create_block_id(s.to_), s.to_key_block_);
|
||||
link.is_fwd = true;
|
||||
// dest_proof:bytes config_proof:bytes signatures:liteServer.SignatureSet
|
||||
dest_proof = std::move(s.dest_proof_);
|
||||
proof = std::move(s.config_proof_);
|
||||
link.cc_seqno = s.signatures_->catchain_seqno_;
|
||||
link.validator_set_hash = s.signatures_->validator_set_hash_;
|
||||
for (auto& sig : s.signatures_->signatures_) {
|
||||
link.signatures.emplace_back(std::move(sig->node_id_short_), std::move(sig->signature_));
|
||||
}
|
||||
ok = true;
|
||||
},
|
||||
[&](auto& obj) {}));
|
||||
if (!ok) {
|
||||
return td::Status::Error("unknown constructor of liteServer.BlockLink");
|
||||
}
|
||||
auto& link = chain->last_link();
|
||||
if (!dest_proof.empty()) {
|
||||
auto d_res = vm::std_boc_deserialize(std::move(dest_proof));
|
||||
if (d_res.is_error()) {
|
||||
return td::Status::Error("cannot deserialize dest_proof in a block proof link: "s +
|
||||
d_res.move_as_error().to_string());
|
||||
}
|
||||
link.dest_proof = d_res.move_as_ok();
|
||||
}
|
||||
auto d_res = vm::std_boc_deserialize(std::move(proof));
|
||||
if (d_res.is_error()) {
|
||||
return td::Status::Error("cannot deserialize proof in a block proof link: "s + d_res.move_as_error().to_string());
|
||||
}
|
||||
link.proof = d_res.move_as_ok();
|
||||
if (!link.is_fwd) {
|
||||
d_res = vm::std_boc_deserialize(std::move(state_proof));
|
||||
if (d_res.is_error()) {
|
||||
return td::Status::Error("cannot deserialize state_proof in a block proof link: "s +
|
||||
d_res.move_as_error().to_string());
|
||||
}
|
||||
link.state_proof = d_res.move_as_ok();
|
||||
}
|
||||
LOG(DEBUG) << "deserialized a " << (link.is_fwd ? "forward" : "backward") << " BlkProofLink from "
|
||||
<< link.from.to_str() << " to " << link.to.to_str() << " with " << link.signatures.size()
|
||||
<< " signatures";
|
||||
}
|
||||
LOG(DEBUG) << "deserialized a BlkProofChain of " << chain->link_count() << " links";
|
||||
return std::move(chain);
|
||||
}
|
||||
} // namespace liteclient
|
10
lite-client/lite-client-common.h
Normal file
10
lite-client/lite-client-common.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "crypto/block/block.h"
|
||||
|
||||
#include "auto/tl/lite_api.hpp"
|
||||
|
||||
namespace liteclient {
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> deserialize_proof_chain(
|
||||
ton::lite_api::object_ptr<ton::lite_api::liteServer_partialBlockProof> f);
|
||||
}
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
#include "lite-client.h"
|
||||
|
||||
#include "lite-client-common.h"
|
||||
|
||||
#include "adnl/adnl-ext-client.h"
|
||||
#include "tl-utils/lite-utils.hpp"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
|
@ -2102,78 +2104,17 @@ bool TestNode::get_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod
|
|||
});
|
||||
}
|
||||
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> TestNode::deserialize_proof_chain(td::BufferSlice pchain) {
|
||||
TRY_RESULT(f, ton::fetch_tl_object<ton::lite_api::liteServer_partialBlockProof>(std::move(pchain), true));
|
||||
// deserialize proof chain
|
||||
auto chain = std::make_unique<block::BlockProofChain>(ton::create_block_id(f->from_), ton::create_block_id(f->to_));
|
||||
chain->complete = f->complete_;
|
||||
for (auto& s : f->steps_) {
|
||||
bool ok = false;
|
||||
td::BufferSlice dest_proof, proof, state_proof;
|
||||
ton::lite_api::downcast_call(
|
||||
*s,
|
||||
td::overloaded(
|
||||
[&](ton::lite_api::liteServer_blockLinkBack& s) {
|
||||
auto& link = chain->new_link(ton::create_block_id(s.from_), ton::create_block_id(s.to_), s.to_key_block_);
|
||||
link.is_fwd = false;
|
||||
// dest_proof:bytes state_proof:bytes proof:bytes
|
||||
dest_proof = std::move(s.dest_proof_);
|
||||
state_proof = std::move(s.state_proof_);
|
||||
proof = std::move(s.proof_);
|
||||
ok = true;
|
||||
},
|
||||
[&](ton::lite_api::liteServer_blockLinkForward& s) {
|
||||
auto& link = chain->new_link(ton::create_block_id(s.from_), ton::create_block_id(s.to_), s.to_key_block_);
|
||||
link.is_fwd = true;
|
||||
// dest_proof:bytes config_proof:bytes signatures:liteServer.SignatureSet
|
||||
dest_proof = std::move(s.dest_proof_);
|
||||
proof = std::move(s.config_proof_);
|
||||
link.cc_seqno = s.signatures_->catchain_seqno_;
|
||||
link.validator_set_hash = s.signatures_->validator_set_hash_;
|
||||
for (auto& sig : s.signatures_->signatures_) {
|
||||
link.signatures.emplace_back(std::move(sig->node_id_short_), std::move(sig->signature_));
|
||||
}
|
||||
ok = true;
|
||||
},
|
||||
[&](auto& obj) {}));
|
||||
if (!ok) {
|
||||
return td::Status::Error("unknown constructor of liteServer.BlockLink");
|
||||
}
|
||||
auto& link = chain->last_link();
|
||||
if (!dest_proof.empty()) {
|
||||
auto d_res = vm::std_boc_deserialize(std::move(dest_proof));
|
||||
if (d_res.is_error()) {
|
||||
return td::Status::Error("cannot deserialize dest_proof in a block proof link: "s +
|
||||
d_res.move_as_error().to_string());
|
||||
}
|
||||
link.dest_proof = d_res.move_as_ok();
|
||||
}
|
||||
auto d_res = vm::std_boc_deserialize(std::move(proof));
|
||||
if (d_res.is_error()) {
|
||||
return td::Status::Error("cannot deserialize proof in a block proof link: "s + d_res.move_as_error().to_string());
|
||||
}
|
||||
link.proof = d_res.move_as_ok();
|
||||
if (!link.is_fwd) {
|
||||
d_res = vm::std_boc_deserialize(std::move(state_proof));
|
||||
if (d_res.is_error()) {
|
||||
return td::Status::Error("cannot deserialize state_proof in a block proof link: "s +
|
||||
d_res.move_as_error().to_string());
|
||||
}
|
||||
link.state_proof = d_res.move_as_ok();
|
||||
}
|
||||
LOG(DEBUG) << "deserialized a " << (link.is_fwd ? "forward" : "backward") << " BlkProofLink from "
|
||||
<< link.from.to_str() << " to " << link.to.to_str() << " with " << link.signatures.size()
|
||||
<< " signatures";
|
||||
}
|
||||
LOG(DEBUG) << "deserialized a BlkProofChain of " << chain->link_count() << " links";
|
||||
return std::move(chain);
|
||||
}
|
||||
|
||||
void TestNode::got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, td::BufferSlice pchain) {
|
||||
LOG(INFO) << "got block proof from " << from.to_str() << " to "
|
||||
<< ((mode & 1) ? to.to_str() : "last masterchain block") << " with mode=" << mode << " (" << pchain.size()
|
||||
<< " bytes)";
|
||||
auto res = deserialize_proof_chain(std::move(pchain));
|
||||
auto r_f = ton::fetch_tl_object<ton::lite_api::liteServer_partialBlockProof>(std::move(pchain), true);
|
||||
if (r_f.is_error()) {
|
||||
LOG(ERROR) << "cannot deserialize liteServer.partialBlockProof: " << r_f.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto f = r_f.move_as_ok();
|
||||
auto res = liteclient::deserialize_proof_chain(std::move(f));
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << "cannot deserialize liteServer.partialBlockProof: " << res.move_as_error();
|
||||
return;
|
||||
|
|
|
@ -150,7 +150,6 @@ class TestNode : public td::actor::Actor {
|
|||
std::vector<TransId> trans, td::BufferSlice proof);
|
||||
bool get_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode);
|
||||
void got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, td::BufferSlice res);
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> deserialize_proof_chain(td::BufferSlice pchain);
|
||||
bool do_parse_line();
|
||||
bool show_help(std::string command);
|
||||
std::string get_word(char delim = ' ');
|
||||
|
|
|
@ -42,12 +42,18 @@ class uint128_emulated {
|
|||
uint64 lo() const {
|
||||
return lo_;
|
||||
}
|
||||
uint64 rounded_hi() const {
|
||||
return hi_ + (lo_ >> 63);
|
||||
}
|
||||
static uint128 from_signed(int64 x) {
|
||||
if (x >= 0) {
|
||||
return uint128(0, x);
|
||||
}
|
||||
return uint128(std::numeric_limits<uint64>::max(), static_cast<uint64>(x));
|
||||
}
|
||||
static uint128 from_unsigned(uint64 x) {
|
||||
return uint128(0, x);
|
||||
}
|
||||
|
||||
uint128 add(uint128 other) const {
|
||||
uint128 res(other.hi() + hi(), other.lo() + lo());
|
||||
|
@ -212,13 +218,18 @@ class uint128_intrinsic {
|
|||
static uint128 from_signed(int64 x) {
|
||||
return uint128(static_cast<ValueT>(x));
|
||||
}
|
||||
static uint128 from_unsigned(uint64 x) {
|
||||
return uint128(static_cast<ValueT>(x));
|
||||
}
|
||||
uint64 hi() const {
|
||||
return uint64(value() >> 64);
|
||||
}
|
||||
uint64 lo() const {
|
||||
return uint64(value() & std::numeric_limits<uint64>::max());
|
||||
}
|
||||
|
||||
uint64 rounded_hi() const {
|
||||
return uint64((value() + (1ULL << 63)) >> 64);
|
||||
}
|
||||
uint128 add(uint128 other) const {
|
||||
return uint128(value() + other.value());
|
||||
}
|
||||
|
|
|
@ -50,5 +50,7 @@ Test_VM_unhandled_exception_1_default 0abe2740dd3b6a6b91eb67fee573f638086fecc726
|
|||
Test_VM_unhandled_exception_4_default 412cbfe13745fde55cdcc5e41d7b15ba4d09f0e723f8e4421ae0b7066ca07b8f
|
||||
Test_VM_unhandled_exception_5_default d760e540cd9c200c207f71c540cdaf06d11c96e32ec19860b9c1046cb1e38855
|
||||
Test_base64_main_default e90d541bd810871c4a81e162f1fffb555024b72807cb895414d16bc11494b789
|
||||
Test_bigexp_main_default 45a1f51fb2abcc1ebf8569e1a57bebee04c334a15e03535ff5869bc9a9db8956
|
||||
Test_bits256_scan_main_default 3ec7434e1cabc8e08eb2e79064e67747ffbfed177473c7873b88c144a7ed6f42
|
||||
Test_crc16_main_default 84abc15310c7d8fe3344a73e97ad3c8d2e23645e1f8e67f8c8756bdf5012ebd6
|
||||
Test_uint64_exp_main_default 263a1a9b021031de86dd72f75ecc42d3024a39bf69133e7a1028afad67db6df8
|
||||
|
|
|
@ -72,4 +72,5 @@ liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode
|
|||
liteServer.getConfigAll mode:# id:tonNode.blockIdExt = liteServer.ConfigInfo;
|
||||
liteServer.getConfigParams mode:# id:tonNode.blockIdExt param_list:(vector int) = liteServer.ConfigInfo;
|
||||
|
||||
liteServer.queryPrefix = Object;
|
||||
liteServer.query data:bytes = Object;
|
||||
|
|
Binary file not shown.
|
@ -362,6 +362,7 @@ tonNode.prepareZeroState block:tonNode.blockIdExt = tonNode.PreparedState;
|
|||
tonNode.getNextKeyBlockIds block:tonNode.blockIdExt max_size:int = tonNode.KeyBlocks;
|
||||
tonNode.downloadBlock block:tonNode.blockIdExt = tonNode.Data;
|
||||
tonNode.downloadPersistentState block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.Data;
|
||||
tonNode.downloadPersistentStateSlice block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt offset:long max_size:long = tonNode.Data;
|
||||
tonNode.downloadZeroState block:tonNode.blockIdExt = tonNode.Data;
|
||||
tonNode.downloadBlockProof block:tonNode.blockIdExt = tonNode.Data;
|
||||
tonNode.downloadBlockProofLink block:tonNode.blockIdExt = tonNode.Data;
|
||||
|
|
Binary file not shown.
|
@ -18,7 +18,7 @@ ok = Ok;
|
|||
|
||||
options config:string keystore_directory:string = Options;
|
||||
|
||||
key public_key:bytes secret:secureBytes = Key;
|
||||
key public_key:string secret:secureBytes = Key;
|
||||
inputKey key:key local_password:secureBytes = InputKey;
|
||||
exportedKey word_list:vector<secureString> = ExportedKey;
|
||||
exportedPemKey pem:secureString = ExportedPemKey;
|
||||
|
@ -36,7 +36,7 @@ raw.message source:string destination:string value:int64 = raw.Message;
|
|||
raw.transaction data:bytes previous_transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
|
||||
raw.transactions transactions:vector<raw.Transaction> = raw.Transactions;
|
||||
|
||||
testWallet.initialAccountState public_key:bytes = testWallet.InitialAccountState;
|
||||
testWallet.initialAccountState public_key:string = testWallet.InitialAccountState;
|
||||
testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId = testWallet.AccountState;
|
||||
|
||||
testGiver.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId = testGiver.AccountState;
|
||||
|
@ -59,7 +59,7 @@ close = Ok;
|
|||
options.setConfig config:string = Ok;
|
||||
|
||||
createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key;
|
||||
deleteKey public_key:bytes = Ok;
|
||||
deleteKey public_key:string = Ok;
|
||||
exportKey input_key:inputKey = ExportedKey;
|
||||
exportPemKey input_key:inputKey key_password:secureBytes = ExportedPemKey;
|
||||
exportEncryptedKey input_key:inputKey key_password:secureBytes = ExportedEncryptedKey;
|
||||
|
|
Binary file not shown.
|
@ -126,10 +126,11 @@ void gen_from_json_constructor(StringBuilder &sb, const T *constructor, bool is_
|
|||
sb << " TRY_RESULT(value, get_json_object_field(from, \"" << tl::simple::gen_cpp_name(arg.name)
|
||||
<< "\", JsonValue::Type::Null, true));\n";
|
||||
sb << " if (value.type() != JsonValue::Type::Null) {\n";
|
||||
if (arg.type->type == tl::simple::Type::Bytes) {
|
||||
if (arg.type->type == tl::simple::Type::Bytes || arg.type->type == tl::simple::Type::SecureBytes) {
|
||||
sb << " TRY_STATUS(from_json_bytes(to." << tl::simple::gen_cpp_field_name(arg.name) << ", value));\n";
|
||||
} else if (arg.type->type == tl::simple::Type::Vector &&
|
||||
arg.type->vector_value_type->type == tl::simple::Type::Bytes) {
|
||||
(arg.type->vector_value_type->type == tl::simple::Type::Bytes ||
|
||||
arg.type->vector_value_type->type == tl::simple::Type::SecureBytes)) {
|
||||
sb << " TRY_STATUS(from_json_vector_bytes(to." << tl::simple::gen_cpp_field_name(arg.name)
|
||||
<< ", value));\n";
|
||||
} else {
|
||||
|
|
|
@ -53,6 +53,8 @@ constexpr unsigned min_split_merge_interval = 30; // split/merge interval must
|
|||
constexpr unsigned max_split_merge_delay =
|
||||
1000; // end of split/merge interval must be at most 1000 seconds in the future
|
||||
|
||||
enum GlobalCapabilities { capIhrEnabled = 1, capCreateStatsEnabled = 2 };
|
||||
|
||||
inline int shard_pfx_len(ShardId shard) {
|
||||
return shard ? 63 - td::count_trailing_zeroes_non_zero64(shard) : 0;
|
||||
}
|
||||
|
|
|
@ -50,9 +50,9 @@ add_library(tonlib STATIC ${TONLIB_SOURCE})
|
|||
target_include_directories(tonlib PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
$<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>
|
||||
)
|
||||
target_link_libraries(tonlib PRIVATE tdactor adnllite tl_lite_api tl-lite-utils ton_crypto ton_block)
|
||||
target_link_libraries(tonlib PRIVATE tdactor adnllite tl_lite_api tl-lite-utils ton_crypto ton_block lite-client-common)
|
||||
target_link_libraries(tonlib PUBLIC tdutils tl_tonlib_api)
|
||||
|
||||
if (TONLIB_ENABLE_JNI AND NOT ANDROID) # jni is available by default on Android
|
||||
|
@ -119,7 +119,8 @@ install(TARGETS tonlibjson TonlibJson EXPORT Tonlib
|
|||
)
|
||||
|
||||
if (NOT TON_USE_ABSEIL)
|
||||
install(TARGETS tdnet keys crc32c tdactor adnllite tl_api tl-utils tl_lite_api tl-lite-utils ton_crypto ton_block tdutils tl_tonlib_api tonlib Tonlib EXPORT Tonlib
|
||||
install(TARGETS tdnet keys crc32c tdactor adnllite tl_api tl-utils tl_lite_api tl-lite-utils ton_crypto ton_block
|
||||
tdutils tl_tonlib_api tonlib lite-client-common Tonlib EXPORT Tonlib
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
|
|
|
@ -65,6 +65,55 @@ td::Result<Config> Config::parse(std::string str) {
|
|||
client.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
|
||||
res.lite_clients.push_back(std::move(client));
|
||||
}
|
||||
|
||||
TRY_RESULT(validator_obj,
|
||||
td::get_json_object_field(json.get_object(), "validator", td::JsonValue::Type::Object, false));
|
||||
auto &validator = validator_obj.get_object();
|
||||
TRY_RESULT(validator_type, td::get_json_object_string_field(validator, "@type", false));
|
||||
if (validator_type != "validator.config.global") {
|
||||
return td::Status::Error("Invalid config (7)");
|
||||
}
|
||||
TRY_RESULT(zero_state_obj, td::get_json_object_field(validator, "zero_state", td::JsonValue::Type::Object, false));
|
||||
auto &zero_state = zero_state_obj.get_object();
|
||||
|
||||
ton::WorkchainId zero_workchain_id;
|
||||
{
|
||||
TRY_RESULT(wc, td::get_json_object_int_field(zero_state, "workchain"));
|
||||
zero_workchain_id = wc;
|
||||
}
|
||||
ton::ShardId zero_shard_id; // uint64
|
||||
{
|
||||
TRY_RESULT(shard_id, td::get_json_object_long_field(zero_state, "shard"));
|
||||
zero_shard_id = static_cast<ton::ShardId>(shard_id);
|
||||
}
|
||||
ton::BlockSeqno zero_seqno;
|
||||
{
|
||||
TRY_RESULT(seqno, td::get_json_object_int_field(zero_state, "seqno"));
|
||||
zero_seqno = seqno;
|
||||
}
|
||||
|
||||
ton::RootHash zero_root_hash;
|
||||
{
|
||||
TRY_RESULT(hash_b64, td::get_json_object_string_field(zero_state, "root_hash"));
|
||||
TRY_RESULT(hash, td::base64_decode(hash_b64));
|
||||
if (hash.size() * 8 != ton::RootHash::size()) {
|
||||
return td::Status::Error("Invalid config (8)");
|
||||
}
|
||||
zero_root_hash = ton::RootHash(td::ConstBitPtr(td::Slice(hash).ubegin()));
|
||||
}
|
||||
ton::FileHash zero_file_hash;
|
||||
{
|
||||
TRY_RESULT(hash_b64, td::get_json_object_string_field(zero_state, "file_hash"));
|
||||
TRY_RESULT(hash, td::base64_decode(hash_b64));
|
||||
if (hash.size() * 8 != ton::FileHash::size()) {
|
||||
return td::Status::Error("Invalid config (9)");
|
||||
}
|
||||
zero_file_hash = ton::RootHash(td::ConstBitPtr(td::Slice(hash).ubegin()));
|
||||
}
|
||||
|
||||
res.zero_state_id = ton::BlockIdExt(zero_workchain_id, zero_shard_id, zero_seqno, std::move(zero_root_hash),
|
||||
std::move(zero_file_hash));
|
||||
|
||||
return res;
|
||||
}
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
#include "adnl/adnl-node-id.hpp"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
#include "ton/ton-types.h"
|
||||
|
||||
namespace tonlib {
|
||||
struct Config {
|
||||
|
@ -26,6 +27,7 @@ struct Config {
|
|||
ton::adnl::AdnlNodeIdFull adnl_id;
|
||||
td::IPAddress address;
|
||||
};
|
||||
ton::BlockIdExt zero_state_id;
|
||||
std::vector<LiteClient> lite_clients;
|
||||
static td::Result<Config> parse(std::string str);
|
||||
};
|
||||
|
|
|
@ -20,8 +20,13 @@
|
|||
|
||||
#include "ton/lite-tl.hpp"
|
||||
|
||||
#include "lite-client/lite-client-common.h"
|
||||
|
||||
namespace tonlib {
|
||||
LastBlock::LastBlock(ExtClientRef client, td::actor::ActorShared<> parent) {
|
||||
LastBlock::LastBlock(ExtClientRef client, ton::ZeroStateIdExt zero_state_id, ton::BlockIdExt last_block_id,
|
||||
td::actor::ActorShared<> parent) {
|
||||
zero_state_id_ = std::move(zero_state_id);
|
||||
mc_last_block_id_ = std::move(last_block_id);
|
||||
client_.set_client(client);
|
||||
parent_ = std::move(parent);
|
||||
}
|
||||
|
@ -36,7 +41,48 @@ void LastBlock::get_last_block(td::Promise<ton::BlockIdExt> promise) {
|
|||
void LastBlock::do_get_last_block() {
|
||||
client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
|
||||
[this](auto r_info) { this->on_masterchain_info(std::move(r_info)); });
|
||||
return;
|
||||
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||
client_.send_query(
|
||||
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(mc_last_block_id_), nullptr),
|
||||
[this, from = mc_last_block_id_](auto r_block_proof) { this->on_block_proof(from, std::move(r_block_proof)); });
|
||||
}
|
||||
|
||||
td::Result<bool> LastBlock::process_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||
TRY_RESULT(block_proof, std::move(r_block_proof));
|
||||
LOG(ERROR) << to_string(block_proof);
|
||||
TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof)));
|
||||
if (chain->from != from) {
|
||||
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
||||
<< ", not from requested block " << from.to_str());
|
||||
}
|
||||
TRY_STATUS(chain->validate());
|
||||
update_mc_last_block(chain->to);
|
||||
return chain->complete;
|
||||
}
|
||||
|
||||
void LastBlock::on_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||
auto r_is_ready = process_block_proof(from, std::move(r_block_proof));
|
||||
if (r_is_ready.is_error()) {
|
||||
LOG(WARNING) << "Failed liteServer_getBlockProof " << r_block_proof.error();
|
||||
return;
|
||||
}
|
||||
auto is_ready = r_is_ready.move_as_ok();
|
||||
if (is_ready) {
|
||||
for (auto& promise : promises_) {
|
||||
auto copy = mc_last_block_id_;
|
||||
promise.set_value(std::move(copy));
|
||||
}
|
||||
promises_.clear();
|
||||
} else {
|
||||
do_get_last_block();
|
||||
}
|
||||
}
|
||||
|
||||
void LastBlock::on_masterchain_info(
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info) {
|
||||
if (r_info.is_ok()) {
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
namespace tonlib {
|
||||
class LastBlock : public td::actor::Actor {
|
||||
public:
|
||||
explicit LastBlock(ExtClientRef client, td::actor::ActorShared<> parent);
|
||||
explicit LastBlock(ExtClientRef client, ton::ZeroStateIdExt zero_state_id, ton::BlockIdExt last_block_id,
|
||||
td::actor::ActorShared<> parent);
|
||||
|
||||
void get_last_block(td::Promise<ton::BlockIdExt> promise);
|
||||
|
||||
|
@ -39,6 +40,11 @@ class LastBlock : public td::actor::Actor {
|
|||
|
||||
void do_get_last_block();
|
||||
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
||||
void on_block_proof(ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
||||
td::Result<bool> process_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
||||
|
||||
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
|
||||
|
||||
|
|
|
@ -280,7 +280,11 @@ void TonlibClient::init_ext_client() {
|
|||
raw_client_ = ExtClientLazy::create(lite_client.adnl_id, lite_client.address,
|
||||
td::make_unique<Callback>(td::actor::actor_shared()));
|
||||
ref_cnt_++;
|
||||
raw_last_block_ = td::actor::create_actor<LastBlock>("LastBlock", get_client_ref(), td::actor::actor_shared());
|
||||
raw_last_block_ = td::actor::create_actor<LastBlock>(
|
||||
"LastBlock", get_client_ref(),
|
||||
ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
|
||||
config_.zero_state_id.file_hash),
|
||||
config_.zero_state_id, td::actor::actor_shared());
|
||||
client_.set_client(get_client_ref());
|
||||
}
|
||||
|
||||
|
@ -382,7 +386,8 @@ td::Result<block::StdAddress> get_account_address(const tonlib_api::raw_initialA
|
|||
}
|
||||
|
||||
td::Result<block::StdAddress> get_account_address(const tonlib_api::testWallet_initialAccountState& test_wallet_state) {
|
||||
auto key = td::Ed25519::PublicKey(td::SecureString(test_wallet_state.public_key_));
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(test_wallet_state.public_key_));
|
||||
auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key));
|
||||
return GenericAccount::get_address(0 /*zerochain*/, TestWallet::get_init_state(key));
|
||||
}
|
||||
|
||||
|
@ -733,7 +738,8 @@ td::Result<KeyStorage::InputKey> from_tonlib(tonlib_api::inputKey& input_key) {
|
|||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
|
||||
return KeyStorage::InputKey{{td::SecureString(input_key.key_->public_key_), std::move(input_key.key_->secret_)},
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(input_key.key_->public_key_));
|
||||
return KeyStorage::InputKey{{td::SecureString(key_bytes.key), std::move(input_key.key_->secret_)},
|
||||
std::move(input_key.local_password_)};
|
||||
}
|
||||
|
||||
|
@ -909,7 +915,8 @@ td::Status TonlibClient::do_request(const tonlib_api::createNewKey& request,
|
|||
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
|
||||
TRY_RESULT(key, key_storage_.create_new_key(std::move(request.local_password_), std::move(request.mnemonic_password_),
|
||||
std::move(request.random_extra_seed_)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice()));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key_bytes.serialize(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -926,7 +933,8 @@ td::Status TonlibClient::do_request(const tonlib_api::exportKey& request,
|
|||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::deleteKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
TRY_STATUS(key_storage_.delete_key(request.public_key_));
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(request.public_key_));
|
||||
TRY_STATUS(key_storage_.delete_key(key_bytes.key));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -938,7 +946,8 @@ td::Status TonlibClient::do_request(const tonlib_api::importKey& request,
|
|||
}
|
||||
TRY_RESULT(key, key_storage_.import_key(std::move(request.local_password_), std::move(request.mnemonic_password_),
|
||||
KeyStorage::ExportedKey{std::move(request.exported_key_->word_list_)}));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice()));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key_bytes.serialize(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -951,9 +960,9 @@ td::Status TonlibClient::do_request(const tonlib_api::exportPemKey& request,
|
|||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
|
||||
KeyStorage::InputKey input_key{
|
||||
{td::SecureString(request.input_key_->key_->public_key_), std::move(request.input_key_->key_->secret_)},
|
||||
std::move(request.input_key_->local_password_)};
|
||||
TRY_RESULT(key_bytes, block::PublicKey::parse(request.input_key_->key_->public_key_));
|
||||
KeyStorage::InputKey input_key{{td::SecureString(key_bytes.key), std::move(request.input_key_->key_->secret_)},
|
||||
std::move(request.input_key_->local_password_)};
|
||||
TRY_RESULT(exported_pem_key, key_storage_.export_pem_key(std::move(input_key), std::move(request.key_password_)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::exportedPemKey>(std::move(exported_pem_key.pem)));
|
||||
return td::Status::OK();
|
||||
|
@ -966,7 +975,8 @@ td::Status TonlibClient::do_request(const tonlib_api::importPemKey& request,
|
|||
}
|
||||
TRY_RESULT(key, key_storage_.import_pem_key(std::move(request.local_password_), std::move(request.key_password_),
|
||||
KeyStorage::ExportedPemKey{std::move(request.exported_key_->pem_)}));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice()));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key_bytes.serialize(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -989,7 +999,8 @@ td::Status TonlibClient::do_request(const tonlib_api::importEncryptedKey& reques
|
|||
TRY_RESULT(key, key_storage_.import_encrypted_key(
|
||||
std::move(request.local_password_), std::move(request.key_password_),
|
||||
KeyStorage::ExportedEncryptedKey{std::move(request.exported_encrypted_key_->data_)}));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
TRY_RESULT(key_bytes, block::PublicKey::from_bytes(key.public_key.as_slice()));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key_bytes.serialize(), std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
@ -1001,11 +1012,10 @@ td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& reque
|
|||
if (!request.input_key_->key_) {
|
||||
return td::Status::Error(400, "Field key must not be empty");
|
||||
}
|
||||
KeyStorage::InputKey input_key{
|
||||
{td::SecureString(request.input_key_->key_->public_key_), std::move(request.input_key_->key_->secret_)},
|
||||
std::move(request.input_key_->local_password_)};
|
||||
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
|
||||
TRY_RESULT(key, key_storage_.change_local_password(std::move(input_key), std::move(request.new_local_password_)));
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key.public_key.as_slice().str(), std::move(key.secret)));
|
||||
promise.set_value(
|
||||
tonlib_api::make_object<tonlib_api::key>(request.input_key_->key_->public_key_, std::move(key.secret)));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::SecureString buf(10000);
|
||||
td::StringBuilder sb(buf.as_mutable_slice());
|
||||
for (auto& info : keys_) {
|
||||
sb << td::base64_encode(info.public_key) << " " << td::base64_encode(info.secret) << "\n";
|
||||
sb << info.public_key << " " << td::base64_encode(info.secret) << "\n";
|
||||
}
|
||||
LOG_IF(FATAL, sb.is_error()) << "StringBuilder overflow";
|
||||
td::atomic_write_file(key_db_path(), sb.as_cslice());
|
||||
|
@ -247,21 +247,20 @@ class TonlibCli : public td::actor::Actor {
|
|||
auto db = r_db.move_as_ok();
|
||||
td::ConstParser parser(db.as_slice());
|
||||
while (true) {
|
||||
auto public_key_b64 = parser.read_word();
|
||||
auto public_key = parser.read_word();
|
||||
auto secret_b64 = parser.read_word();
|
||||
if (secret_b64.empty()) {
|
||||
break;
|
||||
}
|
||||
auto r_public_key = td::base64_decode(public_key_b64);
|
||||
auto r_secret = td::base64_decode_secure(secret_b64);
|
||||
if (r_public_key.is_error() || r_secret.is_error()) {
|
||||
LOG(ERROR) << "Invalid key database at " << key_db_path();
|
||||
if (r_secret.is_error()) {
|
||||
LOG(ERROR) << "Invalid secret database at " << key_db_path();
|
||||
}
|
||||
|
||||
KeyInfo info;
|
||||
info.public_key = r_public_key.move_as_ok();
|
||||
info.public_key = public_key.str();
|
||||
info.secret = r_secret.move_as_ok();
|
||||
LOG(INFO) << td::buffer_to_hex(info.public_key);
|
||||
LOG(INFO) << info.public_key;
|
||||
|
||||
keys_.push_back(std::move(info));
|
||||
}
|
||||
|
@ -271,7 +270,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::TerminalIO::out() << "Got " << keys_.size() << " keys"
|
||||
<< "\n";
|
||||
for (size_t i = 0; i < keys_.size(); i++) {
|
||||
td::TerminalIO::out() << " #" << i << ": " << td::buffer_to_hex(keys_[i].public_key) << "\n";
|
||||
td::TerminalIO::out() << " #" << i << ": " << keys_[i].public_key << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,7 +301,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
size_t res = 0;
|
||||
size_t cnt = 0;
|
||||
for (size_t i = 0; i < keys_.size(); i++) {
|
||||
auto full_key = td::to_lower(td::buffer_to_hex(keys_[i].public_key));
|
||||
auto full_key = td::to_lower(keys_[i].public_key);
|
||||
if (td::begins_with(full_key, prefix)) {
|
||||
res = i;
|
||||
cnt++;
|
||||
|
@ -452,27 +451,22 @@ class TonlibCli : public td::actor::Actor {
|
|||
cont_ = [this](td::Slice key) { this->get_state(key); };
|
||||
return;
|
||||
}
|
||||
auto r_key_i = to_key_i(key);
|
||||
if (r_key_i.is_error()) {
|
||||
auto r_address = to_account_address(key, false);
|
||||
if (r_address.is_error()) {
|
||||
td::TerminalIO::out() << "Unknown key id: [" << key << "]\n";
|
||||
return;
|
||||
}
|
||||
auto key_i = r_key_i.move_as_ok();
|
||||
auto address = r_address.move_as_ok();
|
||||
using tonlib_api::make_object;
|
||||
auto obj = tonlib::TonlibClient::static_request(make_object<tonlib_api::testWallet_getAccountAddress>(
|
||||
make_object<tonlib_api::testWallet_initialAccountState>(keys_[key_i].public_key)));
|
||||
if (obj->get_id() == tonlib_api::error::ID) {
|
||||
td::TerminalIO::out() << "Can't get state of [" << key << "] : " << to_string(obj);
|
||||
}
|
||||
send_query(
|
||||
make_object<tonlib_api::generic_getAccountState>(ton::move_tl_object_as<tonlib_api::accountAddress>(obj)),
|
||||
[](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
});
|
||||
send_query(make_object<tonlib_api::generic_getAccountState>(
|
||||
ton::move_tl_object_as<tonlib_api::accountAddress>(std::move(address.address))),
|
||||
[](auto r_res) {
|
||||
if (r_res.is_error()) {
|
||||
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";
|
||||
return;
|
||||
}
|
||||
td::TerminalIO::out() << to_string(r_res.ok());
|
||||
});
|
||||
}
|
||||
|
||||
void transfer(td::Slice from, td::Slice to, td::Slice grams) {
|
||||
|
@ -497,6 +491,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::Slice password) mutable { this->transfer(std::move(from), std::move(to), grams, password); };
|
||||
return;
|
||||
}
|
||||
transfer(r_from_address.move_as_ok(), r_to_address.move_as_ok(), r_grams.move_as_ok(), "");
|
||||
}
|
||||
|
||||
void transfer(Address from, Address to, td::uint64 grams, td::Slice password) {
|
||||
|
|
|
@ -1087,7 +1087,7 @@ void ValidatorEngine::load_local_config(td::Promise<td::Unit> promise) {
|
|||
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false, ig.get_promise());
|
||||
}
|
||||
|
||||
td::uint32 max_time = 1;
|
||||
td::uint32 max_time = 2000000000;
|
||||
|
||||
if (conf.dht_.size() > 0) {
|
||||
for (auto &d : conf.dht_) {
|
||||
|
|
|
@ -138,7 +138,35 @@ void FileDb::load_file(RefId ref_id, td::Promise<td::BufferSlice> promise) {
|
|||
}
|
||||
});
|
||||
|
||||
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), std::move(P)).release();
|
||||
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), 0, -1, std::move(P)).release();
|
||||
}
|
||||
|
||||
void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise) {
|
||||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
auto R = get_block(ref_id_hash);
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto v = R.move_as_ok();
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise), file_hash = v.file_hash](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
auto data = R.move_as_ok();
|
||||
if (file_hash != sha256_bits256(data.as_slice())) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "db error: bad file hash"));
|
||||
} else {
|
||||
promise.set_value(std::move(data));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), offset, max_size, std::move(P))
|
||||
.release();
|
||||
}
|
||||
|
||||
void FileDb::check_file(RefId ref_id, td::Promise<bool> promise) {
|
||||
|
|
|
@ -144,6 +144,7 @@ class FileDb : public td::actor::Actor {
|
|||
void store_file(RefId ref_id, td::BufferSlice data, td::Promise<FileHash> promise);
|
||||
void store_file_continue(RefId ref_id, FileHash file_hash, std::string path, td::Promise<FileHash> promise);
|
||||
void load_file(RefId ref_id, td::Promise<td::BufferSlice> promise);
|
||||
void load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise);
|
||||
void check_file(RefId ref_id, td::Promise<bool> promise);
|
||||
|
||||
void start_up() override;
|
||||
|
|
|
@ -82,7 +82,7 @@ class WriteFile : public td::actor::Actor {
|
|||
class ReadFile : public td::actor::Actor {
|
||||
public:
|
||||
void start_up() override {
|
||||
auto S = td::read_file(file_name_);
|
||||
auto S = td::read_file(file_name_, max_length_, offset_);
|
||||
if (S.is_ok()) {
|
||||
promise_.set_result(S.move_as_ok());
|
||||
} else {
|
||||
|
@ -92,12 +92,14 @@ class ReadFile : public td::actor::Actor {
|
|||
}
|
||||
stop();
|
||||
}
|
||||
ReadFile(std::string file_name, td::Promise<td::BufferSlice> promise)
|
||||
: file_name_(file_name), promise_(std::move(promise)) {
|
||||
ReadFile(std::string file_name, td::int64 offset, td::int64 max_length, td::Promise<td::BufferSlice> promise)
|
||||
: file_name_(file_name), offset_(offset), max_length_(max_length), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string file_name_;
|
||||
td::int64 offset_;
|
||||
td::int64 max_length_;
|
||||
td::Promise<td::BufferSlice> promise_;
|
||||
};
|
||||
|
||||
|
|
|
@ -299,6 +299,13 @@ void RootDb::get_persistent_state_file(BlockIdExt block_id, BlockIdExt mastercha
|
|||
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_persistent_state_file_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::int64 offset,
|
||||
td::int64 max_size, td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(archive_db_, &FileDb::load_file_slice,
|
||||
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, offset, max_size,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::check_persistent_state_file_exists(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<bool> promise) {
|
||||
td::actor::send_closure(archive_db_, &FileDb::check_file,
|
||||
|
|
|
@ -73,6 +73,8 @@ class RootDb : public Db {
|
|||
td::Promise<td::Unit> promise) override;
|
||||
void get_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void get_persistent_state_file_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::int64 offset,
|
||||
td::int64 max_length, td::Promise<td::BufferSlice> promise) override;
|
||||
void check_persistent_state_file_exists(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<bool> promise) override;
|
||||
void store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) override;
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace validator {
|
|||
|
||||
void StaticFilesDb::load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
|
||||
auto path = path_ + "/" + file_hash.to_hex();
|
||||
td::actor::create_actor<db::ReadFile>("read file", path, std::move(promise)).release();
|
||||
td::actor::create_actor<db::ReadFile>("read file", path, 0, -1, std::move(promise)).release();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -67,7 +67,7 @@ void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_maste
|
|||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
|
||||
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, PublicKeyHash local_id, td::Ref<ValidatorSet> validator_set,
|
||||
std::vector<BlockIdExt> prev, Ed25519_PublicKey local_id, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise);
|
||||
void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,
|
||||
|
|
|
@ -374,6 +374,23 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
|
|||
masterchain_block_id, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix("failed to get state from db: "));
|
||||
return;
|
||||
}
|
||||
|
||||
promise.set_value(R.move_as_ok());
|
||||
});
|
||||
auto block_id = create_block_id(query.block_);
|
||||
auto masterchain_block_id = create_block_id(query.masterchain_block_);
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_slice, block_id,
|
||||
masterchain_block_id, query.offset_, query.max_size_, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto B = fetch_tl_object<ton_api::Function>(std::move(query), true);
|
||||
|
|
|
@ -78,6 +78,8 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentState &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
// void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query,
|
||||
// td::Promise<td::BufferSlice> promise);
|
||||
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
|
|
|
@ -88,13 +88,14 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
auto usage_cell = vm::UsageCell::create(block_root_, usage_tree->root_ptr());
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::ExtBlkRef::Record mcref{}; // _ ExtBlkRef = BlkMasterInfo;
|
||||
block::CurrencyCollection fees;
|
||||
ShardIdFull shard;
|
||||
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no &&
|
||||
block::gen::BlkPrevInfo{info.after_merge}.validate_ref(info.prev_ref) &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
tlb::unpack_cell(std::move(blk.extra), extra) && block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) &&
|
||||
(!info.not_master || tlb::unpack_cell(info.master_ref, mcref)))) {
|
||||
return fatal_error("cannot unpack block header");
|
||||
}
|
||||
|
@ -126,10 +127,9 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
}
|
||||
// 4. visit validator-set related fields in key blocks
|
||||
if (is_key_block_) {
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
mc_extra.key_block && mc_extra.config.not_null())) {
|
||||
if (!(tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && mc_extra.key_block &&
|
||||
mc_extra.config.not_null())) {
|
||||
return fatal_error("cannot unpack extra header of key masterchain block "s + blk_id.to_str());
|
||||
}
|
||||
auto cfg = block::Config::unpack_config(std::move(mc_extra.config));
|
||||
|
@ -156,10 +156,8 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
mc_blkid_.root_hash = mcref.root_hash;
|
||||
mc_blkid_.file_hash = mcref.file_hash;
|
||||
} else if (!is_key_block_) {
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
!mc_extra.key_block)) {
|
||||
if (!(tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && !mc_extra.key_block)) {
|
||||
return fatal_error("extra header of non-key masterchain block "s + blk_id.to_str() +
|
||||
" is invalid or contains extra information reserved for key blocks only");
|
||||
}
|
||||
|
@ -332,8 +330,8 @@ void AcceptBlockQuery::written_block_data() {
|
|||
if (is_fake_) {
|
||||
signatures_ = Ref<BlockSignatureSetQ>(create_signature_set(std::vector<BlockSignature>{}));
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_signatures, handle_, signatures_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_signatures, handle_,
|
||||
signatures_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_block_signatures);
|
||||
});
|
||||
|
@ -367,8 +365,8 @@ void AcceptBlockQuery::written_block_info() {
|
|||
td::actor::send_closure(manager_, &ValidatorManager::wait_prev_block_state, handle_, priority(), timeout_,
|
||||
std::move(P));
|
||||
} else {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, priority(), timeout_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, priority(),
|
||||
timeout_, [SelfId = actor_id(this)](td::Result<td::Ref<BlockData>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_block_data,
|
||||
R.move_as_ok());
|
||||
|
@ -408,8 +406,8 @@ void AcceptBlockQuery::got_prev_state(td::Ref<ShardState> state) {
|
|||
|
||||
handle_->set_split(state_->before_split());
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_, state_,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_state, handle_,
|
||||
state_, [SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::written_state, R.move_as_ok());
|
||||
});
|
||||
|
@ -481,8 +479,8 @@ void AcceptBlockQuery::got_last_mc_block(std::pair<td::Ref<MasterchainState>, Bl
|
|||
if (last_mc_id_.id.seqno < mc_blkid_.id.seqno) {
|
||||
VLOG(VALIDATOR_DEBUG) << "shardchain block refers to newer masterchain block " << mc_blkid_.to_str()
|
||||
<< ", trying to obtain it";
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(), timeout_,
|
||||
[SelfId = actor_id(this)](td::Result<Ref<ShardState>> R) {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(),
|
||||
timeout_, [SelfId = actor_id(this)](td::Result<Ref<ShardState>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_mc_state,
|
||||
R.move_as_ok());
|
||||
|
@ -588,7 +586,7 @@ void AcceptBlockQuery::require_proof_link(BlockIdExt id) {
|
|||
CHECK(ton::ShardIdFull(id) == ton::ShardIdFull(id_));
|
||||
CHECK(id.id.seqno == id_.id.seqno - 1 - proof_links_.size());
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_proof_link_short, id, timeout_,
|
||||
[SelfId = actor_id(this), id](td::Result<Ref<ProofLink>> R) {
|
||||
[ SelfId = actor_id(this), id ](td::Result<Ref<ProofLink>> R) {
|
||||
check_send_error(SelfId, R) ||
|
||||
td::actor::send_closure_bool(SelfId, &AcceptBlockQuery::got_proof_link, id,
|
||||
R.move_as_ok());
|
||||
|
@ -647,9 +645,15 @@ bool AcceptBlockQuery::unpack_proof_link(BlockIdExt id, Ref<ProofLink> proof_lin
|
|||
}
|
||||
try {
|
||||
block::gen::Block::Record block;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
if (!(tlb::unpack_cell(virt_root, block) && block::gen::t_ValueFlow.force_validate_ref(block.value_flow))) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() + " does not contain value flow information");
|
||||
}
|
||||
/* TEMP (uncomment later)
|
||||
if (!tlb::unpack_cell(std::move(block.extra), extra)) {
|
||||
return fatal_error("block proof link for block "s + id.to_str() + " does not contain BlockExtra information");
|
||||
}
|
||||
*/
|
||||
} catch (vm::VmError& err) {
|
||||
return fatal_error("error unpacking proof link for block "s + id.to_str() + " : " + err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
|
|
|
@ -218,12 +218,19 @@ bool CheckProof::init_parse(bool is_aux) {
|
|||
if (is_key_block_ && !shard.is_masterchain()) {
|
||||
return fatal_error("a non-masterchain block cannot be a key block");
|
||||
}
|
||||
block::gen::BlockExtra::Record extra;
|
||||
if (!is_aux) {
|
||||
/* FIXME: temp (uncommend later)
|
||||
if (!tlb::unpack_cell(std::move(blk.extra), extra)) {
|
||||
return fatal_error("cannot unpack extra header of block "s + blk_id.to_str());
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (is_key_block_ && !is_aux) {
|
||||
// visit validator-set related fields in key blocks
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::McBlockExtra::Record mc_extra;
|
||||
if (!(tlb::unpack_cell(std::move(blk.extra), extra) && tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) &&
|
||||
mc_extra.key_block && mc_extra.config.not_null())) {
|
||||
if (!(tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && mc_extra.key_block &&
|
||||
mc_extra.config.not_null())) {
|
||||
return fatal_error("cannot unpack extra header of key masterchain block "s + blk_id.to_str());
|
||||
}
|
||||
auto cfg = block::Config::unpack_config(std::move(mc_extra.config));
|
||||
|
|
|
@ -55,12 +55,13 @@ class Collator final : public td::actor::Actor {
|
|||
bool block_full_{false};
|
||||
bool inbound_queues_empty_{false};
|
||||
bool libraries_changed_{false};
|
||||
bool prev_key_block_exists_{false};
|
||||
UnixTime min_ts;
|
||||
BlockIdExt min_mc_block_id;
|
||||
std::vector<BlockIdExt> prev_blocks;
|
||||
std::vector<Ref<ShardState>> prev_states;
|
||||
std::vector<Ref<BlockData>> prev_block_data;
|
||||
td::Bits256 created_by;
|
||||
Ed25519_PublicKey created_by_;
|
||||
Ref<ValidatorSet> validator_set;
|
||||
td::actor::ActorId<ValidatorManager> manager;
|
||||
td::Timestamp timeout;
|
||||
|
@ -78,7 +79,7 @@ class Collator final : public td::actor::Actor {
|
|||
|
||||
public:
|
||||
Collator(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
|
||||
Ref<ValidatorSet> validator_set, td::Bits256 collator_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<BlockCandidate> promise);
|
||||
~Collator() override = default;
|
||||
bool is_busy() const {
|
||||
|
@ -132,13 +133,15 @@ class Collator final : public td::actor::Actor {
|
|||
ton::LogicalTime prev_key_block_lt_;
|
||||
bool accept_msgs_{true};
|
||||
bool shard_conf_adjusted_{false};
|
||||
bool ihr_enabled_{false};
|
||||
bool create_stats_enabled_{false};
|
||||
td::uint64 overload_history_{0}, underload_history_{0};
|
||||
td::uint64 block_size_estimate_{};
|
||||
Ref<block::WorkchainInfo> wc_info_;
|
||||
std::vector<Ref<ShardTopBlockDescription>> shard_block_descr_;
|
||||
std::vector<Ref<ShardTopBlockDescrQ>> used_shard_block_descr_;
|
||||
std::unique_ptr<vm::Dictionary> shard_libraries_;
|
||||
Ref<vm::Cell> mc_state_extra;
|
||||
Ref<vm::Cell> mc_state_extra_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> account_dict;
|
||||
std::map<ton::StdSmcAddress, std::unique_ptr<block::Account>> accounts;
|
||||
std::vector<block::StoragePrices> storage_prices_;
|
||||
|
@ -162,6 +165,9 @@ class Collator final : public td::actor::Actor {
|
|||
std::unique_ptr<vm::AugmentedDictionary> in_msg_dict, out_msg_dict, out_msg_queue_, sibling_out_msg_queue_;
|
||||
std::unique_ptr<vm::Dictionary> ihr_pending;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> processed_upto_, sibling_processed_upto_;
|
||||
std::unique_ptr<vm::Dictionary> block_create_stats_;
|
||||
std::map<td::Bits256, int> block_create_count_;
|
||||
unsigned block_create_total_{0};
|
||||
std::vector<ExtMessage::Hash> bad_ext_msgs_, delay_ext_msgs_;
|
||||
Ref<vm::Cell> shard_account_blocks_; // ShardAccountBlocks
|
||||
std::vector<Ref<vm::Cell>> collated_roots_;
|
||||
|
@ -200,6 +206,7 @@ class Collator final : public td::actor::Actor {
|
|||
const block::CurrencyCollection& created);
|
||||
bool store_shard_fees(Ref<block::McShardHash> descr);
|
||||
bool import_new_shard_top_blocks();
|
||||
bool register_shard_block_creators(std::vector<td::Bits256> creator_list);
|
||||
bool init_block_limits();
|
||||
bool compute_minted_amount(block::CurrencyCollection& to_mint);
|
||||
bool init_value_create();
|
||||
|
@ -264,6 +271,9 @@ class Collator final : public td::actor::Actor {
|
|||
bool add_public_library(td::ConstBitPtr key, td::ConstBitPtr addr, Ref<vm::Cell> library);
|
||||
bool remove_public_library(td::ConstBitPtr key, td::ConstBitPtr addr);
|
||||
bool check_block_overload();
|
||||
bool update_block_creator_count(td::ConstBitPtr key, unsigned shard_incr, unsigned mc_incr);
|
||||
int creator_count_outdated(td::ConstBitPtr key, vm::CellSlice& cs);
|
||||
bool update_block_creator_stats();
|
||||
bool create_mc_state_extra();
|
||||
bool create_shard_state();
|
||||
td::Result<Ref<vm::Cell>> get_config_data_from_smc(const ton::StdSmcAddress& cfg_addr);
|
||||
|
|
|
@ -54,14 +54,14 @@ static inline bool dbg(int c) {
|
|||
}
|
||||
|
||||
Collator::Collator(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set, td::Bits256 collator_id,
|
||||
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise)
|
||||
: shard(shard)
|
||||
, min_ts(min_ts)
|
||||
, min_mc_block_id{min_masterchain_block_id}
|
||||
, prev_blocks(std::move(prev))
|
||||
, created_by(collator_id)
|
||||
, created_by_(collator_id)
|
||||
, validator_set(std::move(validator_set))
|
||||
, manager(manager)
|
||||
, timeout(timeout)
|
||||
|
@ -74,6 +74,10 @@ void Collator::start_up() {
|
|||
if (prev_blocks.size() > 1) {
|
||||
LOG(DEBUG) << "Previous block #2 is " << prev_blocks.at(1).to_str();
|
||||
}
|
||||
//if (created_by_.is_zero()) {
|
||||
// !!FIXME!! remove this debug later
|
||||
//td::as<td::uint32>(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
|
||||
//}
|
||||
// 1. check validity of parameters, especially prev_blocks, shard and min_mc_block_id
|
||||
if (shard.workchain != ton::masterchainId && shard.workchain != ton::basechainId) {
|
||||
fatal_error(-667, "can create block candidates only for masterchain (-1) and base workchain (0)");
|
||||
|
@ -161,12 +165,12 @@ void Collator::start_up() {
|
|||
// 2. learn latest masterchain state and block id
|
||||
LOG(DEBUG) << "sending get_top_masterchain_state_block() to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::get_top_masterchain_state_block,
|
||||
[self = get_self()](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res)->void {
|
||||
LOG(DEBUG) << "got answer to get_top_masterchain_state_block";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_mc_state, std::move(res));
|
||||
});
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_top_masterchain_state_block,
|
||||
[self = get_self()](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||
LOG(DEBUG) << "got answer to get_top_masterchain_state_block";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_mc_state,
|
||||
std::move(res));
|
||||
});
|
||||
}
|
||||
// 3. load previous block(s) and corresponding state(s)
|
||||
prev_states.resize(prev_blocks.size());
|
||||
|
@ -176,7 +180,7 @@ void Collator::start_up() {
|
|||
LOG(DEBUG) << "sending wait_block_state() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_blocks[i], priority(),
|
||||
timeout, [ self = get_self(), i ](td::Result<Ref<ShardState>> res) {
|
||||
timeout, [self = get_self(), i](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state query #" << i;
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_shard_state, i,
|
||||
std::move(res));
|
||||
|
@ -187,7 +191,7 @@ void Collator::start_up() {
|
|||
LOG(DEBUG) << "sending wait_block_data() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, prev_blocks[i], priority(),
|
||||
timeout, [ self = get_self(), i ](td::Result<Ref<BlockData>> res) {
|
||||
timeout, [self = get_self(), i](td::Result<Ref<BlockData>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_data query #" << i;
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_block_data, i,
|
||||
std::move(res));
|
||||
|
@ -197,8 +201,8 @@ void Collator::start_up() {
|
|||
// 4. load external messages
|
||||
LOG(DEBUG) << "sending get_external_messages() query to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_external_messages,
|
||||
shard, [self = get_self()](td::Result<std::vector<Ref<ExtMessage>>> res)->void {
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_external_messages, shard,
|
||||
[self = get_self()](td::Result<std::vector<Ref<ExtMessage>>> res) -> void {
|
||||
LOG(DEBUG) << "got answer to get_external_messages() query";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_external_messages,
|
||||
std::move(res));
|
||||
|
@ -208,8 +212,8 @@ void Collator::start_up() {
|
|||
LOG(DEBUG) << "sending get_shard_blocks() query to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::get_shard_blocks,
|
||||
prev_blocks[0], [self = get_self()](td::Result<std::vector<Ref<ShardTopBlockDescription>>> res)->void {
|
||||
manager, &ValidatorManager::get_shard_blocks, prev_blocks[0],
|
||||
[self = get_self()](td::Result<std::vector<Ref<ShardTopBlockDescription>>> res) -> void {
|
||||
LOG(DEBUG) << "got answer to get_shard_blocks() query";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_shard_blocks, std::move(res));
|
||||
});
|
||||
|
@ -326,7 +330,7 @@ bool Collator::request_aux_mc_state(BlockSeqno seqno, Ref<MasterchainStateQ>& st
|
|||
LOG(DEBUG) << "sending auxiliary wait_block_state() query for " << blkid.to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, blkid, priority(), timeout,
|
||||
[ self = get_self(), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
[self = get_self(), blkid](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state query for " << blkid.to_str();
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_aux_shard_state,
|
||||
blkid, std::move(res));
|
||||
|
@ -414,8 +418,8 @@ void Collator::after_get_mc_state(td::Result<std::pair<Ref<MasterchainState>, Bl
|
|||
// NB. it is needed only for creating a correct ExtBlkRef reference to it, which requires start_lt and end_lt
|
||||
LOG(DEBUG) << "sending wait_block_data() query #-1 for " << mc_block_id_.to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, mc_block_id_, priority(),
|
||||
timeout, [self = get_self()](td::Result<Ref<BlockData>> res) {
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, mc_block_id_, priority(), timeout,
|
||||
[self = get_self()](td::Result<Ref<BlockData>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_data query #-1";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::after_get_block_data, -1,
|
||||
std::move(res));
|
||||
|
@ -497,7 +501,7 @@ bool Collator::unpack_last_mc_state() {
|
|||
auto res = block::ConfigInfo::extract_config(
|
||||
mc_state_root,
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needLibraries | block::ConfigInfo::needValidatorSet |
|
||||
block::ConfigInfo::needWorkchainInfo |
|
||||
block::ConfigInfo::needWorkchainInfo | block::ConfigInfo::needCapabilities |
|
||||
(is_masterchain() ? block::ConfigInfo::needAccountsRoot | block::ConfigInfo::needSpecialSmc : 0));
|
||||
if (res.is_error()) {
|
||||
td::Status err = res.move_as_error();
|
||||
|
@ -506,16 +510,18 @@ bool Collator::unpack_last_mc_state() {
|
|||
}
|
||||
config_ = res.move_as_ok();
|
||||
CHECK(config_);
|
||||
if (prev_mc_block_seqno > 0) {
|
||||
config_->set_block_id_ext(mc_block_id_);
|
||||
}
|
||||
config_->set_block_id_ext(mc_block_id_);
|
||||
global_id_ = config_->get_global_blockchain_id();
|
||||
ihr_enabled_ = config_->ihr_enabled();
|
||||
create_stats_enabled_ = config_->create_stats_enabled();
|
||||
shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
if (config_->get_last_key_block(prev_key_block_, prev_key_block_lt_)) {
|
||||
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
|
||||
if (prev_key_block_exists_) {
|
||||
prev_key_block_seqno_ = prev_key_block_.seqno();
|
||||
} else {
|
||||
prev_key_block_seqno_ = 0;
|
||||
}
|
||||
LOG(DEBUG) << "previous key block is " << prev_key_block_.to_str() << " (exists=" << prev_key_block_exists_ << ")";
|
||||
auto limits = config_->get_block_limits(is_masterchain());
|
||||
if (limits.is_error()) {
|
||||
return fatal_error(limits.move_as_error());
|
||||
|
@ -552,7 +558,7 @@ bool Collator::request_neighbor_msg_queues() {
|
|||
LOG(DEBUG) << "neighbor #" << i << " : " << descr.blk_.to_str();
|
||||
++pending;
|
||||
send_closure_later(manager, &ValidatorManager::wait_block_message_queue_short, descr.blk_, priority(), timeout,
|
||||
[ self = get_self(), i ](td::Result<Ref<MessageQueue>> res) {
|
||||
[self = get_self(), i](td::Result<Ref<MessageQueue>> res) {
|
||||
td::actor::send_closure(std::move(self), &Collator::got_neighbor_out_queue, i, std::move(res));
|
||||
});
|
||||
++i;
|
||||
|
@ -716,7 +722,7 @@ bool Collator::split_last_state(block::ShardState& ss) {
|
|||
bool Collator::import_shard_state_data(block::ShardState& ss) {
|
||||
account_dict = std::move(ss.account_dict_);
|
||||
shard_libraries_ = std::move(ss.shard_libraries_);
|
||||
mc_state_extra = std::move(ss.mc_state_extra_);
|
||||
mc_state_extra_ = std::move(ss.mc_state_extra_);
|
||||
overload_history_ = ss.overload_history_;
|
||||
underload_history_ = ss.underload_history_;
|
||||
prev_state_utime_ = ss.utime_;
|
||||
|
@ -728,6 +734,7 @@ bool Collator::import_shard_state_data(block::ShardState& ss) {
|
|||
out_msg_queue_ = std::move(ss.out_msg_queue_);
|
||||
processed_upto_ = std::move(ss.processed_upto_);
|
||||
ihr_pending = std::move(ss.ihr_pending_);
|
||||
block_create_stats_ = std::move(ss.block_create_stats_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1250,6 +1257,8 @@ bool Collator::import_new_shard_top_blocks() {
|
|||
CHECK(ures.move_as_ok());
|
||||
store_shard_fees(std::move(prev_descr));
|
||||
store_shard_fees(std::move(descr));
|
||||
register_shard_block_creators(prev_bd->get_creator_list(prev_chain_len));
|
||||
register_shard_block_creators(sh_bd->get_creator_list(chain_len));
|
||||
used_shard_block_descr_.emplace_back(std::move(prev_bd));
|
||||
used_shard_block_descr_.emplace_back(sh_bd);
|
||||
tb_act += 2;
|
||||
|
@ -1284,6 +1293,7 @@ bool Collator::import_new_shard_top_blocks() {
|
|||
continue;
|
||||
}
|
||||
store_shard_fees(std::move(descr));
|
||||
register_shard_block_creators(sh_bd->get_creator_list(chain_len));
|
||||
shards_max_end_lt_ = std::max(shards_max_end_lt_, end_lt);
|
||||
LOG(INFO) << "updated top shard block information with " << sh_bd->block_id().to_str();
|
||||
CHECK(ures.move_as_ok());
|
||||
|
@ -1310,6 +1320,20 @@ bool Collator::import_new_shard_top_blocks() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Collator::register_shard_block_creators(std::vector<td::Bits256> creator_list) {
|
||||
for (const auto& x : creator_list) {
|
||||
LOG(DEBUG) << "registering block creator " << x.to_hex();
|
||||
if (!x.is_zero()) {
|
||||
auto res = block_create_count_.emplace(x, 1);
|
||||
if (!res.second) {
|
||||
(res.first->second)++;
|
||||
}
|
||||
block_create_total_++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collator::try_collate() {
|
||||
if (!preinit_complete) {
|
||||
LOG(DEBUG) << "running do_preinit()";
|
||||
|
@ -2912,34 +2936,34 @@ bool Collator::update_shard_config(const block::WorkchainSet& wc_set, const bloc
|
|||
WorkchainId wc_id{ton::workchainInvalid};
|
||||
Ref<block::WorkchainInfo> wc_info;
|
||||
ton::BlockSeqno& min_seqno = min_ref_mc_seqno_;
|
||||
return shard_conf_->process_sibling_shard_hashes([
|
||||
&wc_set, &wc_id, &wc_info, &ccvc, &min_seqno, now = now_, update_cc
|
||||
](block::McShardHash & cur, const block::McShardHash* sibling) {
|
||||
if (!cur.is_valid()) {
|
||||
return -2;
|
||||
}
|
||||
if (wc_id != cur.workchain()) {
|
||||
wc_id = cur.workchain();
|
||||
auto it = wc_set.find(wc_id);
|
||||
if (it == wc_set.end()) {
|
||||
wc_info.clear();
|
||||
} else {
|
||||
wc_info = it->second;
|
||||
}
|
||||
}
|
||||
min_seqno = std::min(min_seqno, cur.min_ref_mc_seqno_);
|
||||
return update_one_shard(cur, sibling, wc_info.get(), now, ccvc, update_cc);
|
||||
});
|
||||
return shard_conf_->process_sibling_shard_hashes(
|
||||
[&wc_set, &wc_id, &wc_info, &ccvc, &min_seqno, now = now_, update_cc](block::McShardHash& cur,
|
||||
const block::McShardHash* sibling) {
|
||||
if (!cur.is_valid()) {
|
||||
return -2;
|
||||
}
|
||||
if (wc_id != cur.workchain()) {
|
||||
wc_id = cur.workchain();
|
||||
auto it = wc_set.find(wc_id);
|
||||
if (it == wc_set.end()) {
|
||||
wc_info.clear();
|
||||
} else {
|
||||
wc_info = it->second;
|
||||
}
|
||||
}
|
||||
min_seqno = std::min(min_seqno, cur.min_ref_mc_seqno_);
|
||||
return update_one_shard(cur, sibling, wc_info.get(), now, ccvc, update_cc);
|
||||
});
|
||||
}
|
||||
|
||||
bool Collator::create_mc_state_extra() {
|
||||
if (!is_masterchain()) {
|
||||
CHECK(mc_state_extra.is_null());
|
||||
CHECK(mc_state_extra_.is_null());
|
||||
return true;
|
||||
}
|
||||
// should update mc_state_extra with a new McStateExtra
|
||||
block::gen::McStateExtra::Record state_extra;
|
||||
if (!tlb::unpack_cell(mc_state_extra, state_extra)) {
|
||||
if (!tlb::unpack_cell(mc_state_extra_, state_extra)) {
|
||||
return fatal_error("cannot unpack previous McStateExtra");
|
||||
}
|
||||
// 1. update config:ConfigParams
|
||||
|
@ -3003,7 +3027,7 @@ bool Collator::create_mc_state_extra() {
|
|||
return fatal_error("new ShardHashes is invalid");
|
||||
}
|
||||
// 4. check extension flags
|
||||
if (state_extra.r1.flags != 0) {
|
||||
if (state_extra.r1.flags & ~1) {
|
||||
return fatal_error(PSTRING() << "previous McStateExtra has unknown extension flags set (" << state_extra.r1.flags
|
||||
<< "), cannot handle these extensions");
|
||||
}
|
||||
|
@ -3052,13 +3076,14 @@ bool Collator::create_mc_state_extra() {
|
|||
CHECK(new_block_seqno > 0 && new_block_seqno == last_block_seqno + 1);
|
||||
vm::AugmentedDictionary dict{state_extra.r1.prev_blocks, 32, block::tlb::aug_OldMcBlocksInfo};
|
||||
vm::CellBuilder cb;
|
||||
LOG(DEBUG) << "previous state is a key state: " << config_->is_key_state();
|
||||
CHECK(cb.store_bool_bool(config_->is_key_state()) && store_prev_blk_ref(cb, false) &&
|
||||
dict.set_builder(td::BitArray<32>(last_block_seqno), cb, vm::Dictionary::SetMode::Add));
|
||||
state_extra.r1.prev_blocks = std::move(dict).extract_root();
|
||||
cb.reset();
|
||||
// 7. update after_key_block:Bool and last_key_block:(Maybe ExtBlkRef)
|
||||
state_extra.r1.after_key_block = is_key_block_;
|
||||
if (prev_key_block_seqno_) {
|
||||
if (prev_key_block_exists_) {
|
||||
// have non-trivial previous key block
|
||||
LOG(DEBUG) << "previous key block is " << prev_key_block_.to_str() << " lt " << prev_key_block_lt_;
|
||||
CHECK(cb.store_bool_bool(true) && store_ext_blk_ref_to(cb, prev_key_block_, prev_key_block_lt_));
|
||||
|
@ -3083,19 +3108,110 @@ bool Collator::create_mc_state_extra() {
|
|||
if (!global_balance_.pack_to(state_extra.global_balance)) {
|
||||
return fatal_error("cannot store global_balance");
|
||||
}
|
||||
// 9. pack new McStateExtra
|
||||
if (!tlb::pack(cb, state_extra) || !cb.finalize_to(mc_state_extra)) {
|
||||
// 9. update block creator stats
|
||||
if (!update_block_creator_stats()) {
|
||||
return fatal_error("cannot update BlockCreateStats in new masterchain state");
|
||||
}
|
||||
state_extra.r1.flags = (state_extra.r1.flags & ~1) | create_stats_enabled_;
|
||||
if (state_extra.r1.flags & 1) {
|
||||
vm::CellBuilder cb;
|
||||
// block_create_stats#17 counters:(HashmapE 256 CreatorStats) = BlockCreateStats;
|
||||
CHECK(cb.store_long_bool(0x17, 8) && cb.append_cellslice_bool(block_create_stats_->get_root()));
|
||||
auto cs = vm::load_cell_slice_ref(cb.finalize());
|
||||
state_extra.r1.block_create_stats = cs;
|
||||
if (verify >= 1) {
|
||||
if (!block::gen::t_BlockCreateStats.validate_csr(cs)) {
|
||||
cs->print_rec(std::cerr);
|
||||
block::gen::t_BlockCreateStats.print(std::cerr, *cs);
|
||||
return fatal_error("BlockCreateStats in the new masterchain state failed to pass automated validity checks");
|
||||
}
|
||||
}
|
||||
if (verbosity >= 4 * 1) {
|
||||
block::gen::t_BlockCreateStats.print(std::cerr, *cs);
|
||||
}
|
||||
} else {
|
||||
state_extra.r1.block_create_stats.clear();
|
||||
}
|
||||
// 10. pack new McStateExtra
|
||||
if (!tlb::pack(cb, state_extra) || !cb.finalize_to(mc_state_extra_)) {
|
||||
return fatal_error("cannot pack new McStateExtra");
|
||||
}
|
||||
if (verify >= 2) {
|
||||
LOG(INFO) << "verifying new McStateExtra";
|
||||
CHECK(block::gen::t_McStateExtra.validate_ref(mc_state_extra));
|
||||
CHECK(block::tlb::t_McStateExtra.validate_ref(mc_state_extra));
|
||||
CHECK(block::gen::t_McStateExtra.validate_ref(mc_state_extra_));
|
||||
CHECK(block::tlb::t_McStateExtra.validate_ref(mc_state_extra_));
|
||||
}
|
||||
LOG(INFO) << "McStateExtra created";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collator::update_block_creator_count(td::ConstBitPtr key, unsigned shard_incr, unsigned mc_incr) {
|
||||
LOG(DEBUG) << "increasing CreatorStats for " << key.to_hex(256) << " by (" << mc_incr << ", " << shard_incr << ")";
|
||||
block::DiscountedCounter mc_cnt, shard_cnt;
|
||||
auto cs = block_create_stats_->lookup(key, 256);
|
||||
if (!block::unpack_CreatorStats(std::move(cs), mc_cnt, shard_cnt)) {
|
||||
return fatal_error("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state");
|
||||
}
|
||||
// std::cerr << mc_cnt.to_str() << " " << shard_cnt.to_str() << std::endl;
|
||||
if (mc_incr && !mc_cnt.increase_by(mc_incr, now_)) {
|
||||
return fatal_error(PSTRING() << "cannot increase masterchain block counter in CreatorStats for " << key.to_hex(256)
|
||||
<< " by " << mc_incr << " (old value is " << mc_cnt.to_str() << ")");
|
||||
}
|
||||
if (shard_incr && !shard_cnt.increase_by(shard_incr, now_)) {
|
||||
return fatal_error(PSTRING() << "cannot increase shardchain block counter in CreatorStats for " << key.to_hex(256)
|
||||
<< " by " << shard_incr << " (old value is " << shard_cnt.to_str() << ")");
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
if (!block::store_CreatorStats(cb, mc_cnt, shard_cnt)) {
|
||||
return fatal_error("cannot serialize new CreatorStats for "s + key.to_hex(256));
|
||||
}
|
||||
if (!block_create_stats_->set_builder(key, 256, cb)) {
|
||||
return fatal_error("cannot store new CreatorStats for "s + key.to_hex(256) + " into dictionary");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Collator::creator_count_outdated(td::ConstBitPtr key, vm::CellSlice& cs) {
|
||||
block::DiscountedCounter mc_cnt, shard_cnt;
|
||||
if (!(block::fetch_CreatorStats(cs, mc_cnt, shard_cnt) && cs.empty_ext())) {
|
||||
return fatal_error("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state");
|
||||
}
|
||||
if (!(mc_cnt.increase_by(0, now_) && shard_cnt.increase_by(0, now_))) {
|
||||
return fatal_error("cannot amortize counters in CreatorStats for "s + key.to_hex(256));
|
||||
}
|
||||
if (!(mc_cnt.cnt65536 | shard_cnt.cnt65536)) {
|
||||
LOG(DEBUG) << "removing stale CreatorStats for " << key.to_hex(256);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Collator::update_block_creator_stats() {
|
||||
if (!create_stats_enabled_) {
|
||||
return true;
|
||||
}
|
||||
LOG(INFO) << "updating block creator statistics";
|
||||
CHECK(block_create_stats_);
|
||||
for (const auto& p : block_create_count_) {
|
||||
if (!update_block_creator_count(p.first.bits(), p.second, 0)) {
|
||||
return fatal_error("cannot update CreatorStats for "s + p.first.to_hex());
|
||||
}
|
||||
}
|
||||
if (/*!created_by_.is_zero() &&*/ !update_block_creator_count(created_by_.as_bits256().bits(), 0, 1)) {
|
||||
return fatal_error("cannot update CreatorStats for "s + created_by_.as_bits256().to_hex());
|
||||
}
|
||||
if (!update_block_creator_count(td::Bits256::zero().bits(), block_create_total_, 1)) {
|
||||
return fatal_error("cannot update CreatorStats with zero index (representing the sum of other CreatorStats)");
|
||||
}
|
||||
int cnt = block_create_stats_->filter([this](vm::CellSlice& cs, td::ConstBitPtr key, int key_len) {
|
||||
CHECK(key_len == 256);
|
||||
return creator_count_outdated(key, cs);
|
||||
});
|
||||
LOG(DEBUG) << "removed " << cnt << " stale CreatorStats entries";
|
||||
return cnt >= 0;
|
||||
}
|
||||
|
||||
td::Result<Ref<vm::Cell>> Collator::get_config_data_from_smc(const ton::StdSmcAddress& cfg_addr) {
|
||||
return block::get_config_data_from_smc(account_dict->lookup_ref(cfg_addr));
|
||||
}
|
||||
|
@ -3322,7 +3438,7 @@ bool Collator::create_shard_state() {
|
|||
&& cb2.store_bool_bool(!is_masterchain()) &&
|
||||
(is_masterchain() || store_master_ref(cb2)) // master_ref:(Maybe BlkMasterInfo)
|
||||
&& cb.store_ref_bool(cb2.finalize()) // ]
|
||||
&& cb.store_maybe_ref(mc_state_extra) // custom:(Maybe ^McStateExtra)
|
||||
&& cb.store_maybe_ref(mc_state_extra_) // custom:(Maybe ^McStateExtra)
|
||||
&& cb.finalize_to(state_root))) {
|
||||
return fatal_error("cannot create new ShardState");
|
||||
}
|
||||
|
@ -3500,10 +3616,10 @@ bool Collator::create_block_extra(Ref<vm::Cell>& block_extra) {
|
|||
return cb.store_long_bool(0x4a33f6fdU, 32) // block_extra
|
||||
&& in_msg_dict->append_dict_to_bool(cb2) && cb.store_ref_bool(cb2.finalize()) // in_msg_descr:^InMsgDescr
|
||||
&& out_msg_dict->append_dict_to_bool(cb2) && cb.store_ref_bool(cb2.finalize()) // out_msg_descr:^OutMsgDescr
|
||||
&& cb.store_ref_bool(shard_account_blocks_) // account_blocks:^ShardAccountBlocks
|
||||
&& cb.store_bits_bool(rand_seed_) // rand_seed:bits256
|
||||
&& cb.store_bits_bool(created_by) // created_by:bits256
|
||||
&& cb.store_bool_bool(mc) // custom:(Maybe
|
||||
&& cb.store_ref_bool(shard_account_blocks_) // account_blocks:^ShardAccountBlocks
|
||||
&& cb.store_bits_bool(rand_seed_) // rand_seed:bits256
|
||||
&& cb.store_bits_bool(created_by_.as_bits256()) // created_by:bits256
|
||||
&& cb.store_bool_bool(mc) // custom:(Maybe
|
||||
&& (!mc || (create_mc_block_extra(mc_block_extra) && cb.store_ref_bool(mc_block_extra))) // .. ^McBlockExtra)
|
||||
&& cb.finalize_to(block_extra); // = BlockExtra;
|
||||
}
|
||||
|
@ -3643,14 +3759,14 @@ bool Collator::create_block_candidate() {
|
|||
<< block_limit_status_->transactions;
|
||||
// 3. create a BlockCandidate
|
||||
block_candidate = std::make_unique<BlockCandidate>(
|
||||
Ed25519_PublicKey{created_by},
|
||||
created_by_,
|
||||
ton::BlockIdExt{ton::BlockId{shard, new_block_seqno}, new_block->get_hash().bits(),
|
||||
block::compute_file_hash(blk_slice.as_slice())},
|
||||
block::compute_file_hash(cdata_slice.as_slice()), blk_slice.clone(), cdata_slice.clone());
|
||||
// 4. save block candidate
|
||||
LOG(INFO) << "saving new BlockCandidate";
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::set_block_candidate, block_candidate->id,
|
||||
block_candidate->clone(), [self = get_self()](td::Result<td::Unit> saved)->void {
|
||||
block_candidate->clone(), [self = get_self()](td::Result<td::Unit> saved) -> void {
|
||||
LOG(DEBUG) << "got answer to set_block_candidate";
|
||||
td::actor::send_closure_later(std::move(self), &Collator::return_block_candidate,
|
||||
std::move(saved));
|
||||
|
|
|
@ -180,7 +180,7 @@ void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_maste
|
|||
}
|
||||
|
||||
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
|
||||
std::vector<BlockIdExt> prev, PublicKeyHash collator_id, td::Ref<ValidatorSet> validator_set,
|
||||
std::vector<BlockIdExt> prev, Ed25519_PublicKey collator_id, td::Ref<ValidatorSet> validator_set,
|
||||
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
BlockSeqno seqno = 0;
|
||||
|
@ -190,8 +190,8 @@ void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& m
|
|||
}
|
||||
}
|
||||
td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, min_ts,
|
||||
min_masterchain_block_id, std::move(prev), std::move(validator_set),
|
||||
collator_id.bits256_value(), std::move(manager), timeout, std::move(promise))
|
||||
min_masterchain_block_id, std::move(prev), std::move(validator_set), collator_id,
|
||||
std::move(manager), timeout, std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -41,14 +41,14 @@ ShardTopBlockDescrQ* ShardTopBlockDescrQ::make_copy() const {
|
|||
td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cell> proof_root, bool is_head) {
|
||||
auto virt_root = vm::MerkleProof::virtualize(proof_root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
return td::Status::Error(-666, std::string{} + "link for block " + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() +
|
||||
return td::Status::Error(-666, "link for block "s + cur_id.to_str() + " inside ShardTopBlockDescr of " +
|
||||
block_id_.to_str() +
|
||||
" does not contain a valid Merkle proof for the block header");
|
||||
}
|
||||
RootHash virt_hash{virt_root->get_hash().bits()};
|
||||
if (virt_hash != cur_id.root_hash) {
|
||||
return td::Status::Error(-666, std::string{} + "link for block " + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() +
|
||||
return td::Status::Error(-666, "link for block "s + cur_id.to_str() + " inside ShardTopBlockDescr of " +
|
||||
block_id_.to_str() +
|
||||
" contains a Merkle proof with incorrect root hash: expected " +
|
||||
cur_id.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
|
@ -56,18 +56,31 @@ td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cel
|
|||
BlockIdExt mc_blkid;
|
||||
auto res = block::unpack_block_prev_blk_try(virt_root, cur_id, link_prev_, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
return td::Status::Error(-666, std::string{"error in link for block "} + cur_id.to_str() +
|
||||
" inside ShardTopBlockDescr of " + block_id_.to_str() + ": " +
|
||||
res.move_as_error().to_string());
|
||||
return td::Status::Error(-666, "error in link for block "s + cur_id.to_str() + " inside ShardTopBlockDescr of " +
|
||||
block_id_.to_str() + ": " + res.move_as_error().to_string());
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
block::gen::BlockExtra::Record extra;
|
||||
block::gen::ValueFlow::Record flow;
|
||||
block::CurrencyCollection fees_collected, funds_created;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version &&
|
||||
block::gen::t_ValueFlow.force_validate_ref(blk.value_flow) && tlb::unpack_cell(blk.value_flow, flow) &&
|
||||
fees_collected.unpack(flow.fees_collected) && funds_created.unpack(flow.r2.created))) {
|
||||
return td::Status::Error(-666, std::string{"cannot unpack block header in link for block "} + cur_id.to_str());
|
||||
/*tlb::unpack_cell(blk.extra, extra) &&*/ fees_collected.unpack(flow.fees_collected) &&
|
||||
funds_created.unpack(flow.r2.created))) {
|
||||
return td::Status::Error(-666, "cannot unpack block header in link for block "s + cur_id.to_str());
|
||||
}
|
||||
// remove this "try ... catch ..." later and uncomment tlb::unpack_cell(blk.extra, extra) in the previous condition
|
||||
try {
|
||||
if (!tlb::unpack_cell(blk.extra, extra)) {
|
||||
return td::Status::Error(-666,
|
||||
"cannot unpack block extra header (BlockExtra) in link for block "s + cur_id.to_str());
|
||||
}
|
||||
} catch (vm::VmVirtError& err) {
|
||||
// backward compatibility with older Proofs / ProofLinks
|
||||
LOG(WARNING) << "virtualization error while parsing BlockExtra in proof link of " << cur_id.to_str()
|
||||
<< ", setting creator_id to zero: " << err.get_msg();
|
||||
extra.created_by.set_zero();
|
||||
}
|
||||
CHECK(after_split == info.after_split);
|
||||
if (info.gen_catchain_seqno != catchain_seqno_) {
|
||||
|
@ -113,6 +126,7 @@ td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Ref<vm::Cel
|
|||
chain_mc_blk_ids_.push_back(mc_blkid);
|
||||
chain_blk_ids_.push_back(cur_id);
|
||||
chain_fees_.emplace_back(std::move(fees_collected), std::move(funds_created));
|
||||
creators_.push_back(extra.created_by);
|
||||
if (!is_head) {
|
||||
if (info.after_split || info.after_merge) {
|
||||
return td::Status::Error(
|
||||
|
@ -491,6 +505,17 @@ Ref<block::McShardHash> ShardTopBlockDescrQ::get_prev_descr(int pos, int sum_cnt
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<td::Bits256> ShardTopBlockDescrQ::get_creator_list(int count) const {
|
||||
if (!is_valid() || count < 0 || (unsigned)count > size()) {
|
||||
return {};
|
||||
}
|
||||
std::vector<td::Bits256> res;
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
res.push_back(creators_.at(i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ValidateShardTopBlockDescr::finish_query() {
|
||||
if (promise_) {
|
||||
promise_.set_value(std::move(descr_));
|
||||
|
|
|
@ -85,6 +85,7 @@ class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase {
|
|||
Ref<block::McShardHash> get_top_descr(int sum_cnt = 0) const {
|
||||
return get_prev_descr(0, sum_cnt);
|
||||
}
|
||||
std::vector<td::Bits256> get_creator_list(int count) const;
|
||||
Ref<vm::Cell> get_root() const {
|
||||
return root_;
|
||||
}
|
||||
|
@ -131,6 +132,7 @@ class ShardTopBlockDescrQ final : public ShardTopBlockDescrQBase {
|
|||
std::vector<BlockIdExt> chain_mc_blk_ids_;
|
||||
std::vector<BlockIdExt> link_prev_;
|
||||
std::vector<std::pair<block::CurrencyCollection, block::CurrencyCollection>> chain_fees_;
|
||||
std::vector<td::Bits256> creators_;
|
||||
UnixTime first_gen_utime_;
|
||||
|
||||
ShardTopBlockDescrQ(const ShardTopBlockDescrQ& other) = default;
|
||||
|
|
|
@ -152,6 +152,12 @@ void ValidateQuery::start_up() {
|
|||
alarm_timestamp() = timeout;
|
||||
rand_seed_.set_zero();
|
||||
|
||||
created_by_ = block_candidate.pubkey;
|
||||
if (created_by_.is_zero()) {
|
||||
// !!FIXME!! remove this debug later
|
||||
td::as<td::uint32>(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
|
||||
}
|
||||
|
||||
CHECK(id_ == block_candidate.id);
|
||||
if (ShardIdFull(id_) != shard_) {
|
||||
soft_reject_query(PSTRING() << "block candidate belongs to shard " << ShardIdFull(id_).to_str()
|
||||
|
@ -431,6 +437,10 @@ bool ValidateQuery::init_parse() {
|
|||
return reject_query("after_merge value mismatch in block header");
|
||||
}
|
||||
rand_seed_ = extra.rand_seed;
|
||||
if (created_by_ != extra.created_by) {
|
||||
return reject_query("block candidate "s + id_.to_str() + " has creator " + created_by_.to_hex() +
|
||||
" but the block header contains different value " + extra.created_by.to_hex());
|
||||
}
|
||||
if (is_masterchain()) {
|
||||
if (!extra.custom->size_refs()) {
|
||||
return reject_query("masterchain block candidate without McBlockExtra");
|
||||
|
@ -658,6 +668,7 @@ bool ValidateQuery::try_unpack_mc_state() {
|
|||
mc_state_root_,
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needLibraries | block::ConfigInfo::needValidatorSet |
|
||||
block::ConfigInfo::needWorkchainInfo | block::ConfigInfo::needStateExtraRoot |
|
||||
block::ConfigInfo::needCapabilities |
|
||||
(is_masterchain() ? block::ConfigInfo::needAccountsRoot | block::ConfigInfo::needSpecialSmc : 0));
|
||||
if (res.is_error()) {
|
||||
return fatal_error(-666, "cannot extract configuration from reference masterchain state "s + mc_blkid_.to_str() +
|
||||
|
@ -666,6 +677,8 @@ bool ValidateQuery::try_unpack_mc_state() {
|
|||
config_ = res.move_as_ok();
|
||||
CHECK(config_);
|
||||
config_->set_block_id_ext(mc_blkid_);
|
||||
ihr_enabled_ = config_->ihr_enabled();
|
||||
create_stats_enabled_ = config_->create_stats_enabled();
|
||||
old_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
if (!is_masterchain()) {
|
||||
new_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
|
||||
|
@ -677,7 +690,8 @@ bool ValidateQuery::try_unpack_mc_state() {
|
|||
if (global_id_ != config_->get_global_blockchain_id()) {
|
||||
return reject_query("blockchain global id mismatch");
|
||||
}
|
||||
if (config_->get_last_key_block(prev_key_block_, prev_key_block_lt_)) {
|
||||
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
|
||||
if (prev_key_block_exists_) {
|
||||
prev_key_block_seqno_ = prev_key_block_.seqno();
|
||||
} else {
|
||||
prev_key_block_seqno_ = 0;
|
||||
|
@ -1044,7 +1058,7 @@ bool ValidateQuery::compute_next_state() {
|
|||
state_root_, block::ConfigInfo::needShardHashes | block::ConfigInfo::needLibraries |
|
||||
block::ConfigInfo::needValidatorSet | block::ConfigInfo::needWorkchainInfo |
|
||||
block::ConfigInfo::needStateExtraRoot | block::ConfigInfo::needAccountsRoot |
|
||||
block::ConfigInfo::needSpecialSmc);
|
||||
block::ConfigInfo::needSpecialSmc | block::ConfigInfo::needCapabilities);
|
||||
if (r_config_info.is_error()) {
|
||||
return reject_query("cannot extract configuration from new masterchain state "s + mc_blkid_.to_str() + " : " +
|
||||
r_config_info.error().to_string());
|
||||
|
@ -1508,6 +1522,8 @@ bool ValidateQuery::check_one_shard(const block::McShardHash& info, const block:
|
|||
descr->funds_created_.to_str());
|
||||
}
|
||||
}
|
||||
// register shard block creators
|
||||
register_shard_block_creators(sh_bd->get_creator_list(chain_len));
|
||||
// ...
|
||||
} catch (vm::VmError& err) {
|
||||
return reject_query("incorrect ShardTopBlockDescr for "s + shard.to_str() +
|
||||
|
@ -1677,6 +1693,21 @@ bool ValidateQuery::check_shard_layout() {
|
|||
return check_mc_validator_info(is_key_block_ || (now_ / ccvc.mc_cc_lifetime > prev_now_ / ccvc.mc_cc_lifetime));
|
||||
}
|
||||
|
||||
// similar to Collator::register_shard_block_creators
|
||||
bool ValidateQuery::register_shard_block_creators(std::vector<td::Bits256> creator_list) {
|
||||
for (const auto& x : creator_list) {
|
||||
LOG(DEBUG) << "registering block creator " << x.to_hex();
|
||||
if (!x.is_zero()) {
|
||||
auto res = block_create_count_.emplace(x, 1);
|
||||
if (!res.second) {
|
||||
(res.first->second)++;
|
||||
}
|
||||
block_create_total_++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateQuery::check_cur_validator_set() {
|
||||
CatchainSeqno cc_seqno = 0;
|
||||
auto nodes = config_->compute_validator_set_cc(shard_, now_, &cc_seqno);
|
||||
|
@ -4949,9 +4980,15 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
return reject_query("invalid configuration update");
|
||||
}
|
||||
// ...
|
||||
// flags:(## 16) { flags = 0 }
|
||||
if (new_extra.r1.flags != 0) {
|
||||
return reject_query("new McStateExtra has non-zero (unsupported) extension flags; validator too old?");
|
||||
// flags:(## 16) { flags <= 1 }
|
||||
if (new_extra.r1.flags & ~1) {
|
||||
return reject_query(PSTRING() << "new McStateExtra has non-zero (unsupported) extension flags "
|
||||
<< new_extra.r1.flags << "; validator too old?");
|
||||
}
|
||||
if ((bool)(new_extra.r1.flags & 1) != create_stats_enabled_) {
|
||||
return reject_query(PSTRING() << "new McStateExtra has extension flags " << new_extra.r1.flags
|
||||
<< " but active configuration defines create_stats_enabled="
|
||||
<< create_stats_enabled_);
|
||||
}
|
||||
// validator_info:ValidatorInfo
|
||||
// (already checked in check_mc_validator_info())
|
||||
|
@ -5043,11 +5080,21 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
return reject_query("new masterchain state declares previous key block to be "s + blkid.to_str() +
|
||||
" but the value computed from previous masterchain state is " + prev_key_block_.to_str());
|
||||
}
|
||||
} else if (prev_key_block_seqno_ > 0) {
|
||||
} else if (prev_key_block_exists_) {
|
||||
return reject_query(PSTRING() << "new masterchain state declares no previous key block, but the block header "
|
||||
"announces previous key block seqno "
|
||||
<< prev_key_block_seqno_);
|
||||
}
|
||||
// block_create_stats:(flags . 0)?BlockCreateStats
|
||||
if (new_extra.r1.flags & 1) {
|
||||
block::gen::BlockCreateStats::Record rec;
|
||||
if (!tlb::csr_unpack(new_extra.r1.block_create_stats, rec)) {
|
||||
return reject_query("cannot unpack BlockCreateStats in the new masterchain state");
|
||||
}
|
||||
if (!check_block_create_stats()) {
|
||||
return reject_query("invalid BlockCreateStats update in the new masterchain state");
|
||||
}
|
||||
}
|
||||
// global_balance:CurrencyCollection
|
||||
block::CurrencyCollection global_balance, old_global_balance;
|
||||
if (!global_balance.validate_unpack(new_extra.global_balance)) {
|
||||
|
@ -5069,6 +5116,136 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
return true;
|
||||
}
|
||||
|
||||
td::Status ValidateQuery::check_counter_update(const block::DiscountedCounter& oc, const block::DiscountedCounter& nc,
|
||||
unsigned expected_incr) {
|
||||
block::DiscountedCounter cc{oc};
|
||||
if (nc.is_zero()) {
|
||||
if (expected_incr) {
|
||||
return td::Status::Error(PSTRING() << "new counter total is zero, but the total should have been increased by "
|
||||
<< expected_incr);
|
||||
}
|
||||
if (oc.is_zero()) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
cc.increase_by(0, now_);
|
||||
if (!cc.almost_zero()) {
|
||||
return td::Status::Error(
|
||||
"counter has been reset to zero, but it still has non-zero components after relaxation: "s + cc.to_str() +
|
||||
"; original value before relaxation was " + oc.to_str());
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
if (!expected_incr) {
|
||||
if (oc == nc) {
|
||||
return td::Status::OK();
|
||||
} else {
|
||||
return td::Status::Error("unnecessary relaxation of counter from "s + oc.to_str() + " to " + nc.to_str() +
|
||||
" without an increment");
|
||||
}
|
||||
}
|
||||
if (nc.total < oc.total) {
|
||||
return td::Status::Error(PSTRING() << "total counter goes back from " << oc.total << " to " << nc.total
|
||||
<< " (increment by " << expected_incr << " expected instead)");
|
||||
}
|
||||
if (nc.total != oc.total + expected_incr) {
|
||||
return td::Status::Error(PSTRING() << "total counter has been incremented by " << nc.total - oc.total << ", from "
|
||||
<< oc.total << " to " << nc.total << " (increment by " << expected_incr
|
||||
<< " expected instead)");
|
||||
}
|
||||
if (!cc.increase_by(expected_incr, now_)) {
|
||||
return td::Status::Error(PSTRING() << "old counter value " << oc.to_str() << " cannot be increased by "
|
||||
<< expected_incr);
|
||||
}
|
||||
if (!cc.almost_equals(nc)) {
|
||||
return td::Status::Error(PSTRING() << "counter " << oc.to_str() << " has been increased by " << expected_incr
|
||||
<< " with an incorrect resulting value " << nc.to_str()
|
||||
<< "; correct result should be " << cc.to_str()
|
||||
<< " (up to +/-1 in the last two components)");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
bool ValidateQuery::check_one_block_creator_update(td::ConstBitPtr key, Ref<vm::CellSlice> old_val,
|
||||
Ref<vm::CellSlice> new_val) {
|
||||
LOG(DEBUG) << "checking update of CreatorStats for "s + key.to_hex(256);
|
||||
block::DiscountedCounter mc0, shard0, mc1, shard1;
|
||||
if (!block::unpack_CreatorStats(std::move(old_val), mc0, shard0)) {
|
||||
return reject_query("cannot unpack CreatorStats for "s + key.to_hex(256) + " from previous masterchain state");
|
||||
}
|
||||
bool nv_exists = new_val.not_null();
|
||||
if (!block::unpack_CreatorStats(std::move(new_val), mc1, shard1)) {
|
||||
return reject_query("cannot unpack CreatorStats for "s + key.to_hex(256) + " from new masterchain state");
|
||||
}
|
||||
unsigned mc_incr = (created_by_ == key);
|
||||
unsigned shard_incr = 0;
|
||||
if (key.is_zero(256)) {
|
||||
mc_incr = 1;
|
||||
shard_incr = block_create_total_;
|
||||
} else {
|
||||
auto it = block_create_count_.find(td::Bits256{key});
|
||||
shard_incr = (it == block_create_count_.end() ? 0 : it->second);
|
||||
}
|
||||
auto err = check_counter_update(mc0, mc1, mc_incr);
|
||||
if (err.is_error()) {
|
||||
return reject_query("invalid update of created masterchain blocks counter in CreatorStats for "s + key.to_hex(256) +
|
||||
" : " + err.to_string());
|
||||
}
|
||||
err = check_counter_update(shard0, shard1, shard_incr);
|
||||
if (err.is_error()) {
|
||||
return reject_query("invalid update of created shardchain blocks counter in CreatorStats for "s + key.to_hex(256) +
|
||||
" : " + err.to_string());
|
||||
}
|
||||
if (mc1.is_zero() && shard1.is_zero() && nv_exists) {
|
||||
return reject_query("new CreatorStats for "s + key.to_hex(256) +
|
||||
" contains two zero counters (it should have been completely deleted instead)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// similar to Collator::update_block_creator_stats()
|
||||
bool ValidateQuery::check_block_create_stats() {
|
||||
LOG(INFO) << "checking all CreatorStats updates between the old and the new state";
|
||||
try {
|
||||
CHECK(ps_.block_create_stats_ && ns_.block_create_stats_);
|
||||
if (!ps_.block_create_stats_->scan_diff(
|
||||
*ns_.block_create_stats_,
|
||||
[this](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> old_val, Ref<vm::CellSlice> new_val) {
|
||||
CHECK(key_len == 256);
|
||||
return check_one_block_creator_update(key, std::move(old_val), std::move(new_val));
|
||||
},
|
||||
3 /* check augmentation of changed nodes */)) {
|
||||
return reject_query("invalid BlockCreateStats dictionary in the new state");
|
||||
}
|
||||
for (const auto& p : block_create_count_) {
|
||||
auto old_val = ps_.block_create_stats_->lookup(p.first);
|
||||
auto new_val = ns_.block_create_stats_->lookup(p.first);
|
||||
if (old_val.is_null() != new_val.is_null()) {
|
||||
continue;
|
||||
}
|
||||
if (old_val.not_null() && !new_val->contents_equal(*old_val)) {
|
||||
continue;
|
||||
}
|
||||
if (!check_one_block_creator_update(p.first.bits(), std::move(old_val), std::move(new_val))) {
|
||||
return reject_query("invalid update of BlockCreator entry for "s + p.first.to_hex());
|
||||
}
|
||||
}
|
||||
auto key = td::Bits256::zero();
|
||||
auto old_val = ps_.block_create_stats_->lookup(key);
|
||||
auto new_val = ns_.block_create_stats_->lookup(key);
|
||||
if (new_val.is_null()) {
|
||||
return reject_query(
|
||||
"new masterchain state does not contain a BlockCreator entry with zero key with total statistics");
|
||||
}
|
||||
if (!check_one_block_creator_update(key.bits(), std::move(old_val), std::move(new_val))) {
|
||||
return reject_query("invalid update of BlockCreator entry for "s + key.to_hex());
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return reject_query("invalid BlockCreateStats dictionary difference between the old and the new state: "s +
|
||||
err.get_msg());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateQuery::check_one_shard_fee(ShardIdFull shard, const block::CurrencyCollection& fees,
|
||||
const block::CurrencyCollection& created) {
|
||||
auto descr = new_shard_conf_->get_shard_hash(shard);
|
||||
|
|
|
@ -135,10 +135,12 @@ class ValidateQuery : public td::actor::Actor {
|
|||
bool is_key_block_{false};
|
||||
bool update_shard_cc_{false};
|
||||
bool is_fake_{false};
|
||||
bool prev_key_block_exists_{false};
|
||||
BlockSeqno prev_key_seqno_{~0u};
|
||||
int stage_{0};
|
||||
td::BitArray<64> shard_pfx_;
|
||||
int shard_pfx_len_;
|
||||
td::Bits256 created_by_;
|
||||
|
||||
Ref<vm::Cell> prev_state_root_;
|
||||
Ref<vm::Cell> state_root_;
|
||||
|
@ -174,6 +176,8 @@ class ValidateQuery : public td::actor::Actor {
|
|||
ton::LogicalTime max_shard_lt_{0};
|
||||
|
||||
int global_id_{0};
|
||||
bool ihr_enabled_{false};
|
||||
bool create_stats_enabled_{false};
|
||||
ton::BlockSeqno prev_key_block_seqno_;
|
||||
ton::BlockIdExt prev_key_block_;
|
||||
ton::LogicalTime prev_key_block_lt_;
|
||||
|
@ -197,6 +201,9 @@ class ValidateQuery : public td::actor::Actor {
|
|||
std::unique_ptr<vm::AugmentedDictionary> sibling_out_msg_queue_;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> sibling_processed_upto_;
|
||||
|
||||
std::map<td::Bits256, int> block_create_count_;
|
||||
unsigned block_create_total_{0};
|
||||
|
||||
std::unique_ptr<vm::AugmentedDictionary> in_msg_dict_, out_msg_dict_, account_blocks_dict_;
|
||||
block::ValueFlow value_flow_;
|
||||
block::CurrencyCollection import_created_, transaction_fees_;
|
||||
|
@ -285,6 +292,7 @@ class ValidateQuery : public td::actor::Actor {
|
|||
bool check_one_shard(const block::McShardHash& info, const block::McShardHash* sibling,
|
||||
const block::WorkchainInfo* wc_info, const block::CatchainValidatorsConfig& ccvc);
|
||||
bool check_shard_layout();
|
||||
bool register_shard_block_creators(std::vector<td::Bits256> creator_list);
|
||||
bool check_cur_validator_set();
|
||||
bool check_mc_validator_info(bool update_mc_cc);
|
||||
bool check_utime_lt();
|
||||
|
@ -342,6 +350,10 @@ class ValidateQuery : public td::actor::Actor {
|
|||
bool check_one_prev_dict_update(ton::BlockSeqno seqno, Ref<vm::CellSlice> old_val_extra,
|
||||
Ref<vm::CellSlice> new_val_extra);
|
||||
bool check_mc_state_extra();
|
||||
td::Status check_counter_update(const block::DiscountedCounter& oc, const block::DiscountedCounter& nc,
|
||||
unsigned expected_incr);
|
||||
bool check_one_block_creator_update(td::ConstBitPtr key, Ref<vm::CellSlice> old_val, Ref<vm::CellSlice> new_val);
|
||||
bool check_block_create_stats();
|
||||
bool check_one_shard_fee(ShardIdFull shard, const block::CurrencyCollection& fees,
|
||||
const block::CurrencyCollection& create);
|
||||
bool check_mc_block_extra();
|
||||
|
|
|
@ -55,6 +55,8 @@ class Db : public td::actor::Actor {
|
|||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_persistent_state_file_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::int64 offset,
|
||||
td::int64 max_length, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void check_persistent_state_file_exists(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<bool> promise) = 0;
|
||||
virtual void store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) = 0;
|
||||
|
|
|
@ -123,7 +123,12 @@ void ValidatorManagerImpl::sync_complete(td::Promise<td::Unit> promise) {
|
|||
});
|
||||
|
||||
LOG(ERROR) << "running collate query";
|
||||
run_collate_query(shard_id, 0, last_masterchain_block_id_, prev, local_id_, val_set, actor_id(this),
|
||||
if (local_id_.is_zero()) {
|
||||
//td::as<td::uint32>(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
|
||||
}
|
||||
Ed25519_PublicKey created_by{td::Bits256::zero()};
|
||||
td::as<td::uint32>(created_by.as_bits256().data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
|
||||
run_collate_query(shard_id, 0, last_masterchain_block_id_, prev, created_by, val_set, actor_id(this),
|
||||
td::Timestamp::in(10.0), std::move(P));
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
td::Promise<bool> promise) override;
|
||||
void get_persistent_state(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void get_persistent_state_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::int64 offset,
|
||||
td::int64 max_length, td::Promise<td::BufferSlice> promise) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void get_block_proof(BlockHandle handle, td::Promise<td::BufferSlice> promise) override;
|
||||
void get_block_proof_link(BlockHandle block_id, td::Promise<td::BufferSlice> promise) override {
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -262,6 +262,13 @@ void ValidatorManagerImpl::get_persistent_state(BlockIdExt block_id, BlockIdExt
|
|||
td::actor::send_closure(db_, &Db::get_persistent_state_file, block_id, masterchain_block_id, std::move(promise));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::get_persistent_state_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::int64 offset, td::int64 max_length,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(db_, &Db::get_persistent_state_file_slice, block_id, masterchain_block_id, offset, max_length,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::get_block_proof(BlockHandle handle, td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Ref<Proof>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
|
@ -433,12 +440,16 @@ void ValidatorManagerImpl::run_ext_query(td::BufferSlice data, td::Promise<td::B
|
|||
promise.set_error(td::Status::Error(ErrorCode::notready, "node not synced"));
|
||||
return;
|
||||
}
|
||||
auto F = fetch_tl_object<lite_api::liteServer_query>(std::move(data), true);
|
||||
if (F.is_error()) {
|
||||
promise.set_error(F.move_as_error());
|
||||
return;
|
||||
auto F = fetch_tl_object<lite_api::liteServer_query>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
data = std::move(F.move_as_ok()->data_);
|
||||
} else {
|
||||
auto G = fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true);
|
||||
if (G.is_error()) {
|
||||
promise.set_error(G.move_as_error());
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto obj = F.move_as_ok();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
td::BufferSlice data;
|
||||
|
@ -451,7 +462,7 @@ void ValidatorManagerImpl::run_ext_query(td::BufferSlice data, td::Promise<td::B
|
|||
promise.set_value(std::move(data));
|
||||
});
|
||||
|
||||
run_liteserver_query(std::move(obj->data_), actor_id(this), std::move(P));
|
||||
run_liteserver_query(std::move(data), actor_id(this), std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
|
||||
|
|
|
@ -301,6 +301,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
td::Promise<bool> promise) override;
|
||||
void get_persistent_state(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void get_persistent_state_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::int64 offset,
|
||||
td::int64 max_length, td::Promise<td::BufferSlice> promise) override;
|
||||
void get_block_proof(BlockHandle handle, td::Promise<td::BufferSlice> promise) override;
|
||||
void get_block_proof_link(BlockHandle block_id, td::Promise<td::BufferSlice> promise) override;
|
||||
//void get_block_description(BlockIdExt block_id, td::Promise<BlockDescription> promise) override;
|
||||
|
|
|
@ -148,6 +148,10 @@ void DownloadState::got_block_state_description(td::BufferSlice data) {
|
|||
abort_query(td::Status::Error(ErrorCode::notready, "state not found"));
|
||||
},
|
||||
[&, self = this](ton_api::tonNode_preparedState &f) {
|
||||
if (masterchain_block_id_.is_valid()) {
|
||||
got_block_state_part(td::BufferSlice{}, 0);
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(self)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
|
||||
|
@ -156,19 +160,48 @@ void DownloadState::got_block_state_description(td::BufferSlice data) {
|
|||
}
|
||||
});
|
||||
|
||||
td::BufferSlice query;
|
||||
if (masterchain_block_id_.is_valid()) {
|
||||
query = create_serialize_tl_object<ton_api::tonNode_downloadPersistentState>(
|
||||
create_tl_block_id(block_id_), create_tl_block_id(masterchain_block_id_));
|
||||
} else {
|
||||
query = create_serialize_tl_object<ton_api::tonNode_downloadZeroState>(create_tl_block_id(block_id_));
|
||||
}
|
||||
td::BufferSlice query =
|
||||
create_serialize_tl_object<ton_api::tonNode_downloadZeroState>(create_tl_block_id(block_id_));
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_,
|
||||
overlay_id_, "download state", std::move(P), timeout_, std::move(query),
|
||||
FullNode::max_state_size(), rldp_);
|
||||
}));
|
||||
}
|
||||
|
||||
void DownloadState::got_block_state_part(td::BufferSlice data, td::uint32 requested_size) {
|
||||
bool last_part = data.size() < requested_size;
|
||||
sum_ += data.size();
|
||||
parts_.push_back(std::move(data));
|
||||
|
||||
if (last_part) {
|
||||
td::BufferSlice res{sum_};
|
||||
auto S = res.as_slice();
|
||||
for (auto &p : parts_) {
|
||||
S.copy_from(p.as_slice());
|
||||
S.remove_prefix(p.size());
|
||||
}
|
||||
parts_.clear();
|
||||
CHECK(!S.size());
|
||||
got_block_state(std::move(res));
|
||||
return;
|
||||
}
|
||||
|
||||
td::uint32 part_size = 4 << 20;
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), part_size](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &DownloadState::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &DownloadState::got_block_state_part, R.move_as_ok(), part_size);
|
||||
}
|
||||
});
|
||||
|
||||
td::BufferSlice query = create_serialize_tl_object<ton_api::tonNode_downloadPersistentStateSlice>(
|
||||
create_tl_block_id(block_id_), create_tl_block_id(masterchain_block_id_), sum_, part_size);
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_,
|
||||
"download state", std::move(P), timeout_, std::move(query), FullNode::max_state_size(),
|
||||
rldp_);
|
||||
}
|
||||
|
||||
void DownloadState::got_block_state(td::BufferSlice data) {
|
||||
state_ = std::move(data);
|
||||
finish_query();
|
||||
|
|
|
@ -45,6 +45,7 @@ class DownloadState : public td::actor::Actor {
|
|||
void got_block_handle(BlockHandle handle);
|
||||
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
||||
void got_block_state_description(td::BufferSlice data_description);
|
||||
void got_block_state_part(td::BufferSlice data, td::uint32 requested_size);
|
||||
void got_block_state(td::BufferSlice data);
|
||||
|
||||
private:
|
||||
|
@ -66,6 +67,8 @@ class DownloadState : public td::actor::Actor {
|
|||
|
||||
BlockHandle handle_;
|
||||
td::BufferSlice state_;
|
||||
std::vector<td::BufferSlice> parts_;
|
||||
td::uint64 sum_ = 0;
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -270,7 +270,7 @@ void ValidateBroadcast::written_block_data() {
|
|||
if (!key_proof_link_.is_null()) {
|
||||
run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P), key_proof_link_);
|
||||
} else {
|
||||
CHECK(!zero_state_.not_null());
|
||||
CHECK(zero_state_.not_null());
|
||||
run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P), zero_state_);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -29,7 +29,8 @@ void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<B
|
|||
if (round_id > last_known_round_id_) {
|
||||
last_known_round_id_ = round_id;
|
||||
}
|
||||
run_collate_query(shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_, local_id_, validator_set_, manager_,
|
||||
run_collate_query(shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_,
|
||||
Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_, manager_,
|
||||
td::Timestamp::in(10.0), std::move(promise));
|
||||
}
|
||||
|
||||
|
@ -215,10 +216,16 @@ void ValidatorGroup::create_session() {
|
|||
init_ = true;
|
||||
std::vector<validatorsession::ValidatorSessionNode> vec;
|
||||
auto v = validator_set_->export_vector();
|
||||
bool found = false;
|
||||
for (auto &el : v) {
|
||||
validatorsession::ValidatorSessionNode n;
|
||||
n.pub_key = ValidatorFullId{el.key};
|
||||
n.weight = el.weight;
|
||||
if (n.pub_key.compute_short_id() == local_id_) {
|
||||
CHECK(!found);
|
||||
found = true;
|
||||
local_id_full_ = n.pub_key;
|
||||
}
|
||||
if (el.addr.is_zero()) {
|
||||
n.adnl_id = adnl::AdnlNodeIdShort{n.pub_key.compute_short_id()};
|
||||
} else {
|
||||
|
@ -226,6 +233,7 @@ void ValidatorGroup::create_session() {
|
|||
}
|
||||
vec.emplace_back(std::move(n));
|
||||
}
|
||||
CHECK(found);
|
||||
|
||||
session_ = validatorsession::ValidatorSession::create(session_id_, config_, local_id_, std::move(vec),
|
||||
make_validator_session_callback(), keyring_, adnl_, rldp_,
|
||||
|
|
|
@ -79,6 +79,7 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
|
||||
ShardIdFull shard_;
|
||||
PublicKeyHash local_id_;
|
||||
PublicKey local_id_full_;
|
||||
ValidatorSessionId session_id_;
|
||||
|
||||
std::vector<BlockIdExt> prev_block_ids_;
|
||||
|
|
|
@ -143,6 +143,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
td::Promise<bool> promise) = 0;
|
||||
virtual void get_persistent_state(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_persistent_state_slice(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::int64 offset,
|
||||
td::int64 max_length, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_block_proof(BlockHandle handle, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_block_proof_link(BlockHandle handle, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_block_handle(BlockIdExt block_id, bool force, td::Promise<BlockHandle> promise) = 0;
|
||||
|
|
Loading…
Reference in a new issue