mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
147
validator/db/archiver.cpp
Normal file
147
validator/db/archiver.cpp
Normal 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
62
validator/db/archiver.hpp
Normal 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
234
validator/db/blockdb.cpp
Normal 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
86
validator/db/blockdb.hpp
Normal 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
283
validator/db/celldb.cpp
Normal 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
117
validator/db/celldb.hpp
Normal 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
333
validator/db/filedb.cpp
Normal 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
202
validator/db/filedb.hpp
Normal 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
|
||||
|
108
validator/db/files-async.hpp
Normal file
108
validator/db/files-async.hpp
Normal 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
221
validator/db/ltdb.cpp
Normal 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
63
validator/db/ltdb.hpp
Normal 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
470
validator/db/rootdb.cpp
Normal 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
127
validator/db/rootdb.hpp
Normal 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
191
validator/db/statedb.cpp
Normal 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
65
validator/db/statedb.hpp
Normal 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
|
33
validator/db/staticfilesdb.cpp
Normal file
33
validator/db/staticfilesdb.cpp
Normal 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
|
43
validator/db/staticfilesdb.hpp
Normal file
43
validator/db/staticfilesdb.hpp
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue