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

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

147
validator/db/archiver.cpp Normal file
View file

@ -0,0 +1,147 @@
/*
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 "archiver.hpp"
#include "rootdb.hpp"
#include "ton/ton-tl.hpp"
namespace ton {
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)) {
}
void BlockArchiver::start_up() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::got_block_handle, R.move_as_ok());
});
td::actor::send_closure(root_db_, &RootDb::get_block_handle_external, block_id_, false, std::move(P));
}
void BlockArchiver::got_block_handle(BlockHandle handle) {
handle_ = std::move(handle);
if (handle_->moved_to_storage()) {
finish_query();
return;
}
if (!handle_->is_applied() && !handle_->is_archived()) {
// no need for this block
// probably this block not in final chain
// this will eventually delete all associated data
written_block_data();
return;
}
if (!handle_->inited_proof()) {
written_proof();
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
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));
}
void BlockArchiver::got_proof(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> 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));
}
void BlockArchiver::written_proof() {
if (!handle_->inited_proof_link()) {
written_proof_link();
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
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));
}
void BlockArchiver::got_proof_link(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> 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));
}
void BlockArchiver::written_proof_link() {
if (!handle_->received()) {
written_block_data();
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
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));
}
void BlockArchiver::got_block_data(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<FileHash> 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));
}
void BlockArchiver::written_block_data() {
handle_->set_moved_to_storage();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &BlockArchiver::finish_query);
});
td::actor::send_closure(root_db_, &RootDb::store_block_handle, handle_, std::move(P));
}
void BlockArchiver::finish_query() {
if (promise_) {
promise_.set_value(td::Unit());
}
stop();
}
void BlockArchiver::abort_query(td::Status reason) {
if (promise_) {
VLOG(VALIDATOR_WARNING) << "failed to archive block " << block_id_ << ": " << reason;
promise_.set_error(std::move(reason));
}
stop();
}
} // namespace validator
} // namespace ton

62
validator/db/archiver.hpp Normal file
View file

@ -0,0 +1,62 @@
/*
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 "ton/ton-types.h"
#include "td/actor/actor.h"
#include "validator/interfaces/block-handle.h"
#include "ton/ton-io.hpp"
namespace ton {
namespace validator {
class RootDb;
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);
void abort_query(td::Status error);
void start_up() override;
void got_block_handle(BlockHandle handle);
void got_proof(td::BufferSlice data);
void written_proof();
void got_proof_link(td::BufferSlice data);
void written_proof_link();
void got_block_data(td::BufferSlice data);
void written_block_data();
void finish_query();
private:
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_;
BlockHandle handle_;
};
} // namespace validator
} // namespace ton

234
validator/db/blockdb.cpp Normal file
View file

@ -0,0 +1,234 @@
/*
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 "blockdb.hpp"
#include "rootdb.hpp"
#include "validator/fabric.h"
#include "ton/ton-tl.hpp"
#include "td/utils/port/path.h"
#include "files-async.hpp"
#include "td/db/RocksDb.h"
namespace ton {
namespace validator {
void BlockDb::store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
if (!handle->id().is_valid()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "invalid block id"));
return;
}
auto lru_key = get_block_lru_key(handle->id());
auto value_key = get_block_value_key(handle->id());
while (handle->need_flush()) {
auto version = handle->version();
auto R = get_block_value(value_key);
if (R.is_ok()) {
kv_->begin_transaction().ensure();
set_block_value(value_key, handle->serialize());
kv_->commit_transaction().ensure();
} else {
CHECK(get_block_lru(lru_key).is_error());
auto empty = get_block_lru_empty_key_hash();
auto ER = get_block_lru(empty);
ER.ensure();
auto E = ER.move_as_ok();
auto PR = get_block_lru(E.prev);
PR.ensure();
auto P = PR.move_as_ok();
CHECK(P.next == empty);
DbEntry D{handle->id(), E.prev, empty};
E.prev = lru_key;
P.next = lru_key;
if (P.is_empty()) {
E.next = lru_key;
P.prev = lru_key;
}
kv_->begin_transaction().ensure();
set_block_value(value_key, handle->serialize());
set_block_lru(empty, std::move(E));
set_block_lru(D.prev, std::move(P));
set_block_lru(lru_key, std::move(D));
kv_->commit_transaction().ensure();
}
handle->flushed_upto(version);
}
promise.set_value(td::Unit());
}
void BlockDb::get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) {
if (!id.is_valid()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "invalid block id"));
return;
}
CHECK(id.is_valid());
auto key_hash = get_block_value_key(id);
auto B = get_block_value(key_hash);
if (B.is_error()) {
promise.set_error(B.move_as_error());
return;
}
promise.set_result(create_block_handle(B.move_as_ok()));
}
void BlockDb::start_up() {
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
alarm_timestamp() = td::Timestamp::in(0.1);
auto empty = get_block_lru_empty_key_hash();
if (get_block_lru(empty).is_error()) {
DbEntry e{BlockIdExt{}, empty, empty};
kv_->begin_transaction().ensure();
set_block_lru(empty, std::move(e));
kv_->commit_transaction().ensure();
}
last_gc_ = empty;
}
BlockDb::BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
}
BlockDb::KeyHash BlockDb::get_block_lru_key(BlockIdExt id) {
if (!id.is_valid()) {
return KeyHash::zero();
} else {
auto obj = create_tl_object<ton_api::db_blockdb_key_lru>(create_tl_block_id(id));
return get_tl_object_sha_bits256(obj);
}
}
BlockDb::KeyHash BlockDb::get_block_value_key(BlockIdExt id) {
CHECK(id.is_valid());
auto obj = create_tl_object<ton_api::db_blockdb_key_value>(create_tl_block_id(id));
return get_tl_object_sha_bits256(obj);
}
td::Result<BlockDb::DbEntry> BlockDb::get_block_lru(KeyHash key_hash) {
std::string value;
auto R = kv_->get(key_hash.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
return td::Status::Error(ErrorCode::notready, "not in db");
}
auto v = fetch_tl_object<ton_api::db_blockdb_lru>(td::BufferSlice{value}, true);
v.ensure();
return DbEntry{v.move_as_ok()};
}
td::Result<td::BufferSlice> BlockDb::get_block_value(KeyHash key_hash) {
std::string value;
auto R = kv_->get(key_hash.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
return td::Status::Error(ErrorCode::notready, "not in db");
}
return td::BufferSlice{value};
}
void BlockDb::set_block_lru(KeyHash key_hash, DbEntry e) {
kv_->set(key_hash.as_slice(), serialize_tl_object(e.release(), true)).ensure();
}
void BlockDb::set_block_value(KeyHash key_hash, td::BufferSlice value) {
kv_->set(key_hash.as_slice(), std::move(value)).ensure();
}
void BlockDb::alarm() {
auto R = get_block_lru(last_gc_);
R.ensure();
auto N = R.move_as_ok();
if (N.is_empty()) {
last_gc_ = N.next;
alarm_timestamp() = td::Timestamp::in(0.01);
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &BlockDb::skip_gc);
} else {
auto value = R.move_as_ok();
if (!value) {
td::actor::send_closure(SelfId, &BlockDb::skip_gc);
} else {
td::actor::send_closure(SelfId, &BlockDb::gc);
}
}
});
td::actor::send_closure(root_db_, &RootDb::allow_block_gc, N.block_id, std::move(P));
}
void BlockDb::gc() {
auto FR = get_block_lru(last_gc_);
FR.ensure();
auto F = FR.move_as_ok();
auto PR = get_block_lru(F.prev);
PR.ensure();
auto P = PR.move_as_ok();
auto NR = get_block_lru(F.next);
NR.ensure();
auto N = NR.move_as_ok();
P.next = F.next;
N.prev = F.prev;
if (P.is_empty() && N.is_empty()) {
P.prev = P.next;
N.next = N.prev;
}
auto value_key = get_block_value_key(F.block_id);
kv_->begin_transaction().ensure();
kv_->erase(last_gc_.as_slice()).ensure();
kv_->erase(value_key.as_slice()).ensure();
set_block_lru(F.prev, std::move(P));
set_block_lru(F.next, std::move(N));
kv_->commit_transaction().ensure();
alarm_timestamp() = td::Timestamp::now();
DCHECK(get_block_lru(last_gc_).is_error());
last_gc_ = F.next;
}
void BlockDb::skip_gc() {
auto R = get_block_lru(last_gc_);
R.ensure();
auto N = R.move_as_ok();
last_gc_ = N.next;
alarm_timestamp() = td::Timestamp::in(0.01);
}
BlockDb::DbEntry::DbEntry(tl_object_ptr<ton_api::db_blockdb_lru> entry)
: block_id(create_block_id(entry->id_)), prev(entry->prev_), next(entry->next_) {
}
tl_object_ptr<ton_api::db_blockdb_lru> BlockDb::DbEntry::release() {
return create_tl_object<ton_api::db_blockdb_lru>(create_tl_block_id(block_id), prev, next);
}
} // namespace validator
} // namespace ton

86
validator/db/blockdb.hpp Normal file
View file

@ -0,0 +1,86 @@
/*
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 "td/actor/actor.h"
#include "ton/ton-types.h"
#include "validator/interfaces/block-handle.h"
#include "validator/interfaces/db.h"
#include "td/db/KeyValueAsync.h"
namespace ton {
namespace validator {
class RootDb;
class BlockDb : public td::actor::Actor {
public:
void store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise);
void get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise);
void start_up() override;
void alarm() override;
void gc();
void skip_gc();
BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path);
private:
using KeyHash = td::Bits256;
struct DbEntry {
BlockIdExt block_id;
KeyHash prev;
KeyHash next;
DbEntry(tl_object_ptr<ton_api::db_blockdb_lru> entry);
DbEntry() {
}
DbEntry(BlockIdExt block_id, KeyHash prev, KeyHash next) : block_id(block_id), prev(prev), next(next) {
}
tl_object_ptr<ton_api::db_blockdb_lru> release();
bool is_empty() const {
return !block_id.is_valid();
}
};
static KeyHash get_block_lru_key(BlockIdExt block_id);
static KeyHash get_block_value_key(BlockIdExt block_id);
static KeyHash get_block_lru_empty_key_hash() {
return KeyHash::zero();
}
td::Result<DbEntry> get_block_lru(KeyHash key);
td::Result<td::BufferSlice> get_block_value(KeyHash key);
void set_block_lru(KeyHash key_hash, DbEntry e);
void set_block_value(KeyHash key_hash, td::BufferSlice data);
std::shared_ptr<td::KeyValue> kv_;
td::actor::ActorId<RootDb> root_db_;
std::string db_path_;
KeyHash last_gc_ = KeyHash::zero();
};
} // namespace validator
} // namespace ton

283
validator/db/celldb.cpp Normal file
View file

@ -0,0 +1,283 @@
/*
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 "celldb.hpp"
#include "rootdb.hpp"
#include "td/db/RocksDb.h"
#include "ton/ton-tl.hpp"
#include "ton/ton-io.hpp"
namespace ton {
namespace validator {
CellDbIn::CellDbIn(td::actor::ActorId<RootDb> root_db, td::actor::ActorId<CellDb> parent, std::string path)
: root_db_(root_db), parent_(parent), path_(std::move(path)) {
}
void CellDbIn::start_up() {
cell_db_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_).move_as_ok());
boc_ = vm::DynamicBagOfCellsDb::create();
boc_->set_loader(std::make_unique<vm::CellLoader>(cell_db_->snapshot())).ensure();
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
alarm_timestamp() = td::Timestamp::in(10.0);
auto empty = get_empty_key_hash();
if (get_block(empty).is_error()) {
DbEntry e{get_empty_key(), empty, empty, RootHash::zero()};
cell_db_->begin_transaction().ensure();
set_block(empty, std::move(e));
cell_db_->commit_transaction().ensure();
}
last_gc_ = empty;
}
void CellDbIn::load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise) {
td::PerfWarningTimer{"loadcell", 0.1};
promise.set_result(boc_->load_cell(hash.as_slice()));
}
void CellDbIn::store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise) {
td::PerfWarningTimer{"storecell", 0.1};
auto key_hash = get_key_hash(block_id);
auto R = get_block(key_hash);
// duplicate
if (R.is_ok()) {
promise.set_result(boc_->load_cell(cell->get_hash().as_slice()));
return;
}
auto empty = get_empty_key_hash();
auto ER = get_block(empty);
ER.ensure();
auto E = ER.move_as_ok();
auto PR = get_block(E.prev);
PR.ensure();
auto P = PR.move_as_ok();
CHECK(P.next == empty);
DbEntry D{block_id, E.prev, empty, cell->get_hash().bits()};
E.prev = key_hash;
P.next = key_hash;
if (P.is_empty()) {
E.next = key_hash;
P.prev = key_hash;
}
boc_->inc(cell);
boc_->prepare_commit().ensure();
vm::CellStorer stor{*cell_db_.get()};
cell_db_->begin_transaction().ensure();
boc_->commit(stor).ensure();
set_block(empty, std::move(E));
set_block(D.prev, std::move(P));
set_block(key_hash, std::move(D));
cell_db_->commit_transaction().ensure();
boc_->set_loader(std::make_unique<vm::CellLoader>(cell_db_->snapshot())).ensure();
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
promise.set_result(boc_->load_cell(cell->get_hash().as_slice()));
}
void CellDbIn::alarm() {
auto R = get_block(last_gc_);
R.ensure();
auto N = R.move_as_ok();
if (N.is_empty()) {
last_gc_ = N.next;
alarm_timestamp() = td::Timestamp::in(0.1);
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &CellDbIn::skip_gc);
} else {
auto value = R.move_as_ok();
if (!value) {
td::actor::send_closure(SelfId, &CellDbIn::skip_gc);
} else {
td::actor::send_closure(SelfId, &CellDbIn::gc);
}
}
});
td::actor::send_closure(root_db_, &RootDb::allow_state_gc, N.block_id, std::move(P));
}
void CellDbIn::gc() {
auto R = get_block(last_gc_);
R.ensure();
auto N = R.move_as_ok();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
R.ensure();
td::actor::send_closure(SelfId, &CellDbIn::gc_cont, R.move_as_ok());
});
td::actor::send_closure(root_db_, &RootDb::get_block_handle_external, N.block_id, false, std::move(P));
}
void CellDbIn::gc_cont(BlockHandle handle) {
CHECK(handle->inited_state_boc());
handle->set_deleted_state_boc();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &CellDbIn::gc_cont2, handle);
});
td::actor::send_closure(root_db_, &RootDb::store_block_handle, handle, std::move(P));
}
void CellDbIn::gc_cont2(BlockHandle handle) {
td::PerfWarningTimer{"gccell", 0.1};
auto FR = get_block(last_gc_);
FR.ensure();
auto F = FR.move_as_ok();
auto PR = get_block(F.prev);
PR.ensure();
auto P = PR.move_as_ok();
auto NR = get_block(F.next);
NR.ensure();
auto N = NR.move_as_ok();
P.next = F.next;
N.prev = F.prev;
if (P.is_empty() && N.is_empty()) {
P.prev = P.next;
N.next = N.prev;
}
auto cell = boc_->load_cell(F.root_hash.as_slice()).move_as_ok();
boc_->dec(cell);
boc_->prepare_commit().ensure();
vm::CellStorer stor{*cell_db_.get()};
cell_db_->begin_transaction().ensure();
boc_->commit(stor).ensure();
cell_db_->erase(get_key(last_gc_)).ensure();
set_block(F.prev, std::move(P));
set_block(F.next, std::move(N));
cell_db_->commit_transaction().ensure();
alarm_timestamp() = td::Timestamp::now();
boc_->set_loader(std::make_unique<vm::CellLoader>(cell_db_->snapshot())).ensure();
td::actor::send_closure(parent_, &CellDb::update_snapshot, cell_db_->snapshot());
DCHECK(get_block(last_gc_).is_error());
last_gc_ = F.next;
}
void CellDbIn::skip_gc() {
auto FR = get_block(last_gc_);
FR.ensure();
auto F = FR.move_as_ok();
last_gc_ = F.next;
alarm_timestamp() = td::Timestamp::in(0.01);
}
std::string CellDbIn::get_key(KeyHash key_hash) {
if (!key_hash.is_zero()) {
return PSTRING() << "desc" << key_hash;
} else {
return "desczero";
}
}
CellDbIn::KeyHash CellDbIn::get_key_hash(BlockIdExt block_id) {
if (block_id.is_valid()) {
return get_tl_object_sha_bits256(create_tl_block_id(block_id));
} else {
return KeyHash::zero();
}
}
BlockIdExt CellDbIn::get_empty_key() {
return BlockIdExt{workchainInvalid, 0, 0, RootHash::zero(), FileHash::zero()};
}
CellDbIn::KeyHash CellDbIn::get_empty_key_hash() {
return KeyHash::zero();
}
td::Result<CellDbIn::DbEntry> CellDbIn::get_block(KeyHash key_hash) {
const auto key = get_key(key_hash);
std::string value;
auto R = cell_db_->get(td::as_slice(key), value);
R.ensure();
auto S = R.move_as_ok();
if (S == td::KeyValue::GetStatus::NotFound) {
return td::Status::Error(ErrorCode::notready, "not in db");
}
auto obj = fetch_tl_object<ton_api::db_celldb_value>(td::BufferSlice{value}, true);
obj.ensure();
return DbEntry{obj.move_as_ok()};
}
void CellDbIn::set_block(KeyHash key_hash, DbEntry e) {
const auto key = get_key(key_hash);
cell_db_->set(td::as_slice(key), e.release()).ensure();
}
void CellDb::load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise) {
if (!started_) {
td::actor::send_closure(cell_db_, &CellDbIn::load_cell, hash, std::move(promise));
} else {
auto R = boc_->load_cell(hash.as_slice());
if (R.is_error()) {
td::actor::send_closure(cell_db_, &CellDbIn::load_cell, hash, std::move(promise));
} else {
promise.set_result(R.move_as_ok());
}
}
}
void CellDb::store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise) {
td::actor::send_closure(cell_db_, &CellDbIn::store_cell, block_id, std::move(cell), std::move(promise));
}
void CellDb::start_up() {
boc_ = vm::DynamicBagOfCellsDb::create();
cell_db_ = td::actor::create_actor<CellDbIn>("celldbin", root_db_, actor_id(this), path_);
}
CellDbIn::DbEntry::DbEntry(tl_object_ptr<ton_api::db_celldb_value> entry)
: block_id(create_block_id(entry->block_id_))
, prev(entry->prev_)
, next(entry->next_)
, root_hash(entry->root_hash_) {
}
td::BufferSlice CellDbIn::DbEntry::release() {
return create_serialize_tl_object<ton_api::db_celldb_value>(create_tl_block_id(block_id), prev, next, root_hash);
}
} // namespace validator
} // namespace ton

117
validator/db/celldb.hpp Normal file
View file

@ -0,0 +1,117 @@
/*
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 "td/actor/actor.h"
#include "crypto/vm/db/DynamicBagOfCellsDb.h"
#include "crypto/vm/db/CellStorage.h"
#include "td/db/KeyValue.h"
#include "ton/ton-types.h"
#include "interfaces/block-handle.h"
#include "auto/tl/ton_api.h"
namespace ton {
namespace validator {
class RootDb;
class CellDb;
class CellDbIn : public td::actor::Actor {
public:
using KeyHash = td::Bits256;
void load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise);
void store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise);
CellDbIn(td::actor::ActorId<RootDb> root_db, td::actor::ActorId<CellDb> parent, std::string path);
void start_up() override;
void alarm() override;
private:
struct DbEntry {
BlockIdExt block_id;
KeyHash prev;
KeyHash next;
RootHash root_hash;
DbEntry(tl_object_ptr<ton_api::db_celldb_value> entry);
DbEntry() {
}
DbEntry(BlockIdExt block_id, KeyHash prev, KeyHash next, RootHash root_hash)
: block_id(block_id), prev(prev), next(next), root_hash(root_hash) {
}
td::BufferSlice release();
bool is_empty() const {
return !block_id.is_valid();
}
};
td::Result<DbEntry> get_block(KeyHash key);
void set_block(KeyHash key, DbEntry e);
static std::string get_key(KeyHash key);
static KeyHash get_key_hash(BlockIdExt block_id);
static BlockIdExt get_empty_key();
KeyHash get_empty_key_hash();
void gc();
void gc_cont(BlockHandle handle);
void gc_cont2(BlockHandle handle);
void skip_gc();
td::actor::ActorId<RootDb> root_db_;
td::actor::ActorId<CellDb> parent_;
std::string path_;
std::unique_ptr<vm::DynamicBagOfCellsDb> boc_;
std::shared_ptr<vm::KeyValue> cell_db_;
KeyHash last_gc_;
};
class CellDb : public td::actor::Actor {
public:
void load_cell(RootHash hash, td::Promise<td::Ref<vm::DataCell>> promise);
void store_cell(BlockIdExt block_id, td::Ref<vm::Cell> cell, td::Promise<td::Ref<vm::DataCell>> promise);
void update_snapshot(std::unique_ptr<td::KeyValueReader> snapshot) {
started_ = true;
boc_->set_loader(std::make_unique<vm::CellLoader>(std::move(snapshot))).ensure();
}
CellDb(td::actor::ActorId<RootDb> root_db, std::string path) : root_db_(root_db), path_(path) {
}
void start_up() override;
private:
td::actor::ActorId<RootDb> root_db_;
std::string path_;
td::actor::ActorOwn<CellDbIn> cell_db_;
std::unique_ptr<vm::DynamicBagOfCellsDb> boc_;
bool started_ = false;
};
} // namespace validator
} // namespace ton

333
validator/db/filedb.cpp Normal file
View file

@ -0,0 +1,333 @@
/*
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 "filedb.hpp"
#include "rootdb.hpp"
#include "td/utils/port/path.h"
#include "files-async.hpp"
#include "adnl/utils.hpp"
#include "tl-utils/tl-utils.hpp"
#include "td/utils/overloaded.h"
#include "td/db/RocksDb.h"
namespace ton {
namespace validator {
std::string FileDb::get_file_name(const RefId& ref_id, bool create_dirs) {
auto ref_id_hash = get_ref_id_hash(ref_id);
auto s = ref_id_hash.to_hex();
if (create_dirs) {
td::mkdir(root_path_ + "/files/" + s[0] + s[1] + "/").ensure();
td::mkdir(root_path_ + "/files/" + s[0] + s[1] + "/" + s[2] + s[3] + "/").ensure();
}
return root_path_ + "/files/" + s[0] + s[1] + "/" + s[2] + s[3] + "/" + s;
}
void FileDb::store_file(RefId ref_id, td::BufferSlice data, td::Promise<FileHash> promise) {
auto ref_id_hash = get_ref_id_hash(ref_id);
auto R = get_block(ref_id_hash);
if (R.is_ok()) {
auto val = R.move_as_ok();
promise.set_result(val.file_hash);
return;
}
auto file_hash = sha256_bits256(data.as_slice());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), file_hash, ref_id = std::move(ref_id),
promise = std::move(promise)](td::Result<std::string> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
td::actor::send_closure(SelfId, &FileDb::store_file_continue, std::move(ref_id), file_hash, R.move_as_ok(),
std::move(promise));
}
});
td::actor::create_actor<db::WriteFile>("writefile", root_path_ + "/tmp/", "", std::move(data), std::move(P))
.release();
}
void FileDb::store_file_continue(RefId ref_id, FileHash file_hash, std::string res_path,
td::Promise<FileHash> promise) {
auto ref_id_hash = get_ref_id_hash(ref_id);
auto R = get_block(ref_id_hash);
if (R.is_ok()) {
td::unlink(res_path).ignore();
auto val = R.move_as_ok();
promise.set_result(val.file_hash);
return;
}
auto path = get_file_name(ref_id, true);
td::rename(res_path, path).ensure();
auto empty = get_empty_ref_id_hash();
auto ER = get_block(empty);
ER.ensure();
auto E = ER.move_as_ok();
auto PR = get_block(E.prev);
PR.ensure();
auto P = PR.move_as_ok();
CHECK(P.next == empty);
DbEntry D;
D.key = std::move(ref_id);
D.prev = E.prev;
D.next = empty;
D.file_hash = file_hash;
E.prev = ref_id_hash;
P.next = ref_id_hash;
if (P.is_empty()) {
E.next = ref_id_hash;
P.prev = ref_id_hash;
}
kv_->begin_transaction().ensure();
set_block(empty, std::move(E));
set_block(D.prev, std::move(P));
set_block(ref_id_hash, std::move(D));
kv_->commit_transaction().ensure();
promise.set_value(std::move(file_hash));
}
void FileDb::load_file(RefId ref_id, 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), std::move(P)).release();
}
void FileDb::check_file(RefId ref_id, td::Promise<bool> promise) {
auto ref_id_hash = get_ref_id_hash(ref_id);
auto R = get_block(ref_id_hash);
if (R.is_error()) {
promise.set_result(false);
return;
}
promise.set_result(true);
}
td::Slice FileDb::get_key(const RefIdHash& ref) {
return ref.as_slice();
}
td::Result<FileDb::DbEntry> FileDb::get_block(const RefIdHash& ref) {
std::string value;
auto R = kv_->get(get_key(ref), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
return td::Status::Error(ErrorCode::notready, "not in db");
}
auto val = fetch_tl_object<ton_api::db_filedb_value>(td::BufferSlice{value}, true);
val.ensure();
return DbEntry{val.move_as_ok()};
}
void FileDb::set_block(const RefIdHash& ref, DbEntry entry) {
DCHECK(ref == get_ref_id_hash(entry.key));
kv_->set(get_key(ref), entry.release()).ensure();
}
FileDb::FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, bool is_archive)
: root_db_(root_db), root_path_(root_path), is_archive_(is_archive) {
}
void FileDb::start_up() {
td::mkdir(root_path_).ensure();
db_path_ = root_path_ + "/db/";
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
td::mkdir(root_path_ + "/files/").ensure();
td::mkdir(root_path_ + "/tmp/").ensure();
last_gc_ = get_empty_ref_id_hash();
alarm_timestamp() = td::Timestamp::in(0.01);
auto R = get_block(last_gc_);
if (R.is_error()) {
DbEntry e{get_empty_ref_id(), last_gc_, last_gc_, FileHash::zero()};
kv_->begin_transaction().ensure();
set_block(last_gc_, std::move(e));
kv_->commit_transaction().ensure();
}
}
void FileDb::alarm() {
auto R = get_block(last_gc_);
R.ensure();
auto N = R.move_as_ok();
if (N.is_empty()) {
last_gc_ = N.next;
alarm_timestamp() = td::Timestamp::in(0.01);
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) mutable {
if (R.is_error()) {
td::actor::send_closure(SelfId, &FileDb::skip_gc);
} else {
auto value = R.move_as_ok();
if (!value) {
td::actor::send_closure(SelfId, &FileDb::skip_gc);
} else {
td::actor::send_closure(SelfId, &FileDb::gc);
}
}
});
td::actor::send_closure(root_db_, &RootDb::allow_gc, std::move(N.key), is_archive_, std::move(P));
}
void FileDb::gc() {
auto FR = get_block(last_gc_);
FR.ensure();
auto F = FR.move_as_ok();
auto PR = get_block(F.prev);
PR.ensure();
auto P = PR.move_as_ok();
auto NR = get_block(F.next);
NR.ensure();
auto N = NR.move_as_ok();
P.next = F.next;
N.prev = F.prev;
if (P.is_empty() && N.is_empty()) {
P.prev = P.next;
N.next = N.prev;
}
auto name = get_file_name(F.key, false);
auto S = td::unlink(name);
if (S.is_error()) {
LOG(WARNING) << "failed to delete " << name;
}
kv_->begin_transaction().ensure();
kv_->erase(last_gc_.as_slice()).ensure();
set_block(F.prev, std::move(P));
set_block(F.next, std::move(N));
kv_->commit_transaction().ensure();
alarm_timestamp() = td::Timestamp::now();
DCHECK(get_block(last_gc_).is_error());
last_gc_ = F.next;
}
void FileDb::skip_gc() {
auto FR = get_block(last_gc_);
FR.ensure();
auto F = FR.move_as_ok();
last_gc_ = F.next;
alarm_timestamp() = td::Timestamp::in(0.01);
}
td::BufferSlice FileDb::DbEntry::release() {
return create_serialize_tl_object<ton_api::db_filedb_value>(get_ref_id_tl(key), prev, next, file_hash);
}
bool FileDb::DbEntry::is_empty() const {
return (key.get_offset() == key.offset<fileref::Empty>());
}
FileDb::RefIdHash FileDb::get_ref_id_hash(const RefId& ref) {
FileHash x;
ref.visit([&](const auto& obj) { x = obj.hash(); });
return x;
}
tl_object_ptr<ton_api::db_filedb_Key> FileDb::get_ref_id_tl(const RefId& ref) {
tl_object_ptr<ton_api::db_filedb_Key> x;
ref.visit([&](const auto& obj) { x = obj.tl(); });
return x;
}
FileDb::RefId FileDb::get_ref_from_tl(const ton_api::db_filedb_Key& from) {
RefId ref_id{fileref::Empty{}};
ton_api::downcast_call(
const_cast<ton_api::db_filedb_Key&>(from),
td::overloaded(
[&](const ton_api::db_filedb_key_empty& key) { ref_id = fileref::Empty{}; },
[&](const ton_api::db_filedb_key_blockFile& key) { ref_id = fileref::Block{create_block_id(key.block_id_)}; },
[&](const ton_api::db_filedb_key_zeroStateFile& key) {
ref_id = fileref::ZeroState{create_block_id(key.block_id_)};
},
[&](const ton_api::db_filedb_key_persistentStateFile& key) {
ref_id =
fileref::PersistentState{create_block_id(key.block_id_), create_block_id(key.masterchain_block_id_)};
},
[&](const ton_api::db_filedb_key_proof& key) { ref_id = fileref::Proof{create_block_id(key.block_id_)}; },
[&](const ton_api::db_filedb_key_proofLink& key) {
ref_id = fileref::ProofLink{create_block_id(key.block_id_)};
},
[&](const ton_api::db_filedb_key_signatures& key) {
ref_id = fileref::Signatures{create_block_id(key.block_id_)};
},
[&](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_};
}));
return ref_id;
}
FileDb::RefId FileDb::get_empty_ref_id() {
return fileref::Empty();
}
FileDb::RefIdHash FileDb::get_empty_ref_id_hash() {
if (empty_.is_zero()) {
empty_ = get_ref_id_hash(get_empty_ref_id());
}
return empty_;
}
FileDb::DbEntry::DbEntry(tl_object_ptr<ton_api::db_filedb_value> entry)
: key(FileDb::get_ref_from_tl(*entry->key_.get()))
, prev(entry->prev_)
, next(entry->next_)
, file_hash(entry->file_hash_) {
}
} // namespace validator
} // namespace ton

202
validator/db/filedb.hpp Normal file
View file

@ -0,0 +1,202 @@
/*
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 "ton/ton-types.h"
#include "td/actor/actor.h"
#include "validator/interfaces/shard.h"
#include "td/db/KeyValue.h"
#include "ton/ton-tl.hpp"
namespace ton {
namespace validator {
namespace fileref {
class Empty {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_empty>();
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_empty>();
}
};
class Block {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_blockFile>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_blockFile>(create_tl_block_id(block_id));
}
BlockIdExt block_id;
};
class ZeroState {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_zeroStateFile>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_zeroStateFile>(create_tl_block_id(block_id));
}
BlockIdExt block_id;
};
class PersistentState {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_persistentStateFile>(create_tl_block_id(block_id),
create_tl_block_id(masterchain_block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_persistentStateFile>(create_tl_block_id(block_id),
create_tl_block_id(masterchain_block_id));
}
BlockIdExt block_id;
BlockIdExt masterchain_block_id;
};
class Proof {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_proof>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_proof>(create_tl_block_id(block_id));
}
BlockIdExt block_id;
};
class ProofLink {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_proofLink>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_proofLink>(create_tl_block_id(block_id));
}
BlockIdExt block_id;
};
class Signatures {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_signatures>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_signatures>(create_tl_block_id(block_id));
}
BlockIdExt block_id;
};
class Candidate {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_candidate>(
create_tl_object<ton_api::db_candidate_id>(source.tl(), create_tl_block_id(block_id), collated_data_file_hash));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_candidate>(
create_tl_object<ton_api::db_candidate_id>(source.tl(), create_tl_block_id(block_id), collated_data_file_hash));
}
PublicKey source;
BlockIdExt block_id;
FileHash collated_data_file_hash;
};
}; // namespace fileref
class RootDb;
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>;
using RefIdHash = td::Bits256;
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 check_file(RefId ref_id, td::Promise<bool> promise);
void start_up() override;
void alarm() override;
void gc();
void skip_gc();
FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, bool is_archive);
private:
struct DbEntry {
RefId key;
RefIdHash prev;
RefIdHash next;
FileHash file_hash;
DbEntry(tl_object_ptr<ton_api::db_filedb_value> entry);
DbEntry() {
}
DbEntry(RefId key, RefIdHash prev, RefIdHash next, FileHash file_hash)
: key(std::move(key)), prev(prev), next(next), file_hash(file_hash) {
}
td::BufferSlice release();
bool is_empty() const;
};
static RefIdHash get_ref_id_hash(const RefId& ref);
static tl_object_ptr<ton_api::db_filedb_Key> get_ref_id_tl(const RefId& ref);
static RefId get_ref_from_tl(const ton_api::db_filedb_Key& from);
static RefId get_empty_ref_id();
RefIdHash get_empty_ref_id_hash();
std::string get_file_name(const RefId& ref, bool create_dirs);
td::Slice get_key(const RefIdHash& ref);
td::Result<DbEntry> get_block(const RefIdHash& ref_id);
void set_block(const RefIdHash& ref_id_hash, DbEntry entry);
td::actor::ActorId<RootDb> root_db_;
std::string root_path_;
std::string db_path_;
bool is_archive_;
std::shared_ptr<td::KeyValue> kv_;
RefIdHash last_gc_;
RefIdHash empty_ = RefIdHash::zero();
};
} // namespace validator
} // namespace ton

View file

@ -0,0 +1,108 @@
/*
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 "td/utils/port/path.h"
#include "td/utils/filesystem.h"
#include "td/actor/actor.h"
#include "td/utils/buffer.h"
#include "common/errorcode.h"
namespace ton {
namespace validator {
namespace db {
class WriteFile : public td::actor::Actor {
public:
void start_up() override {
auto R = [&]() {
td::uint32 cnt = 0;
while (true) {
cnt++;
auto res = td::mkstemp(td::CSlice{tmp_dir_});
if (res.is_ok() || cnt >= 10) {
return res;
}
}
}();
if (R.is_error()) {
promise_.set_error(R.move_as_error());
stop();
return;
}
auto res = R.move_as_ok();
auto file = std::move(res.first);
auto old_name = res.second;
size_t offset = 0;
while (data_.size() > 0) {
auto R = file.pwrite(data_.as_slice(), offset);
auto s = R.move_as_ok();
offset += s;
data_.confirm_read(s);
}
file.sync().ensure();
if (new_name_.length() > 0) {
td::rename(old_name, new_name_).ensure();
promise_.set_value(std::move(new_name_));
} else {
promise_.set_value(std::move(old_name));
}
stop();
}
WriteFile(std::string tmp_dir, std::string new_name, td::BufferSlice data, td::Promise<std::string> promise)
: tmp_dir_(tmp_dir), new_name_(new_name), data_(std::move(data)), promise_(std::move(promise)) {
}
private:
const std::string tmp_dir_;
std::string new_name_;
td::BufferSlice data_;
td::Promise<std::string> promise_;
};
class ReadFile : public td::actor::Actor {
public:
void start_up() override {
auto S = td::read_file(file_name_);
if (S.is_ok()) {
promise_.set_result(S.move_as_ok());
} else {
// TODO check error code
LOG(ERROR) << "missing file " << file_name_;
promise_.set_error(td::Status::Error(ErrorCode::notready, "file does not exist"));
}
stop();
}
ReadFile(std::string file_name, td::Promise<td::BufferSlice> promise)
: file_name_(file_name), promise_(std::move(promise)) {
}
private:
std::string file_name_;
td::Promise<td::BufferSlice> promise_;
};
} // namespace db
} // namespace validator
} // namespace ton

221
validator/db/ltdb.cpp Normal file
View file

@ -0,0 +1,221 @@
/*
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 "ltdb.hpp"
#include "rootdb.hpp"
#include "auto/tl/ton_api.h"
#include "ton/ton-tl.hpp"
#include "ton/ton-io.hpp"
#include "td/db/RocksDb.h"
namespace ton {
namespace validator {
void LtDb::add_new_block(BlockIdExt block_id, LogicalTime lt, UnixTime ts, td::Promise<td::Unit> promise) {
auto key = get_desc_key(block_id.shard_full());
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
tl_object_ptr<ton_api::db_lt_desc_value> v;
bool add_shard = false;
if (R.move_as_ok() == td::KeyValue::GetStatus::Ok) {
auto F = fetch_tl_object<ton_api::db_lt_desc_value>(td::BufferSlice{value}, true);
F.ensure();
v = F.move_as_ok();
} else {
v = create_tl_object<ton_api::db_lt_desc_value>(1, 1, 0, 0, 0);
add_shard = true;
}
if (block_id.id.seqno <= static_cast<td::uint32>(v->last_seqno_) || lt <= static_cast<LogicalTime>(v->last_lt_) ||
ts <= static_cast<UnixTime>(v->last_ts_)) {
promise.set_value(td::Unit());
return;
}
auto db_value = create_serialize_tl_object<ton_api::db_lt_el_value>(create_tl_block_id(block_id), lt, ts);
auto db_key = get_el_key(block_id.shard_full(), v->last_idx_++);
auto status_key = create_serialize_tl_object<ton_api::db_lt_status_key>();
v->last_seqno_ = block_id.id.seqno;
v->last_lt_ = lt;
v->last_ts_ = ts;
td::uint32 idx = 0;
if (add_shard) {
auto G = kv_->get(status_key.as_slice(), value);
G.ensure();
if (G.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
idx = 0;
} else {
auto F = fetch_tl_object<ton_api::db_lt_status_value>(value, true);
F.ensure();
auto f = F.move_as_ok();
idx = f->total_shards_;
}
}
kv_->begin_transaction().ensure();
kv_->set(key, serialize_tl_object(v, true)).ensure();
kv_->set(db_key, db_value.as_slice()).ensure();
if (add_shard) {
auto shard_key = create_serialize_tl_object<ton_api::db_lt_shard_key>(idx);
auto shard_value = create_serialize_tl_object<ton_api::db_lt_shard_value>(block_id.id.workchain, block_id.id.shard);
kv_->set(status_key.as_slice(), create_serialize_tl_object<ton_api::db_lt_status_value>(idx + 1)).ensure();
kv_->set(shard_key.as_slice(), shard_value.as_slice()).ensure();
}
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void LtDb::get_block_common(AccountIdPrefixFull account_id,
std::function<td::int32(ton_api::db_lt_desc_value &)> compare_desc,
std::function<td::int32(ton_api::db_lt_el_value &)> compare, bool exact,
td::Promise<BlockIdExt> promise) {
bool f = false;
BlockIdExt block_id;
td::uint32 ls = 0;
for (td::uint32 len = 0; len <= 60; len++) {
auto s = shard_prefix(account_id, len);
auto key = get_desc_key(s);
std::string value;
auto F = kv_->get(key, value);
F.ensure();
if (F.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
if (!f) {
continue;
} else {
break;
}
}
f = true;
auto G = fetch_tl_object<ton_api::db_lt_desc_value>(td::BufferSlice{value}, true);
G.ensure();
auto g = G.move_as_ok();
if (compare_desc(*g.get()) > 0) {
continue;
}
td::uint32 l = g->first_idx_ - 1;
BlockIdExt lseq;
td::uint32 r = g->last_idx_;
BlockIdExt rseq;
while (r - l > 1) {
auto x = (r + l) / 2;
auto db_key = get_el_key(s, x);
F = kv_->get(db_key, value);
F.ensure();
CHECK(F.move_as_ok() == td::KeyValue::GetStatus::Ok);
auto E = fetch_tl_object<ton_api::db_lt_el_value>(td::BufferSlice{value}, true);
E.ensure();
auto e = E.move_as_ok();
int cmp_val = compare(*e.get());
if (cmp_val < 0) {
rseq = create_block_id(e->id_);
r = x;
} else if (cmp_val > 0) {
lseq = create_block_id(e->id_);
l = x;
} else {
promise.set_value(create_block_id(e->id_));
return;
}
}
if (rseq.is_valid()) {
if (!block_id.is_valid()) {
block_id = rseq;
} else if (block_id.id.seqno > rseq.id.seqno) {
block_id = rseq;
}
}
if (lseq.is_valid()) {
if (ls < lseq.id.seqno) {
ls = lseq.id.seqno;
}
}
if (block_id.is_valid() && ls + 1 == block_id.id.seqno) {
if (!exact) {
promise.set_value(std::move(block_id));
} else {
promise.set_error(td::Status::Error(ErrorCode::notready, "ltdb: block not found"));
}
return;
}
}
if (!exact && block_id.is_valid()) {
promise.set_value(std::move(block_id));
} else {
promise.set_error(td::Status::Error(ErrorCode::notready, "ltdb: block not found"));
}
}
void LtDb::get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime lt, td::Promise<BlockIdExt> promise) {
return get_block_common(
account_id,
[lt](ton_api::db_lt_desc_value &w) {
return lt > static_cast<LogicalTime>(w.last_lt_) ? 1 : lt == static_cast<LogicalTime>(w.last_lt_) ? 0 : -1;
},
[lt](ton_api::db_lt_el_value &w) {
return lt > static_cast<LogicalTime>(w.lt_) ? 1 : lt == static_cast<LogicalTime>(w.lt_) ? 0 : -1;
},
false, std::move(promise));
}
void LtDb::get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise) {
return get_block_common(
account_id,
[seqno](ton_api::db_lt_desc_value &w) {
return seqno > static_cast<BlockSeqno>(w.last_seqno_)
? 1
: seqno == static_cast<BlockSeqno>(w.last_seqno_) ? 0 : -1;
},
[seqno](ton_api::db_lt_el_value &w) {
return seqno > static_cast<BlockSeqno>(w.id_->seqno_)
? 1
: seqno == static_cast<BlockSeqno>(w.id_->seqno_) ? 0 : -1;
},
true, std::move(promise));
}
void LtDb::get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise) {
return get_block_common(
account_id,
[ts](ton_api::db_lt_desc_value &w) {
return ts > static_cast<UnixTime>(w.last_ts_) ? 1 : ts == static_cast<UnixTime>(w.last_ts_) ? 0 : -1;
},
[ts](ton_api::db_lt_el_value &w) {
return ts > static_cast<UnixTime>(w.ts_) ? 1 : ts == static_cast<UnixTime>(w.ts_) ? 0 : -1;
},
false, std::move(promise));
}
td::BufferSlice LtDb::get_desc_key(ShardIdFull shard) {
return create_serialize_tl_object<ton_api::db_lt_desc_key>(shard.workchain, shard.shard);
}
td::BufferSlice LtDb::get_el_key(ShardIdFull shard, td::uint32 idx) {
return create_serialize_tl_object<ton_api::db_lt_el_key>(shard.workchain, shard.shard, idx);
}
void LtDb::start_up() {
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
}
} // namespace validator
} // namespace ton

63
validator/db/ltdb.hpp Normal file
View file

@ -0,0 +1,63 @@
/*
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 "td/actor/actor.h"
#include "td/db/KeyValueAsync.h"
#include "ton/ton-types.h"
#include "auto/tl/ton_api.h"
namespace ton {
namespace validator {
class RootDb;
class LtDb : public td::actor::Actor {
public:
void add_new_block(BlockIdExt block_id, LogicalTime lt, UnixTime ts, td::Promise<td::Unit> promise);
void get_block_common(AccountIdPrefixFull account_id,
std::function<td::int32(ton_api::db_lt_desc_value &)> compare_desc,
std::function<td::int32(ton_api::db_lt_el_value &)> compare, bool exact,
td::Promise<BlockIdExt> promise);
void get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime lt, td::Promise<BlockIdExt> promise);
void get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise);
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise);
void start_up() override;
LtDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(std::move(db_path)) {
}
private:
td::BufferSlice get_desc_key(ShardIdFull shard);
td::BufferSlice get_el_key(ShardIdFull shard, td::uint32 idx);
td::BufferSlice get_from_db(ShardIdFull shard, td::uint32 idx);
std::shared_ptr<td::KeyValue> kv_;
td::actor::ActorId<RootDb> root_db_;
std::string db_path_;
};
} // namespace validator
} // namespace ton

470
validator/db/rootdb.cpp Normal file
View file

@ -0,0 +1,470 @@
/*
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 "rootdb.hpp"
#include "validator/fabric.h"
#include "archiver.hpp"
#include "td/db/RocksDb.h"
#include "ton/ton-tl.hpp"
#include "td/utils/overloaded.h"
#include "common/checksum.h"
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()) {
promise.set_value(td::Unit());
return;
}
auto id = block_db_.get();
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
handle->set_received();
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
}
});
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::Block{handle->id()}}, block->data(),
std::move(P));
}
void RootDb::get_block_data(BlockHandle handle, td::Promise<td::Ref<BlockData>> promise) {
if (!handle->received()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
} else {
auto P = td::PromiseCreator::lambda(
[id = handle->id(), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_result(create_block(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::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()) {
promise.set_value(td::Unit());
return;
}
auto id = block_db_.get();
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
handle->set_signatures();
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
}
});
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::Signatures{handle->id()}},
data->serialize(), std::move(P));
}
void RootDb::get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockSignatureSet>> promise) {
if (!handle->inited_signatures()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
} else {
if (handle->moved_to_storage()) {
promise.set_error(td::Status::Error(ErrorCode::error, "signatures already gc'd"));
return;
}
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_result(create_signature_set(R.move_as_ok()));
}
});
td::actor::send_closure(file_db_, &FileDb::load_file, FileDb::RefId{fileref::Signatures{handle->id()}},
std::move(P));
}
}
void RootDb::store_block_proof(BlockHandle handle, td::Ref<Proof> proof, td::Promise<td::Unit> promise) {
if (handle->moved_to_storage()) {
promise.set_value(td::Unit());
return;
}
auto id = block_db_.get();
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
handle->set_proof();
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
}
});
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::Proof{handle->id()}}, proof->data(),
std::move(P));
}
void RootDb::get_block_proof(BlockHandle handle, td::Promise<td::Ref<Proof>> promise) {
if (!handle->inited_proof()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
} else {
auto P = td::PromiseCreator::lambda(
[id = handle->id(), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
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));
}
}
void RootDb::store_block_proof_link(BlockHandle handle, td::Ref<ProofLink> proof, td::Promise<td::Unit> promise) {
if (handle->moved_to_storage()) {
promise.set_value(td::Unit());
return;
}
auto id = block_db_.get();
auto P = td::PromiseCreator::lambda([id, handle, promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
handle->set_proof_link();
td::actor::send_closure(id, &BlockDb::store_block_handle, std::move(handle), std::move(promise));
}
});
td::actor::send_closure(file_db_, &FileDb::store_file, FileDb::RefId{fileref::ProofLink{handle->id()}}, proof->data(),
std::move(P));
}
void RootDb::get_block_proof_link(BlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) {
if (!handle->inited_proof_link()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
} else {
auto P = td::PromiseCreator::lambda(
[id = handle->id(), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
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));
}
}
void RootDb::store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) {
auto obj = create_serialize_tl_object<ton_api::db_candidate>(
PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}.tl(), create_tl_block_id(candidate.id),
std::move(candidate.data), std::move(candidate.collated_data));
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_value(td::Unit());
}
});
td::actor::send_closure(file_db_, &FileDb::store_file,
FileDb::RefId{fileref::Candidate{PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}},
candidate.id, candidate.collated_file_hash}},
std::move(obj), std::move(P));
}
void RootDb::get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) {
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
auto f = fetch_tl_object<ton_api::db_candidate>(R.move_as_ok(), true);
f.ensure();
auto val = f.move_as_ok();
auto hash = sha256_bits256(val->collated_data_);
auto key = ton::PublicKey{val->source_};
auto e_key = Ed25519_PublicKey{key.ed25519_value().raw()};
promise.set_value(BlockCandidate{e_key, create_block_id(val->id_), hash, std::move(val->data_),
std::move(val->collated_data_)});
}
});
td::actor::send_closure(file_db_, &FileDb::load_file,
FileDb::RefId{fileref::Candidate{source, id, collated_data_file_hash}}, std::move(P));
}
void RootDb::store_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) {
if (handle->moved_to_storage()) {
promise.set_value(std::move(state));
return;
}
if (!handle->inited_state_boc()) {
auto P = td::PromiseCreator::lambda([b = block_db_.get(), root_hash = state->root_hash(), handle,
promise = std::move(promise)](td::Result<td::Ref<vm::DataCell>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
handle->set_state_root_hash(root_hash);
handle->set_state_boc();
auto S = create_shard_state(handle->id(), R.move_as_ok());
S.ensure();
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), state = S.move_as_ok()](td::Result<td::Unit> R) mutable {
R.ensure();
promise.set_value(std::move(state));
});
td::actor::send_closure(b, &BlockDb::store_block_handle, std::move(handle), std::move(P));
}
});
td::actor::send_closure(cell_db_, &CellDb::store_cell, handle->id(), state->root_cell(), std::move(P));
} else {
get_block_state(handle, std::move(promise));
}
}
void RootDb::get_block_state(BlockHandle handle, td::Promise<td::Ref<ShardState>> promise) {
if (handle->inited_state_boc()) {
if (handle->deleted_state_boc()) {
promise.set_error(td::Status::Error(ErrorCode::error, "state already gc'd"));
return;
}
auto P =
td::PromiseCreator::lambda([handle, promise = std::move(promise)](td::Result<td::Ref<vm::DataCell>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
auto S = create_shard_state(handle->id(), R.move_as_ok());
S.ensure();
promise.set_value(S.move_as_ok());
}
});
td::actor::send_closure(cell_db_, &CellDb::load_cell, handle->state(), std::move(P));
} else {
promise.set_error(td::Status::Error(ErrorCode::notready, "state not in db"));
}
}
void RootDb::store_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::BufferSlice state,
td::Promise<td::Unit> promise) {
auto id = block_db_.get();
auto P = td::PromiseCreator::lambda([id, promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_value(td::Unit());
}
});
td::actor::send_closure(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,
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, 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,
FileDb::RefId{fileref::PersistentState{block_id, masterchain_block_id}}, std::move(promise));
}
void RootDb::store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) {
auto id = block_db_.get();
auto P = td::PromiseCreator::lambda([id, promise = std::move(promise)](td::Result<FileHash> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_value(td::Unit());
}
});
td::actor::send_closure(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}},
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}},
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));
}
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));
}
void RootDb::try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(static_files_db_, &StaticFilesDb::load_file, file_hash, std::move(promise));
}
void RootDb::apply_block(BlockHandle handle, td::Promise<td::Unit> promise) {
if (handle->id().id.seqno == 0) {
promise.set_value(td::Unit());
} else {
td::actor::send_closure(lt_db_, &LtDb::add_new_block, handle->id(), handle->logical_time(), handle->unix_time(),
std::move(promise));
}
}
void RootDb::get_block_by_lt(AccountIdPrefixFull account, LogicalTime lt, td::Promise<BlockIdExt> promise) {
td::actor::send_closure(lt_db_, &LtDb::get_block_by_lt, account, lt, std::move(promise));
}
void RootDb::get_block_by_unix_time(AccountIdPrefixFull account, UnixTime ts, td::Promise<BlockIdExt> promise) {
td::actor::send_closure(lt_db_, &LtDb::get_block_by_unix_time, account, ts, std::move(promise));
}
void RootDb::get_block_by_seqno(AccountIdPrefixFull account, BlockSeqno seqno, td::Promise<BlockIdExt> promise) {
td::actor::send_closure(lt_db_, &LtDb::get_block_by_seqno, account, seqno, std::move(promise));
}
void RootDb::update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::update_init_masterchain_block, block, std::move(promise));
}
void RootDb::get_init_masterchain_block(td::Promise<BlockIdExt> promise) {
td::actor::send_closure(state_db_, &StateDb::get_init_masterchain_block, std::move(promise));
}
void RootDb::update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::update_gc_masterchain_block, block, std::move(promise));
}
void RootDb::get_gc_masterchain_block(td::Promise<BlockIdExt> promise) {
td::actor::send_closure(state_db_, &StateDb::get_gc_masterchain_block, std::move(promise));
}
void RootDb::update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::update_shard_client_state, masterchain_block_id, std::move(promise));
}
void RootDb::get_shard_client_state(td::Promise<BlockIdExt> promise) {
td::actor::send_closure(state_db_, &StateDb::get_shard_client_state, std::move(promise));
}
void RootDb::update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::update_destroyed_validator_sessions, std::move(sessions),
std::move(promise));
}
void RootDb::get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) {
td::actor::send_closure(state_db_, &StateDb::get_destroyed_validator_sessions, std::move(promise));
}
void RootDb::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::update_async_serializer_state, std::move(state), std::move(promise));
}
void RootDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promise) {
td::actor::send_closure(state_db_, &StateDb::get_async_serializer_state, std::move(promise));
}
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/", false);
archive_db_ = td::actor::create_actor<FileDb>("filedbarchive", actor_id(this), root_path_ + "/archive/", 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/");
}
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))
.release();
}
void RootDb::allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise) {
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_state_gc, block_id, std::move(promise));
}
void RootDb::allow_block_gc(BlockIdExt block_id, td::Promise<bool> promise) {
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_info_gc, block_id, std::move(promise));
}
void RootDb::allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> promise) {
ref_id.visit(
td::overloaded([&](const fileref::Empty &key) { UNREACHABLE(); },
[&](const fileref::Block &key) {
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_data_gc, key.block_id,
is_archive, std::move(promise));
},
[&](const fileref::ZeroState &key) {
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_zero_state_file_gc,
key.block_id, std::move(promise));
},
[&](const fileref::PersistentState &key) {
CHECK(is_archive);
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_persistent_state_file_gc,
key.block_id, key.masterchain_block_id, std::move(promise));
},
[&](const fileref::Proof &key) {
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_proof_gc,
key.block_id, is_archive, std::move(promise));
},
[&](const fileref::ProofLink &key) {
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_proof_link_gc,
key.block_id, is_archive, std::move(promise));
},
[&](const fileref::Signatures &key) {
CHECK(!is_archive);
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_signatures_gc,
key.block_id, std::move(promise));
},
[&](const fileref::Candidate &key) {
CHECK(!is_archive);
td::actor::send_closure(validator_manager_, &ValidatorManager::allow_block_candidate_gc,
key.block_id, std::move(promise));
}));
}
} // namespace validator
} // namespace ton

127
validator/db/rootdb.hpp Normal file
View file

@ -0,0 +1,127 @@
/*
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 "td/actor/actor.h"
#include "td/db/KeyValueAsync.h"
#include "ton/ton-types.h"
#include "blockdb.hpp"
#include "celldb.hpp"
#include "filedb.hpp"
#include "ltdb.hpp"
#include "statedb.hpp"
#include "staticfilesdb.hpp"
namespace ton {
namespace validator {
class RootDb : public Db {
public:
enum class Flags : td::uint32 { f_started = 1, f_ready = 2, f_switched = 4, f_archived = 8 };
RootDb(td::actor::ActorId<ValidatorManager> validator_manager, std::string root_path)
: validator_manager_(validator_manager), root_path_(std::move(root_path)) {
}
void start_up() override;
void store_block_data(BlockHandle handle, td::Ref<BlockData> block, td::Promise<td::Unit> promise) override;
void get_block_data(BlockHandle handle, td::Promise<td::Ref<BlockData>> promise) override;
void store_block_signatures(BlockHandle handle, td::Ref<BlockSignatureSet> data,
td::Promise<td::Unit> promise) override;
void get_block_signatures(BlockHandle handle, td::Promise<td::Ref<BlockSignatureSet>> promise) override;
void store_block_proof(BlockHandle handle, td::Ref<Proof> proof, td::Promise<td::Unit> promise) override;
void get_block_proof(BlockHandle handle, td::Promise<td::Ref<Proof>> promise) override;
void store_block_proof_link(BlockHandle handle, td::Ref<ProofLink> proof, td::Promise<td::Unit> promise) override;
void get_block_proof_link(BlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override;
void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
void get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) override;
void store_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) override;
void get_block_state(BlockHandle handle, td::Promise<td::Ref<ShardState>> promise) override;
void store_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
void get_block_handle(BlockIdExt id, td::Promise<BlockHandle> promise) override;
void get_block_handle_external(BlockIdExt id, bool force, td::Promise<BlockHandle> promise) {
td::actor::send_closure(validator_manager_, &ValidatorManager::get_block_handle, id, force, std::move(promise));
}
void store_persistent_state_file(BlockIdExt block_id, BlockIdExt masterchain_block_id, td::BufferSlice state,
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 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;
void get_zero_state_file(BlockIdExt block_id, td::Promise<td::BufferSlice> promise) override;
void check_zero_state_file_exists(BlockIdExt block_id, td::Promise<bool> promise) override;
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
void apply_block(BlockHandle handle, td::Promise<td::Unit> promise) override;
void get_block_by_lt(AccountIdPrefixFull account, LogicalTime lt, td::Promise<BlockIdExt> promise) override;
void get_block_by_unix_time(AccountIdPrefixFull account, UnixTime ts, td::Promise<BlockIdExt> promise) override;
void get_block_by_seqno(AccountIdPrefixFull account, BlockSeqno seqno, td::Promise<BlockIdExt> promise) override;
void update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) override;
void get_init_masterchain_block(td::Promise<BlockIdExt> promise) override;
void update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) override;
void get_gc_masterchain_block(td::Promise<BlockIdExt> promise) override;
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(td::Promise<BlockIdExt> promise) override;
void update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
td::Promise<td::Unit> promise) override;
void get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) override;
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) override;
void allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise);
void allow_block_gc(BlockIdExt block_id, td::Promise<bool> promise);
void allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> promise);
private:
td::actor::ActorId<ValidatorManager> validator_manager_;
std::string root_path_;
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<LtDb> lt_db_;
td::actor::ActorOwn<StateDb> state_db_;
td::actor::ActorOwn<StaticFilesDb> static_files_db_;
};
} // namespace validator
} // namespace ton

191
validator/db/statedb.cpp Normal file
View file

@ -0,0 +1,191 @@
/*
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 "statedb.hpp"
#include "ton/ton-tl.hpp"
#include "adnl/utils.hpp"
#include "td/db/RocksDb.h"
#include "ton/ton-shard.h"
namespace ton {
namespace validator {
void StateDb::update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_initBlockId>();
kv_->begin_transaction().ensure();
kv_->set(key.as_slice(),
create_serialize_tl_object<ton_api::db_state_initBlockId>(create_tl_block_id(block)).as_slice())
.ensure();
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void StateDb::get_init_masterchain_block(td::Promise<BlockIdExt> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_initBlockId>();
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not found"));
return;
}
auto F = fetch_tl_object<ton_api::db_state_initBlockId>(td::BufferSlice{value}, true);
F.ensure();
auto obj = F.move_as_ok();
promise.set_value(create_block_id(obj->block_));
}
void StateDb::update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_gcBlockId>();
kv_->begin_transaction().ensure();
kv_->set(key.as_slice(),
create_serialize_tl_object<ton_api::db_state_gcBlockId>(create_tl_block_id(block)).as_slice())
.ensure();
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void StateDb::get_gc_masterchain_block(td::Promise<BlockIdExt> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_gcBlockId>();
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not found"));
return;
}
auto F = fetch_tl_object<ton_api::db_state_gcBlockId>(td::BufferSlice{value}, true);
F.ensure();
auto obj = F.move_as_ok();
promise.set_value(create_block_id(obj->block_));
}
void StateDb::update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_shardClient>();
kv_->begin_transaction().ensure();
kv_->set(key.as_slice(),
create_serialize_tl_object<ton_api::db_state_shardClient>(create_tl_block_id(masterchain_block_id)))
.ensure();
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void StateDb::get_shard_client_state(td::Promise<BlockIdExt> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_shardClient>();
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not found"));
return;
}
auto F = fetch_tl_object<ton_api::db_state_shardClient>(td::BufferSlice{value}, true);
F.ensure();
auto obj = F.move_as_ok();
promise.set_value(create_block_id(obj->block_));
}
void StateDb::update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions,
td::Promise<td::Unit> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_destroyedSessions>();
kv_->begin_transaction().ensure();
kv_->set(key.as_slice(), create_serialize_tl_object<ton_api::db_state_destroyedSessions>(std::move(sessions)))
.ensure();
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void StateDb::get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_destroyedSessions>();
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_value(std::vector<ValidatorSessionId>{});
return;
}
auto F = fetch_tl_object<ton_api::db_state_destroyedSessions>(td::BufferSlice{value}, true);
F.ensure();
auto obj = F.move_as_ok();
promise.set_value(std::move(obj->sessions_));
}
void StateDb::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_asyncSerializer>();
auto value = create_serialize_tl_object<ton_api::db_state_asyncSerializer>(
create_tl_block_id(state.last_block_id), create_tl_block_id(state.last_written_block_id),
state.last_written_block_ts);
kv_->begin_transaction().ensure();
kv_->set(key.as_slice(), value.as_slice()).ensure();
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
void StateDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_asyncSerializer>();
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_value(AsyncSerializerState{BlockIdExt{}, BlockIdExt{}, 0});
return;
}
auto F = fetch_tl_object<ton_api::db_state_asyncSerializer>(td::BufferSlice{value}, true);
F.ensure();
auto obj = F.move_as_ok();
promise.set_value(AsyncSerializerState{create_block_id(obj->block_), create_block_id(obj->last_),
static_cast<UnixTime>(obj->last_ts_)});
}
StateDb::StateDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
}
void StateDb::start_up() {
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
}
} // namespace validator
} // namespace ton

65
validator/db/statedb.hpp Normal file
View file

@ -0,0 +1,65 @@
/*
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 "td/actor/actor.h"
#include "td/db/KeyValueAsync.h"
#include "ton/ton-types.h"
#include "validator/interfaces/db.h"
namespace ton {
namespace validator {
class RootDb;
class StateDb : public td::actor::Actor {
public:
void update_init_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise);
void get_init_masterchain_block(td::Promise<BlockIdExt> promise);
void update_gc_masterchain_block(BlockIdExt block, td::Promise<td::Unit> promise);
void get_gc_masterchain_block(td::Promise<BlockIdExt> promise);
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise);
void get_shard_client_state(td::Promise<BlockIdExt> promise);
void update_destroyed_validator_sessions(std::vector<ValidatorSessionId> sessions, td::Promise<td::Unit> promise);
void get_destroyed_validator_sessions(td::Promise<std::vector<ValidatorSessionId>> promise);
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise);
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise);
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
void start_up() override;
private:
using KeyType = td::Bits256;
std::shared_ptr<td::KeyValue> kv_;
td::actor::ActorId<RootDb> root_db_;
std::string db_path_;
};
} // namespace validator
} // namespace ton

View file

@ -0,0 +1,33 @@
/*
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 "staticfilesdb.hpp"
#include "files-async.hpp"
namespace ton {
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();
}
} // namespace validator
} // namespace ton

View file

@ -0,0 +1,43 @@
/*
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 "ton/ton-types.h"
#include "td/actor/actor.h"
namespace ton {
namespace validator {
class RootDb;
class StaticFilesDb : public td::actor::Actor {
public:
void load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise);
StaticFilesDb(td::actor::ActorId<RootDb> root_db, std::string path) : root_db_(root_db), path_(path) {
}
private:
td::actor::ActorId<RootDb> root_db_;
std::string path_;
};
} // namespace validator
} // namespace ton