src/blockchain/impl/storage_util.cpp¶
Namespaces¶
| Name |
|---|
| sgns |
| sgns::blockchain |
Types¶
| Name | |
|---|---|
| enum | Prefix { } |
| using Blob< 32 > | Hash256 |
| using boost::variant< BlockHash, BlockNumber > | BlockId Block id is the variant over BlockHash and BlockNumber. |
| using uint64_t | BlockNumber |
Functions¶
| Name | |
|---|---|
| OUTCOME_CPP_DEFINE_CATEGORY_3(sgns::blockchain , KeyValueRepositoryError , e ) | |
| outcome::result< void > | putWithPrefix(crdt::GlobalDB & db, prefix::Prefix prefix, primitives::BlockNumber num, base::Hash256 block_hash, const base::Buffer & value) |
| outcome::result< base::Buffer > | getWithPrefix(crdt::GlobalDB & db, prefix::Prefix prefix, const primitives::BlockId & block_id) |
| base::Buffer | NumberToBuffer(primitives::BlockNumber n) |
| base::Buffer | numberAndHashToLookupKey(primitives::BlockNumber number, const base::Hash256 & hash) |
| outcome::result< primitives::BlockNumber > | BufferToNumber(const base::Buffer & key) |
| base::Buffer | prependPrefix(const base::Buffer & key, prefix::Prefix key_column) |
| bool | isNotFoundError(outcome::result< void > result) |
Types Documentation¶
enum Prefix¶
| Enumerator | Value | Description |
|---|---|---|
using Hash256¶
using BlockId¶
Block id is the variant over BlockHash and BlockNumber.
using BlockNumber¶
Functions Documentation¶
function OUTCOME_CPP_DEFINE_CATEGORY_3¶
function putWithPrefix¶
outcome::result< void > putWithPrefix(
crdt::GlobalDB & db,
prefix::Prefix prefix,
primitives::BlockNumber num,
base::Hash256 block_hash,
const base::Buffer & value
)
Parameters:
- db database to put the entry to
- prefix keyspace for the entry value
- num block number that could be used to retrieve the value
- block_hash block hash that could be used to retrieve the value
- value data to be put to the storage
Return: storage error if any
Put an entry to key space prefix and corresponding lookup keys to ID_TO_LOOKUP_KEY space.
function getWithPrefix¶
outcome::result< base::Buffer > getWithPrefix(
crdt::GlobalDB & db,
prefix::Prefix prefix,
const primitives::BlockId & block_id
)
Parameters:
- db database to get the entry from
- prefix prefix with which the entry was put into
- block_id id of the block to get entry for
Return: encoded entry or error
Get an entry from the database.
function NumberToBuffer¶
Convert block number into short lookup key (LE representation) for blocks that are in the canonical chain.
In the current database schema, this kind of key is only used for lookups into an index, NOT for storing header data or others.
base::Buffer retval;
Little endian for ( std::size_t i = 0; i < sizeof(primitives::BlockNumber); ++i ) { retval.putUint8(static_cast
function numberAndHashToLookupKey¶
Convert number and hash into long lookup key for blocks that are not in the canonical chain.
function BufferToNumber¶
Converts buffer data to a block number
function prependPrefix¶
Parameters:
- key key buffer
- key_column prefix keyspace
Return: key_column|key
Concatenate prefix with key.
function isNotFoundError¶
For a persistant map based storage checks whether result should be considered as NOT FOUND error
Source code¶
#include "blockchain/impl/storage_util.hpp"
#include "blockchain/impl/common.hpp"
#include "storage/database_error.hpp"
#include "crdt/globaldb/globaldb.hpp"
#include "blockchain/impl/proto/SGBlocks.pb.h"
using sgns::blockchain::prefix::Prefix;
using sgns::base::Buffer;
using sgns::base::Hash256;
using sgns::primitives::BlockId;
using sgns::primitives::BlockNumber;
OUTCOME_CPP_DEFINE_CATEGORY_3(sgns::blockchain, KeyValueRepositoryError, e) {
using E = sgns::blockchain::KeyValueRepositoryError;
switch (e) {
case E::INVALID_KEY:
return "Invalid storage key";
}
return "Unknown error";
}
namespace sgns::blockchain {
outcome::result<void> putWithPrefix(crdt::GlobalDB &db,
prefix::Prefix prefix,
BlockNumber num,
Hash256 block_hash,
const base::Buffer &value) {
auto block_lookup_key = numberAndHashToLookupKey(num, block_hash);
auto value_lookup_key = prependPrefix(block_lookup_key, prefix);
auto num_to_idx_key =
prependPrefix(NumberToBuffer(num), Prefix::ID_TO_LOOKUP_KEY);
auto hash_to_idx_key =
prependPrefix(Buffer{block_hash}, Prefix::ID_TO_LOOKUP_KEY);
BOOST_OUTCOME_TRYV2(auto &&, db.Put( { "num_to_idx_key" }, block_lookup_key, { "topic" } ) );
BOOST_OUTCOME_TRYV2(auto &&, db.Put( { "hash_to_idx_key" }, block_lookup_key, { "topic" } ) );
OUTCOME_TRY(db.Put( { "value_lookup_key" }, value, { "topic" } ) );
return outcome::success();
}
outcome::result<base::Buffer> getWithPrefix(
crdt::GlobalDB &db,
prefix::Prefix prefix,
const primitives::BlockId &block_id) {
OUTCOME_TRY((auto &&, key), idToBufferKey(db, block_id));
return db.Get({"prependPrefix(key, prefix)"});
}
base::Buffer NumberToBuffer(primitives::BlockNumber n) {
// TODO(Harrm) Figure out why exactly it is this way in substrate
//BOOST_ASSERT((n & 0xffffffff00000000) == 0);
SGBlocks::BlockID blockID;
blockID.set_block_number(n);
size_t size = blockID.ByteSizeLong();
std::vector<uint8_t> serialized_proto( size );
blockID.SerializeToArray( serialized_proto.data(), static_cast<int>(serialized_proto.size()) );
return base::Buffer{serialized_proto};
//return {uint8_t(n >> 24u),
// uint8_t((n >> 16u) & 0xffu),
// uint8_t((n >> 8u) & 0xffu),
// uint8_t(n & 0xffu)};
}
base::Buffer numberAndHashToLookupKey(primitives::BlockNumber number,
const base::Hash256 &hash) {
auto lookup_key = NumberToBuffer(number);
lookup_key.put(hash);
return lookup_key;
}
outcome::result<primitives::BlockNumber> BufferToNumber(
const base::Buffer &key) {
if (key.size() > sizeof(primitives::BlockNumber)) {
return outcome::failure(KeyValueRepositoryError::INVALID_KEY);
}
SGBlocks::BlockID blockID;
if ( !blockID.ParseFromArray( key.toVector().data(), static_cast<int>(key.toVector().size()) ) )
{
std::cerr << "Failed to parse BlockID from array." << std::endl;
}
return blockID.block_number();
/*primitives::BlockNumber retval = 0;
//Little endian
for ( std::size_t i = 0; i < key.size(); ++i )
{
retval += (key[i] << (i * 8));
}
return retval;*/
//return (uint64_t(key[0]) << 24u) | (uint64_t(key[1]) << 16u)
// | (uint64_t(key[2]) << 8u) | uint64_t(key[3]);
}
base::Buffer prependPrefix(const base::Buffer &key,
prefix::Prefix key_column) {
return base::Buffer{}
.reserve(key.size() + 1)
.putUint8(key_column)
.put(key);
}
bool isNotFoundError(outcome::result<void> result) {
if (result) {
return false;
}
return (result.error() == storage::DatabaseError::NOT_FOUND);
}
} // namespace sgns::blockchain
Updated on 2026-03-04 at 13:10:44 -0800