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

updated smartcontracts

- updated smartcontracts
- updated fullnode database layout
- fixed memory leak in blockchain-explorer
- updated tonlib
This commit is contained in:
ton 2019-10-23 17:43:50 +04:00
parent 9c9248a9ae
commit c860ce3d1e
104 changed files with 7309 additions and 1335 deletions

View file

@ -10,6 +10,8 @@ add_subdirectory(impl)
set(VALIDATOR_DB_SOURCE
db/archiver.cpp
db/archiver.hpp
db/archive-db.cpp
db/archive-db.hpp
db/blockdb.cpp
db/blockdb.hpp
db/celldb.cpp
@ -25,6 +27,9 @@ set(VALIDATOR_DB_SOURCE
db/statedb.cpp
db/staticfilesdb.cpp
db/staticfilesdb.hpp
db/package.hpp
db/package.cpp
)
set(VALIDATOR_HEADERS

View file

@ -59,6 +59,7 @@ struct BlockHandleImpl : public BlockHandleInterface {
dbf_moved = 0x1000000,
dbf_deleted = 0x2000000,
dbf_deleted_boc = 0x4000000,
dbf_moved_new = 0x8000000,
dbf_processed = 0x10000000,
};
@ -95,6 +96,9 @@ struct BlockHandleImpl : public BlockHandleInterface {
bool moved_to_storage() const override {
return flags_.load(std::memory_order_consume) & Flags::dbf_moved;
}
bool moved_to_archive() const override {
return flags_.load(std::memory_order_consume) & Flags::dbf_moved_new;
}
bool deleted() const override {
return flags_.load(std::memory_order_consume) & Flags::dbf_deleted;
}
@ -393,6 +397,15 @@ struct BlockHandleImpl : public BlockHandleInterface {
flags_ |= Flags::dbf_moved;
unlock();
}
void set_moved_to_archive() override {
if (flags_.load(std::memory_order_consume) & Flags::dbf_moved_new) {
return;
}
lock();
flags_ |= Flags::dbf_moved_new;
flags_ &= ~Flags::dbf_moved;
unlock();
}
void set_deleted() override {
if (flags_.load(std::memory_order_consume) & Flags::dbf_deleted) {
return;

332
validator/db/archive-db.cpp Normal file
View file

@ -0,0 +1,332 @@
#include "archive-db.hpp"
#include "common/errorcode.h"
#include "common/int-to-string.hpp"
#include "files-async.hpp"
#include "td/db/RocksDb.h"
#include "validator/fabric.h"
namespace ton {
namespace validator {
void PackageWriter::append(std::string filename, td::BufferSlice data,
td::Promise<std::pair<td::uint64, td::uint64>> promise) {
auto offset = package_->append(std::move(filename), std::move(data));
auto size = package_->size();
promise.set_value(std::pair<td::uint64, td::uint64>{offset, size});
}
class PackageReader : public td::actor::Actor {
public:
PackageReader(std::shared_ptr<Package> package, td::uint64 offset,
td::Promise<std::pair<std::string, td::BufferSlice>> promise)
: package_(std::move(package)), offset_(offset), promise_(std::move(promise)) {
}
void start_up() {
promise_.set_result(package_->read(offset_));
}
private:
std::shared_ptr<Package> package_;
td::uint64 offset_;
td::Promise<std::pair<std::string, td::BufferSlice>> promise_;
};
void ArchiveFile::start_up() {
auto R = Package::open(path_, false, true);
if (R.is_error()) {
LOG(FATAL) << "failed to open/create archive '" << path_ << "': " << R.move_as_error();
return;
}
package_ = std::make_shared<Package>(R.move_as_ok());
index_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_ + ".index").move_as_ok());
std::string value;
auto R2 = index_->get("status", value);
R2.ensure();
if (R2.move_as_ok() == td::KeyValue::GetStatus::Ok) {
auto len = td::to_integer<td::uint64>(value);
package_->truncate(len);
} else {
package_->truncate(0);
}
writer_ = td::actor::create_actor<PackageWriter>("writer", package_);
}
void ArchiveFile::write(FileDb::RefId ref_id, td::BufferSlice data, td::Promise<td::Unit> promise) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), ref_id, promise = std::move(promise)](
td::Result<std::pair<td::uint64, td::uint64>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
return;
}
auto v = R.move_as_ok();
td::actor::send_closure(SelfId, &ArchiveFile::completed_write, std::move(ref_id), v.first, v.second,
std::move(promise));
});
FileHash hash;
ref_id.visit([&](const auto &obj) { hash = obj.hash(); });
td::actor::send_closure(writer_, &PackageWriter::append, hash.to_hex(), std::move(data), std::move(P));
}
void ArchiveFile::write_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
FileHash hash = fileref::BlockInfo{handle->id()}.hash();
index_->begin_transaction().ensure();
do {
auto version = handle->version();
index_->set(hash.to_hex(), handle->serialize().as_slice().str()).ensure();
handle->flushed_upto(version);
} while (handle->need_flush());
index_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void ArchiveFile::completed_write(FileDb::RefId ref_id, td::uint64 offset, td::uint64 new_size,
td::Promise<td::Unit> promise) {
FileHash hash;
ref_id.visit([&](const auto &obj) { hash = obj.hash(); });
index_->begin_transaction().ensure();
index_->set("status", td::to_string(new_size)).ensure();
index_->set(hash.to_hex(), td::to_string(offset)).ensure();
index_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void ArchiveFile::read(FileDb::RefId ref_id, td::Promise<td::BufferSlice> promise) {
FileHash hash;
ref_id.visit([&](const auto &obj) { hash = obj.hash(); });
std::string value;
auto R = index_->get(hash.to_hex(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db (archive)"));
return;
}
auto offset = td::to_integer<td::uint64>(value);
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise)](td::Result<std::pair<std::string, td::BufferSlice>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_value(std::move(R.move_as_ok().second));
}
});
td::actor::create_actor<PackageReader>("reader", package_, offset, std::move(P)).release();
}
void ArchiveFile::read_handle(BlockIdExt block_id, td::Promise<BlockHandle> promise) {
FileHash hash = fileref::BlockInfo{block_id}.hash();
std::string value;
auto R = index_->get(hash.to_hex(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in archive db"));
return;
}
promise.set_result(create_block_handle(td::BufferSlice{value}));
}
ArchiveManager::ArchiveManager(std::string db_root) : db_root_(db_root) {
}
void ArchiveManager::write(UnixTime ts, bool key_block, FileDb::RefId ref_id, td::BufferSlice data,
td::Promise<td::Unit> promise) {
auto f = get_file(ts, key_block);
td::actor::send_closure(f->file_actor_id(), &ArchiveFile::write, std::move(ref_id), std::move(data),
std::move(promise));
}
void ArchiveManager::write_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
auto f = get_file(handle->unix_time(), handle->is_key_block());
update_desc(*f, handle->id().shard_full(), handle->id().seqno(), handle->logical_time());
td::actor::send_closure(f->file_actor_id(), &ArchiveFile::write_handle, std::move(handle), std::move(promise));
}
void ArchiveManager::read(UnixTime ts, bool key_block, FileDb::RefId ref_id, td::Promise<td::BufferSlice> promise) {
auto f = get_file(ts, key_block);
td::actor::send_closure(f->file_actor_id(), &ArchiveFile::read, std::move(ref_id), std::move(promise));
}
void ArchiveManager::read_handle(BlockIdExt block_id, td::Promise<BlockHandle> promise) {
if (block_id.is_masterchain()) {
auto f = get_file_by_seqno(block_id.shard_full(), block_id.seqno(), true);
if (!f) {
read_handle_cont(block_id, std::move(promise));
return;
}
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), block_id, promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ArchiveManager::read_handle_cont, block_id, std::move(promise));
} else {
promise.set_value(R.move_as_ok());
}
});
td::actor::send_closure(f->file_actor_id(), &ArchiveFile::read_handle, block_id, std::move(P));
} else {
read_handle_cont(block_id, std::move(promise));
}
}
void ArchiveManager::read_handle_cont(BlockIdExt block_id, td::Promise<BlockHandle> promise) {
auto f = get_file_by_seqno(block_id.shard_full(), block_id.seqno(), false);
if (!f) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in archive db"));
return;
}
td::actor::send_closure(f->file_actor_id(), &ArchiveFile::read_handle, block_id, std::move(promise));
}
UnixTime ArchiveManager::convert_ts(UnixTime ts, bool key_block) {
if (!key_block) {
return ts - (ts % (1 << 17));
} else {
return ts - (ts % (1 << 22));
}
}
ArchiveManager::FileDescription *ArchiveManager::get_file(UnixTime ts, bool key_block, bool force) {
ts = convert_ts(ts, key_block);
auto &f = key_block ? key_files_ : files_;
auto it = f.find(ts);
if (it != f.end()) {
return &it->second;
}
if (!force) {
return nullptr;
}
return add_file(ts, key_block);
}
ArchiveManager::FileDescription *ArchiveManager::add_file(UnixTime ts, bool key_block) {
CHECK((key_block ? key_files_ : files_).count(ts) == 0);
index_->begin_transaction().ensure();
{
std::vector<td::int32> t;
std::vector<td::int32> tk;
for (auto &e : files_) {
t.push_back(e.first);
}
for (auto &e : key_files_) {
tk.push_back(e.first);
}
(key_block ? tk : t).push_back(ts);
index_
->set(create_serialize_tl_object<ton_api::db_archive_index_key>().as_slice(),
create_serialize_tl_object<ton_api::db_archive_index_value>(std::move(t), std::move(tk)).as_slice())
.ensure();
}
{
index_
->set(create_serialize_tl_object<ton_api::db_archive_package_key>(ts, key_block).as_slice(),
create_serialize_tl_object<ton_api::db_archive_package_value>(
ts, key_block, std::vector<tl_object_ptr<ton_api::db_archive_package_firstBlock>>(), false)
.as_slice())
.ensure();
}
index_->commit_transaction().ensure();
FileDescription desc{ts, key_block};
auto w = td::actor::create_actor<ArchiveFile>(
PSTRING() << "archivefile" << ts,
PSTRING() << db_root_ << "/packed/" << (key_block ? "key" : "") << ts << ".pack", ts);
desc.file = std::move(w);
return &(key_block ? key_files_ : files_).emplace(ts, std::move(desc)).first->second;
}
void ArchiveManager::load_package(UnixTime ts, bool key_block) {
auto key = create_serialize_tl_object<ton_api::db_archive_package_key>(ts, key_block);
std::string value;
auto v = index_->get(key.as_slice(), value);
v.ensure();
CHECK(v.move_as_ok() == td::KeyValue::GetStatus::Ok);
auto R = fetch_tl_object<ton_api::db_archive_package_value>(value, true);
R.ensure();
auto x = R.move_as_ok();
if (x->deleted_) {
return;
}
FileDescription desc{ts, key_block};
for (auto &e : x->firstblocks_) {
desc.first_blocks[ShardIdFull{e->workchain_, static_cast<ShardId>(e->shard_)}] =
FileDescription::Desc{static_cast<td::uint32>(e->seqno_), static_cast<LogicalTime>(e->lt_)};
}
desc.file = td::actor::create_actor<ArchiveFile>(
PSTRING() << "archivefile" << ts,
PSTRING() << db_root_ << "/packed/" << (key_block ? "key" : "") << ts << ".pack", ts);
(key_block ? key_files_ : files_).emplace(ts, std::move(desc));
}
void ArchiveManager::update_desc(FileDescription &desc, ShardIdFull shard, BlockSeqno seqno, LogicalTime lt) {
auto it = desc.first_blocks.find(shard);
if (it != desc.first_blocks.end() && it->second.seqno <= seqno) {
return;
}
desc.first_blocks[shard] = FileDescription::Desc{seqno, lt};
std::vector<tl_object_ptr<ton_api::db_archive_package_firstBlock>> vec;
for (auto &e : desc.first_blocks) {
vec.push_back(create_tl_object<ton_api::db_archive_package_firstBlock>(e.first.workchain, e.first.shard,
e.second.seqno, e.second.lt));
}
index_->begin_transaction().ensure();
index_
->set(create_serialize_tl_object<ton_api::db_archive_package_key>(desc.unix_time, desc.key_block).as_slice(),
create_serialize_tl_object<ton_api::db_archive_package_value>(desc.unix_time, desc.key_block,
std::move(vec), false)
.as_slice())
.ensure();
index_->commit_transaction().ensure();
}
ArchiveManager::FileDescription *ArchiveManager::get_file_by_seqno(ShardIdFull shard, BlockSeqno seqno,
bool key_block) {
auto &f = (key_block ? key_files_ : files_);
for (auto it = f.rbegin(); it != f.rend(); it++) {
auto i = it->second.first_blocks.find(shard);
if (i != it->second.first_blocks.end() && i->second.seqno <= seqno) {
return &it->second;
}
}
return nullptr;
}
void ArchiveManager::start_up() {
td::mkdir(db_root_).ensure();
td::mkdir(db_root_ + "/packed").ensure();
index_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_root_ + "/packed/globalindex").move_as_ok());
std::string value;
auto v = index_->get(create_serialize_tl_object<ton_api::db_archive_index_key>().as_slice(), value);
v.ensure();
if (v.move_as_ok() == td::KeyValue::GetStatus::Ok) {
auto R = fetch_tl_object<ton_api::db_archive_index_value>(value, true);
R.ensure();
auto x = R.move_as_ok();
for (auto &d : x->packages_) {
load_package(d, false);
}
for (auto &d : x->key_packages_) {
load_package(d, true);
}
}
}
} // namespace validator
} // namespace ton

View file

@ -0,0 +1,97 @@
#pragma once
#include "td/actor/actor.h"
#include "td/utils/buffer.h"
#include "ton/ton-types.h"
#include "td/utils/port/FileFd.h"
#include "package.hpp"
#include "filedb.hpp"
#include "validator/interfaces/block-handle.h"
#include <map>
#include <list>
namespace ton {
namespace validator {
class PackageWriter : public td::actor::Actor {
public:
PackageWriter(std::shared_ptr<Package> package) : package_(std::move(package)) {
}
void append(std::string filename, td::BufferSlice data, td::Promise<std::pair<td::uint64, td::uint64>> promise);
private:
std::shared_ptr<Package> package_;
};
class ArchiveFile : public td::actor::Actor {
public:
ArchiveFile(std::string path, UnixTime ts) : path_(std::move(path)), ts_(ts) {
}
void start_up() override;
void write(FileDb::RefId ref_id, td::BufferSlice data, td::Promise<td::Unit> promise);
void write_handle(BlockHandle handle, td::Promise<td::Unit> promise);
void read(FileDb::RefId ref_id, td::Promise<td::BufferSlice> promise);
void read_handle(BlockIdExt block_id, td::Promise<BlockHandle> promise);
private:
void completed_write(FileDb::RefId ref_id, td::uint64 offset, td::uint64 new_size, td::Promise<td::Unit> promise);
std::shared_ptr<Package> package_;
std::shared_ptr<td::KeyValue> index_;
td::actor::ActorOwn<PackageWriter> writer_;
std::string path_;
UnixTime ts_;
};
class ArchiveManager : public td::actor::Actor {
public:
ArchiveManager(std::string db_root);
void write(UnixTime ts, bool key_block, FileDb::RefId ref_id, td::BufferSlice data, td::Promise<td::Unit> promise);
void write_handle(BlockHandle handle, td::Promise<td::Unit> promise);
void read(UnixTime ts, bool key_block, FileDb::RefId ref_id, td::Promise<td::BufferSlice> promise);
void read_handle(BlockIdExt block_id, td::Promise<BlockHandle> promise);
void start_up() override;
private:
void read_handle_cont(BlockIdExt block_id, td::Promise<BlockHandle> promise);
struct FileDescription {
struct Desc {
BlockSeqno seqno;
LogicalTime lt;
};
FileDescription(UnixTime unix_time, bool key_block) : unix_time(unix_time), key_block(key_block) {
}
auto file_actor_id() const {
return file.get();
}
UnixTime unix_time;
bool key_block;
std::map<ShardIdFull, Desc> first_blocks;
td::actor::ActorOwn<ArchiveFile> file;
};
void load_package(UnixTime ts, bool key_block);
UnixTime convert_ts(UnixTime ts, bool key_block);
FileDescription *get_file(UnixTime ts, bool key_block, bool force = true);
FileDescription *add_file(UnixTime ts, bool key_block);
void update_desc(FileDescription &desc, ShardIdFull shard, BlockSeqno seqno, LogicalTime lt);
FileDescription *get_file_by_seqno(ShardIdFull shard, BlockSeqno seqno, bool key_block);
std::string db_root_;
std::map<UnixTime, FileDescription> files_;
std::map<UnixTime, FileDescription> key_files_;
std::shared_ptr<td::KeyValue> index_;
};
} // namespace validator
} // namespace ton

View file

@ -26,8 +26,13 @@ namespace validator {
BlockArchiver::BlockArchiver(BlockIdExt block_id, td::actor::ActorId<RootDb> root_db,
td::actor::ActorId<FileDb> file_db, td::actor::ActorId<FileDb> archive_db,
td::Promise<td::Unit> promise)
: block_id_(block_id), root_db_(root_db), file_db_(file_db), archive_db_(archive_db), promise_(std::move(promise)) {
td::actor::ActorId<ArchiveManager> archive, td::Promise<td::Unit> promise)
: block_id_(block_id)
, root_db_(root_db)
, file_db_(file_db)
, archive_db_(archive_db)
, archive_(archive)
, promise_(std::move(promise)) {
}
void BlockArchiver::start_up() {
@ -40,7 +45,7 @@ void BlockArchiver::start_up() {
void BlockArchiver::got_block_handle(BlockHandle handle) {
handle_ = std::move(handle);
if (handle_->moved_to_storage()) {
if (handle_->moved_to_archive()) {
finish_query();
return;
}
@ -63,16 +68,21 @@ void BlockArchiver::got_block_handle(BlockHandle handle) {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::got_proof, R.move_as_ok());
});
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Proof{block_id_}}, std::move(P));
if (handle_->moved_to_storage()) {
td::actor::send_closure(archive_db_, &FileDb::load_file, FileDb::RefId{fileref::Proof{block_id_}}, std::move(P));
} else {
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Proof{block_id_}}, std::move(P));
}
}
void BlockArchiver::got_proof(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> R) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::written_proof);
});
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::Proof{block_id_}}, std::move(data),
std::move(P));
td::actor::send_closure(archive_, &ArchiveManager::write, handle_->unix_time(), handle_->is_key_block(),
FileDb::RefId{fileref::Proof{block_id_}}, std::move(data), std::move(P));
}
void BlockArchiver::written_proof() {
@ -85,16 +95,21 @@ void BlockArchiver::written_proof() {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::got_proof_link, R.move_as_ok());
});
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::ProofLink{block_id_}}, std::move(P));
if (handle_->moved_to_storage()) {
td::actor::send_closure(archive_db_, &FileDb::load_file, FileDb::RefId{fileref::ProofLink{block_id_}},
std::move(P));
} else {
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::ProofLink{block_id_}}, std::move(P));
}
}
void BlockArchiver::got_proof_link(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> R) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::written_proof_link);
});
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::ProofLink{block_id_}},
std::move(data), std::move(P));
td::actor::send_closure(archive_, &ArchiveManager::write, handle_->unix_time(), handle_->is_key_block(),
FileDb::RefId{fileref::ProofLink{block_id_}}, std::move(data), std::move(P));
}
void BlockArchiver::written_proof_link() {
@ -106,20 +121,24 @@ void BlockArchiver::written_proof_link() {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::got_block_data, R.move_as_ok());
});
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Block{block_id_}}, std::move(P));
if (handle_->moved_to_storage()) {
td::actor::send_closure(archive_db_, &FileDb::load_file, FileDb::RefId{fileref::Block{block_id_}}, std::move(P));
} else {
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Block{block_id_}}, std::move(P));
}
}
void BlockArchiver::got_block_data(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> R) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::written_block_data);
});
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::Block{block_id_}}, std::move(data),
std::move(P));
td::actor::send_closure(archive_, &ArchiveManager::write, handle_->unix_time(), handle_->is_key_block(),
FileDb::RefId{fileref::Block{block_id_}}, std::move(data), std::move(P));
}
void BlockArchiver::written_block_data() {
handle_->set_moved_to_storage();
handle_->set_moved_to_archive();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();

View file

@ -22,6 +22,7 @@
#include "td/actor/actor.h"
#include "validator/interfaces/block-handle.h"
#include "ton/ton-io.hpp"
#include "archive-db.hpp"
namespace ton {
@ -33,7 +34,8 @@ class FileDb;
class BlockArchiver : public td::actor::Actor {
public:
BlockArchiver(BlockIdExt block_id, td::actor::ActorId<RootDb> root_db, td::actor::ActorId<FileDb> file_db,
td::actor::ActorId<FileDb> archive_db, td::Promise<td::Unit> promise);
td::actor::ActorId<FileDb> archive_db, td::actor::ActorId<ArchiveManager> archive,
td::Promise<td::Unit> promise);
void abort_query(td::Status error);
@ -52,6 +54,7 @@ class BlockArchiver : public td::actor::Actor {
td::actor::ActorId<RootDb> root_db_;
td::actor::ActorId<FileDb> file_db_;
td::actor::ActorId<FileDb> archive_db_;
td::actor::ActorId<ArchiveManager> archive_;
td::Promise<td::Unit> promise_;
BlockHandle handle_;

View file

@ -331,6 +331,9 @@ FileDb::RefId FileDb::get_ref_from_tl(const ton_api::db_filedb_Key& from) {
[&](const ton_api::db_filedb_key_candidate& key) {
ref_id = fileref::Candidate{PublicKey{key.id_->source_}, create_block_id(key.id_->id_),
key.id_->collated_data_file_hash_};
},
[&](const ton_api::db_filedb_key_blockInfo& key) {
ref_id = fileref::BlockInfo{create_block_id(key.block_id_)};
}));
return ref_id;
}

View file

@ -130,6 +130,18 @@ class Candidate {
BlockIdExt block_id;
FileHash collated_data_file_hash;
};
class BlockInfo {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_blockInfo>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_blockInfo>(create_tl_block_id(block_id));
}
BlockIdExt block_id;
};
}; // namespace fileref
class RootDb;
@ -138,7 +150,7 @@ class FileDb : public td::actor::Actor {
public:
using RefId =
td::Variant<fileref::Empty, fileref::Block, fileref::ZeroState, fileref::PersistentState, fileref::Proof,
fileref::Proof, fileref::ProofLink, fileref::Signatures, fileref::Candidate>;
fileref::Proof, fileref::ProofLink, fileref::Signatures, fileref::Candidate, fileref::BlockInfo>;
using RefIdHash = td::Bits256;
void store_file(RefId ref_id, td::BufferSlice data, td::Promise<FileHash> promise);

View file

@ -52,7 +52,7 @@ class WriteFile : public td::actor::Actor {
auto res = R.move_as_ok();
auto file = std::move(res.first);
auto old_name = res.second;
size_t offset = 0;
td::uint64 offset = 0;
while (data_.size() > 0) {
auto R = file.pwrite(data_.as_slice(), offset);
auto s = R.move_as_ok();

143
validator/db/package.cpp Normal file
View file

@ -0,0 +1,143 @@
#include "package.hpp"
#include "common/errorcode.h"
namespace ton {
namespace {
constexpr td::uint32 header_size() {
return 4;
}
constexpr td::uint32 max_data_size() {
return (1u << 31) - 1;
}
constexpr td::uint32 max_filename_size() {
return (1u << 16) - 1;
}
constexpr td::uint16 entry_header_magic() {
return 0x1e8b;
}
constexpr td::uint32 package_header_magic() {
return 0xae8fdd01;
}
} // namespace
Package::Package(td::FileFd fd) : fd_(std::move(fd)) {
}
td::Status Package::truncate(td::uint64 size) {
TRY_STATUS(fd_.seek(size + header_size()));
return fd_.truncate_to_current_position(size + header_size());
}
td::uint64 Package::append(std::string filename, td::Slice data) {
CHECK(data.size() <= max_data_size());
CHECK(filename.size() <= max_filename_size());
auto size = fd_.get_size().move_as_ok();
auto orig_size = size;
td::uint32 header[2];
header[0] = entry_header_magic() + (td::narrow_cast<td::uint32>(filename.size()) << 16);
header[1] = td::narrow_cast<td::uint32>(data.size());
CHECK(fd_.pwrite(td::Slice(reinterpret_cast<const td::uint8*>(header), 8), size).move_as_ok() == 8);
size += 8;
CHECK(fd_.pwrite(filename, size).move_as_ok() == filename.size());
size += filename.size();
CHECK(fd_.pwrite(data, size).move_as_ok() == data.size());
size += data.size();
fd_.sync().ensure();
return orig_size - header_size();
}
td::uint64 Package::size() const {
return fd_.get_size().move_as_ok() - header_size();
}
td::Result<std::pair<std::string, td::BufferSlice>> Package::read(td::uint64 offset) const {
offset += header_size();
td::uint32 header[2];
TRY_RESULT(s1, fd_.pread(td::MutableSlice(reinterpret_cast<td::uint8*>(header), 8), offset));
if (s1 != 8) {
return td::Status::Error(ErrorCode::notready, "too short read");
}
if ((header[0] & 0xffff) != entry_header_magic()) {
return td::Status::Error(ErrorCode::notready, "bad entry magic");
}
offset += 8;
auto fname_size = header[0] >> 16;
auto data_size = header[1];
std::string fname(fname_size, '\0');
TRY_RESULT(s2, fd_.pread(fname, offset));
if (s2 != fname_size) {
return td::Status::Error(ErrorCode::notready, "too short read (filename)");
}
offset += fname_size;
td::BufferSlice data{data_size};
TRY_RESULT(s3, fd_.pread(data.as_slice(), offset));
if (s3 != data_size) {
return td::Status::Error(ErrorCode::notready, "too short read (data)");
}
return std::pair<std::string, td::BufferSlice>{std::move(fname), std::move(data)};
}
td::Result<td::uint64> Package::advance(td::uint64 offset) {
offset += header_size();
td::uint32 header[2];
TRY_RESULT(s1, fd_.pread(td::MutableSlice(reinterpret_cast<td::uint8*>(header), 8), offset));
if (s1 != 8) {
return td::Status::Error(ErrorCode::notready, "too short read");
}
if ((header[0] & 0xffff) != entry_header_magic()) {
return td::Status::Error(ErrorCode::notready, "bad entry magic");
}
offset += 8 + (header[0] >> 16) + header[1];
if (offset > static_cast<td::uint64>(fd_.get_size().move_as_ok())) {
return td::Status::Error(ErrorCode::notready, "truncated read");
}
return offset - header_size();
}
td::Result<Package> Package::open(std::string path, bool read_only, bool create) {
td::uint32 flags = td::FileFd::Flags::Read;
if (!read_only) {
flags |= td::FileFd::Write;
}
if (create) {
flags |= td::FileFd::Create;
}
TRY_RESULT(fd, td::FileFd::open(path, flags));
TRY_RESULT(size, fd.get_size());
if (size < header_size()) {
if (!create) {
return td::Status::Error(ErrorCode::notready, "db is too short");
}
td::uint32 header[1];
header[0] = package_header_magic();
TRY_RESULT(s, fd.pwrite(td::Slice(reinterpret_cast<const td::uint8*>(header), header_size()), size));
if (s != header_size()) {
return td::Status::Error(ErrorCode::notready, "db write is short");
}
} else {
td::uint32 header[1];
TRY_RESULT(s, fd.pread(td::MutableSlice(reinterpret_cast<td::uint8*>(header), header_size()), 0));
if (s != header_size()) {
return td::Status::Error(ErrorCode::notready, "db read failed");
}
if (header[0] != package_header_magic()) {
return td::Status::Error(ErrorCode::notready, "magic mismatch");
}
}
return Package{std::move(fd)};
}
} // namespace ton

40
validator/db/package.hpp Normal file
View file

@ -0,0 +1,40 @@
#pragma once
#include "td/actor/actor.h"
#include "td/utils/port/FileFd.h"
#include "td/utils/buffer.h"
namespace ton {
class Package {
public:
static td::Result<Package> open(std::string path, bool read_only = false, bool create = false);
Package(td::FileFd fd);
td::Status truncate(td::uint64 size);
td::uint64 append(std::string filename, td::Slice data);
td::uint64 size() const;
td::Result<std::pair<std::string, td::BufferSlice>> read(td::uint64 offset) const;
td::Result<td::uint64> advance(td::uint64 offset);
struct Iterator {
td::uint64 offset;
Package &package;
Iterator operator++(int);
const Iterator operator++(int) const;
td::Result<std::pair<std::string, td::BufferSlice>> read() const;
};
Iterator begin();
const Iterator begin() const;
Iterator end();
const Iterator end() const;
private:
td::FileFd fd_;
};
} // namespace ton

View file

@ -32,7 +32,7 @@ namespace ton {
namespace validator {
void RootDb::store_block_data(BlockHandle handle, td::Ref<BlockData> block, td::Promise<td::Unit> promise) {
if (handle->moved_to_storage()) {
if (handle->moved_to_storage() || handle->moved_to_archive()) {
promise.set_value(td::Unit());
return;
}
@ -64,14 +64,19 @@ void RootDb::get_block_data(BlockHandle handle, td::Promise<td::Ref<BlockData>>
}
});
td::actor::send_closure(handle->moved_to_storage() ? archive_db_.get() : file_db_.get(), &FileDb::load_file,
FileDb::RefId{fileref::Block{handle->id()}}, std::move(P));
if (handle->moved_to_archive()) {
td::actor::send_closure(new_archive_db_, &ArchiveManager::read, handle->unix_time(), handle->is_key_block(),
FileDb::RefId{fileref::Block{handle->id()}}, std::move(P));
} else {
td::actor::send_closure(handle->moved_to_storage() ? old_archive_db_.get() : file_db_.get(), &FileDb::load_file,
FileDb::RefId{fileref::Block{handle->id()}}, std::move(P));
}
}
}
void RootDb::store_block_signatures(BlockHandle handle, td::Ref<BlockSignatureSet> data,
td::Promise<td::Unit> promise) {
if (handle->moved_to_storage()) {
if (handle->moved_to_storage() || handle->moved_to_archive()) {
promise.set_value(td::Unit());
return;
}
@ -94,7 +99,7 @@ void RootDb::get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockS
if (!handle->inited_signatures()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
} else {
if (handle->moved_to_storage()) {
if (handle->moved_to_storage() || handle->moved_to_archive()) {
promise.set_error(td::Status::Error(ErrorCode::error, "signatures already gc'd"));
return;
}
@ -111,7 +116,7 @@ void RootDb::get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockS
}
void RootDb::store_block_proof(BlockHandle handle, td::Ref<Proof> proof, td::Promise<td::Unit> promise) {
if (handle->moved_to_storage()) {
if (handle->moved_to_storage() || handle->moved_to_archive()) {
promise.set_value(td::Unit());
return;
}
@ -142,13 +147,18 @@ void RootDb::get_block_proof(BlockHandle handle, td::Promise<td::Ref<Proof>> pro
promise.set_result(create_proof(id, R.move_as_ok()));
}
});
td::actor::send_closure(handle->moved_to_storage() ? archive_db_.get() : file_db_.get(), &FileDb::load_file,
FileDb::RefId{fileref::Proof{handle->id()}}, std::move(P));
if (handle->moved_to_archive()) {
td::actor::send_closure(new_archive_db_, &ArchiveManager::read, handle->unix_time(), handle->is_key_block(),
FileDb::RefId{fileref::Proof{handle->id()}}, std::move(P));
} else {
td::actor::send_closure(handle->moved_to_storage() ? old_archive_db_.get() : file_db_.get(), &FileDb::load_file,
FileDb::RefId{fileref::Proof{handle->id()}}, std::move(P));
}
}
}
void RootDb::store_block_proof_link(BlockHandle handle, td::Ref<ProofLink> proof, td::Promise<td::Unit> promise) {
if (handle->moved_to_storage()) {
if (handle->moved_to_storage() || handle->moved_to_archive()) {
promise.set_value(td::Unit());
return;
}
@ -179,8 +189,13 @@ void RootDb::get_block_proof_link(BlockHandle handle, td::Promise<td::Ref<ProofL
promise.set_result(create_proof_link(id, R.move_as_ok()));
}
});
td::actor::send_closure(handle->moved_to_storage() ? archive_db_.get() : file_db_.get(), &FileDb::load_file,
FileDb::RefId{fileref::ProofLink{handle->id()}}, std::move(P));
if (handle->moved_to_archive()) {
td::actor::send_closure(new_archive_db_, &ArchiveManager::read, handle->unix_time(), handle->is_key_block(),
FileDb::RefId{fileref::ProofLink{handle->id()}}, std::move(P));
} else {
td::actor::send_closure(handle->moved_to_storage() ? old_archive_db_.get() : file_db_.get(), &FileDb::load_file,
FileDb::RefId{fileref::ProofLink{handle->id()}}, std::move(P));
}
}
}
@ -225,7 +240,7 @@ void RootDb::get_block_candidate(PublicKey source, BlockIdExt id, FileHash colla
void RootDb::store_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) {
if (handle->moved_to_storage()) {
if (handle->moved_to_storage() || handle->moved_to_archive()) {
promise.set_value(std::move(state));
return;
}
@ -290,27 +305,27 @@ void RootDb::store_persistent_state_file(BlockIdExt block_id, BlockIdExt masterc
}
});
td::actor::send_closure(archive_db_, &FileDb::store_file,
td::actor::send_closure(old_archive_db_, &FileDb::store_file,
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(state),
std::move(P));
}
void RootDb::get_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id,
td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(archive_db_, &FileDb::load_file,
td::actor::send_closure(old_archive_db_, &FileDb::load_file,
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,
td::actor::send_closure(old_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,
td::actor::send_closure(old_archive_db_, &FileDb::check_file,
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(promise));
}
@ -325,26 +340,38 @@ void RootDb::store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, t
}
});
td::actor::send_closure(archive_db_, &FileDb::store_file, FileDb::RefId{fileref::ZeroState{block_id}},
td::actor::send_closure(old_archive_db_, &FileDb::store_file, FileDb::RefId{fileref::ZeroState{block_id}},
std::move(state), std::move(P));
}
void RootDb::get_zero_state_file(BlockIdExt block_id, td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(archive_db_, &FileDb::load_file, FileDb::RefId{fileref::ZeroState{block_id}},
td::actor::send_closure(old_archive_db_, &FileDb::load_file, FileDb::RefId{fileref::ZeroState{block_id}},
std::move(promise));
}
void RootDb::check_zero_state_file_exists(BlockIdExt block_id, td::Promise<bool> promise) {
td::actor::send_closure(archive_db_, &FileDb::check_file, FileDb::RefId{fileref::ZeroState{block_id}},
td::actor::send_closure(old_archive_db_, &FileDb::check_file, FileDb::RefId{fileref::ZeroState{block_id}},
std::move(promise));
}
void RootDb::store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
td::actor::send_closure(block_db_, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
if (handle->moved_to_archive()) {
td::actor::send_closure(new_archive_db_, &ArchiveManager::write_handle, std::move(handle), std::move(promise));
} else {
td::actor::send_closure(block_db_, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
}
}
void RootDb::get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) {
td::actor::send_closure(block_db_, &BlockDb::get_block_handle, id, std::move(promise));
auto P = td::PromiseCreator::lambda(
[db = block_db_.get(), id, promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
td::actor::send_closure(db, &BlockDb::get_block_handle, id, std::move(promise));
} else {
promise.set_value(R.move_as_ok());
}
});
td::actor::send_closure(new_archive_db_, &ArchiveManager::read_handle, id, std::move(P));
}
void RootDb::try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
@ -426,16 +453,17 @@ void RootDb::start_up() {
cell_db_ = td::actor::create_actor<CellDb>("celldb", actor_id(this), root_path_ + "/celldb/");
block_db_ = td::actor::create_actor<BlockDb>("blockdb", actor_id(this), root_path_ + "/blockdb/");
file_db_ = td::actor::create_actor<FileDb>("filedb", actor_id(this), root_path_ + "/files/", depth_, false);
archive_db_ =
old_archive_db_ =
td::actor::create_actor<FileDb>("filedbarchive", actor_id(this), root_path_ + "/archive/", depth_, true);
lt_db_ = td::actor::create_actor<LtDb>("ltdb", actor_id(this), root_path_ + "/ltdb/");
state_db_ = td::actor::create_actor<StateDb>("statedb", actor_id(this), root_path_ + "/state/");
static_files_db_ = td::actor::create_actor<StaticFilesDb>("staticfilesdb", actor_id(this), root_path_ + "/static/");
new_archive_db_ = td::actor::create_actor<ArchiveManager>("archivemanager", root_path_ + "/archive/");
}
void RootDb::archive(BlockIdExt block_id, td::Promise<td::Unit> promise) {
td::actor::create_actor<BlockArchiver>("archiveblock", block_id, actor_id(this), file_db_.get(), archive_db_.get(),
std::move(promise))
td::actor::create_actor<BlockArchiver>("archiveblock", block_id, actor_id(this), file_db_.get(),
old_archive_db_.get(), new_archive_db_.get(), std::move(promise))
.release();
}
@ -480,14 +508,15 @@ void RootDb::allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> p
CHECK(!is_archive);
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_candidate_gc,
key.block_id, std::move(promise));
}));
},
[&](const fileref::BlockInfo &key) { UNREACHABLE(); }));
}
void RootDb::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) {
auto merger = StatsMerger::create(std::move(promise));
td::actor::send_closure(file_db_, &FileDb::prepare_stats, merger.make_promise("filedb."));
td::actor::send_closure(archive_db_, &FileDb::prepare_stats, merger.make_promise("archivedb."));
td::actor::send_closure(old_archive_db_, &FileDb::prepare_stats, merger.make_promise("archivedb."));
}
void RootDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {

View file

@ -28,6 +28,7 @@
#include "ltdb.hpp"
#include "statedb.hpp"
#include "staticfilesdb.hpp"
#include "archive-db.hpp"
namespace ton {
@ -126,10 +127,11 @@ class RootDb : public Db {
td::actor::ActorOwn<CellDb> cell_db_;
td::actor::ActorOwn<BlockDb> block_db_;
td::actor::ActorOwn<FileDb> file_db_;
td::actor::ActorOwn<FileDb> archive_db_;
td::actor::ActorOwn<FileDb> old_archive_db_;
td::actor::ActorOwn<LtDb> lt_db_;
td::actor::ActorOwn<StateDb> state_db_;
td::actor::ActorOwn<StaticFilesDb> static_files_db_;
td::actor::ActorOwn<ArchiveManager> new_archive_db_;
};
} // namespace validator

View file

@ -33,6 +33,7 @@ struct BlockHandleInterface {
virtual BlockIdExt id() const = 0;
virtual bool received() const = 0;
virtual bool moved_to_storage() const = 0;
virtual bool moved_to_archive() const = 0;
virtual bool deleted() const = 0;
virtual bool inited_next_left() const = 0;
virtual bool inited_next_right() const = 0;
@ -83,6 +84,7 @@ struct BlockHandleInterface {
virtual void set_prev(BlockIdExt prev) = 0;
virtual void set_received() = 0;
virtual void set_moved_to_storage() = 0;
virtual void set_moved_to_archive() = 0;
virtual void set_deleted() = 0;
virtual void set_split(bool value) = 0;
virtual void set_merge(bool value) = 0;

View file

@ -1842,6 +1842,27 @@ void ValidatorManagerImpl::allow_block_state_gc(BlockIdExt block_id, td::Promise
UNREACHABLE();
}
void ValidatorManagerImpl::allow_block_info_gc(BlockIdExt block_id, td::Promise<bool> promise) {
auto P =
td::PromiseCreator::lambda([db = db_.get(), promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
promise.set_result(false);
} else {
auto handle = R.move_as_ok();
if (!handle->moved_to_archive()) {
promise.set_result(false);
} else {
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
R.ensure();
promise.set_result(true);
});
td::actor::send_closure(db, &Db::store_block_handle, handle, std::move(P));
}
}
});
get_block_handle(block_id, false, std::move(P));
}
void ValidatorManagerImpl::got_next_gc_masterchain_handle(BlockHandle handle) {
CHECK(gc_advancing_);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Ref<ShardState>> R) {

View file

@ -463,11 +463,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void allow_delete(BlockIdExt block_id, td::Promise<bool> promise);
void allow_archive(BlockIdExt block_id, td::Promise<bool> promise);
void allow_block_data_gc(BlockIdExt block_id, bool is_archive, td::Promise<bool> promise) override {
if (!is_archive) {
allow_archive(block_id, std::move(promise));
} else {
allow_delete(block_id, std::move(promise));
}
allow_archive(block_id, std::move(promise));
}
void allow_block_state_gc(BlockIdExt block_id, td::Promise<bool> promise) override;
void allow_zero_state_file_gc(BlockIdExt block_id, td::Promise<bool> promise) override {
@ -479,25 +475,15 @@ class ValidatorManagerImpl : public ValidatorManager {
allow_archive(block_id, std::move(promise));
}
void allow_block_proof_gc(BlockIdExt block_id, bool is_archive, td::Promise<bool> promise) override {
if (!is_archive) {
allow_archive(block_id, std::move(promise));
} else {
allow_delete(block_id, std::move(promise));
}
allow_archive(block_id, std::move(promise));
}
void allow_block_proof_link_gc(BlockIdExt block_id, bool is_archive, td::Promise<bool> promise) override {
if (!is_archive) {
allow_archive(block_id, std::move(promise));
} else {
allow_delete(block_id, std::move(promise));
}
allow_archive(block_id, std::move(promise));
}
void allow_block_candidate_gc(BlockIdExt block_id, td::Promise<bool> promise) override {
allow_block_state_gc(block_id, std::move(promise));
}
void allow_block_info_gc(BlockIdExt block_id, td::Promise<bool> promise) override {
allow_delete(block_id, std::move(promise));
}
void allow_block_info_gc(BlockIdExt block_id, td::Promise<bool> promise) override;
void send_peek_key_block_request();
void got_next_key_blocks(std::vector<BlockIdExt> vec);

View file

@ -188,7 +188,7 @@ void DownloadState::got_block_state_part(td::BufferSlice data, td::uint32 reques
parts_.push_back(std::move(data));
if (last_part) {
td::BufferSlice res{sum_};
td::BufferSlice res{td::narrow_cast<std::size_t>(sum_)};
auto S = res.as_slice();
for (auto &p : parts_) {
S.copy_from(p.as_slice());