1
0
mirror of https://github.com/danog/ton.git synced 2024-12-11 08:39:51 +01:00
ton/crypto/vm/cells/DataCell.h
2019-09-07 14:33:36 +04:00

213 lines
6.5 KiB
C++

/*
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 "vm/cells/Cell.h"
#include "td/utils/Span.h"
#include "td/utils/ThreadSafeCounter.h"
namespace vm {
class DataCell : public Cell {
public:
DataCell(const DataCell& other) = delete;
~DataCell() override;
static void store_depth(td::uint8* dest, td::uint16 depth) {
td::bitstring::bits_store_long(dest, depth, depth_bits);
}
static td::uint16 load_depth(const td::uint8* src) {
return td::bitstring::bits_load_ulong(src, depth_bits) & 0xff;
}
protected:
struct Info {
unsigned bits_;
// d1
unsigned char refs_count_ : 3;
bool is_special_ : 1;
unsigned char level_mask_ : 3;
unsigned char hash_count_ : 3;
unsigned char virtualization_ : 3;
unsigned char d1() const {
return d1(LevelMask{level_mask_});
}
unsigned char d1(LevelMask level_mask) const {
// d1 = refs_count + 8 * is_special + 32 * level
// + 16 * with_hashes - for seriazlization
// d1 = 7 + 16 + 32 * l - for absent cells
return static_cast<unsigned char>(refs_count_ + 8 * is_special_ + 32 * level_mask.get_mask());
}
unsigned char d2() const {
auto res = static_cast<unsigned char>((bits_ / 8) * 2);
if ((bits_ & 7) != 0) {
return static_cast<unsigned char>(res + 1);
}
return res;
}
size_t get_hashes_offset() const {
return 0;
}
size_t get_refs_offset() const {
return get_hashes_offset() + hash_bytes * hash_count_;
}
size_t get_depth_offset() const {
return get_refs_offset() + refs_count_ * sizeof(Cell*);
}
size_t get_data_offset() const {
return get_depth_offset() + sizeof(td::uint16) * hash_count_;
}
size_t get_storage_size() const {
return get_data_offset() + (bits_ + 7) / 8;
}
const Hash* get_hashes(const char* storage) const {
return reinterpret_cast<const Hash*>(storage + get_hashes_offset());
}
Hash* get_hashes(char* storage) const {
return reinterpret_cast<Hash*>(storage + get_hashes_offset());
}
const td::uint16* get_depth(const char* storage) const {
return reinterpret_cast<const td::uint16*>(storage + get_depth_offset());
}
td::uint16* get_depth(char* storage) const {
return reinterpret_cast<td::uint16*>(storage + get_depth_offset());
}
const unsigned char* get_data(const char* storage) const {
return reinterpret_cast<const unsigned char*>(storage + get_data_offset());
}
unsigned char* get_data(char* storage) const {
return reinterpret_cast<unsigned char*>(storage + get_data_offset());
}
Cell* const* get_refs(const char* storage) const {
return reinterpret_cast<Cell* const*>(storage + get_refs_offset());
}
Cell** get_refs(char* storage) const {
return reinterpret_cast<Cell**>(storage + get_refs_offset());
}
};
Info info_;
virtual char* get_storage() = 0;
virtual const char* get_storage() const = 0;
// TODO: we may also save three different pointers
void destroy_storage(char* storage);
explicit DataCell(Info info);
Cell* get_ref_raw_ptr(unsigned idx) const {
DCHECK(idx < get_refs_cnt());
return info_.get_refs(get_storage())[idx];
}
public:
td::Result<LoadedCell> load_cell() const override {
return LoadedCell{Ref<DataCell>{this}, {}, {}};
}
unsigned get_refs_cnt() const {
return info_.refs_count_;
}
unsigned get_bits() const {
return info_.bits_;
}
unsigned size_refs() const {
return info_.refs_count_;
}
unsigned size() const {
return info_.bits_;
}
const unsigned char* get_data() const {
return info_.get_data(get_storage());
}
Ref<Cell> get_ref(unsigned idx) const {
if (idx >= get_refs_cnt()) {
return Ref<Cell>{};
}
return Ref<Cell>(get_ref_raw_ptr(idx));
}
td::uint32 get_virtualization() const override {
return info_.virtualization_;
}
CellUsageTree::NodePtr get_tree_node() const override {
return {};
}
bool is_loaded() const override {
return true;
}
LevelMask get_level_mask() const override {
return LevelMask{info_.level_mask_};
}
bool is_special() const {
return info_.is_special_;
}
SpecialType special_type() const;
int get_serialized_size(bool with_hashes = false) const {
return ((get_bits() + 23) >> 3) +
(with_hashes ? get_level_mask().get_hashes_count() * (hash_bytes + depth_bytes) : 0);
}
int serialize(unsigned char* buff, int buff_size, bool with_hashes = false) const;
std::string serialize() const;
std::string to_hex() const;
static td::int64 get_total_data_cells() {
return get_thread_safe_counter().sum();
}
template <class StorerT>
void store(StorerT& storer) const {
storer.template store_binary<td::uint8>(info_.d1());
storer.template store_binary<td::uint8>(info_.d2());
storer.store_slice(td::Slice(get_data(), (get_bits() + 7) / 8));
}
protected:
static constexpr auto max_storage_size = max_refs * sizeof(void*) + (max_level + 1) * hash_bytes + max_bytes;
private:
static td::NamedThreadSafeCounter::CounterRef get_thread_safe_counter() {
static auto res = td::NamedThreadSafeCounter::get_default().get_counter("DataCell");
return res;
}
static std::unique_ptr<DataCell> create_empty_data_cell(Info info);
const Hash do_get_hash(td::uint32 level) const override;
td::uint16 do_get_depth(td::uint32 level) const override;
friend class CellBuilder;
static td::Result<Ref<DataCell>> create(td::ConstBitPtr data, unsigned bits, td::Span<Ref<Cell>> refs, bool special);
static td::Result<Ref<DataCell>> create(td::ConstBitPtr data, unsigned bits, td::MutableSpan<Ref<Cell>> refs,
bool special);
};
std::ostream& operator<<(std::ostream& os, const DataCell& c);
} // namespace vm