// Copyright 2017-2018 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! Db-based backend utility structures and functions, used by both
//! full and light storages.
use std::sync::Arc;
use std::io;
use kvdb::{KeyValueDB, DBTransaction};
use kvdb_rocksdb::{Database, DatabaseConfig};
use client;
use codec::Decode;
use trie::DBValue;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, Zero};
use DatabaseSettings;
/// Number of columns in the db. Must be the same for both full && light dbs.
/// Otherwise RocksDb will fail to open database && check its type.
pub const NUM_COLUMNS: u32 = 9;
/// Meta column. The set of keys in the column is shared by full && light storages.
pub const COLUMN_META: Option = Some(0);
/// Keys of entries in COLUMN_META.
pub mod meta_keys {
/// Type of storage (full or light).
pub const TYPE: &[u8; 4] = b"type";
/// Best block key.
pub const BEST_BLOCK: &[u8; 4] = b"best";
/// Last finalized block key.
pub const FINALIZED_BLOCK: &[u8; 5] = b"final";
/// Meta information prefix for list-based caches.
pub const CACHE_META_PREFIX: &[u8; 5] = b"cache";
/// Genesis block hash.
pub const GENESIS_HASH: &[u8; 3] = b"gen";
/// Leaves prefix list key.
pub const LEAF_PREFIX: &[u8; 4] = b"leaf";
}
/// Database metadata.
#[derive(Debug)]
pub struct Meta {
/// Hash of the best known block.
pub best_hash: H,
/// Number of the best known block.
pub best_number: N,
/// Hash of the best finalized block.
pub finalized_hash: H,
/// Number of the best finalized block.
pub finalized_number: N,
/// Hash of the genesis block.
pub genesis_hash: H,
}
/// A block lookup key: used for canonical lookup from block number to hash
pub type NumberIndexKey = [u8; 4];
/// 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.
pub fn number_index_key(n: N) -> NumberIndexKey where N: As {
let n: u64 = n.as_();
assert!(n & 0xffffffff00000000 == 0);
[
(n >> 24) as u8,
((n >> 16) & 0xff) as u8,
((n >> 8) & 0xff) as u8,
(n & 0xff) as u8
]
}
/// Convert number and hash into long lookup key for blocks that are
/// not in the canonical chain.
pub fn number_and_hash_to_lookup_key(number: N, hash: H) -> Vec where
N: As,
H: AsRef<[u8]>
{
let mut lookup_key = number_index_key(number).to_vec();
lookup_key.extend_from_slice(hash.as_ref());
lookup_key
}
/// Convert block lookup key into block number.
/// all block lookup keys start with the block number.
pub fn lookup_key_to_number(key: &[u8]) -> client::error::Result where N: As {
if key.len() < 4 {
return Err(client::error::ErrorKind::Backend("Invalid block key".into()).into());
}
Ok((key[0] as u64) << 24
| (key[1] as u64) << 16
| (key[2] as u64) << 8
| (key[3] as u64)).map(As::sa)
}
/// Delete number to hash mapping in DB transaction.
pub fn remove_number_to_key_mapping>(
transaction: &mut DBTransaction,
key_lookup_col: Option,
number: N,
) {
transaction.delete(key_lookup_col, number_index_key(number).as_ref())
}
/// Remove key mappings.
pub fn remove_key_mappings, H: AsRef<[u8]>>(
transaction: &mut DBTransaction,
key_lookup_col: Option,
number: N,
hash: H,
) {
remove_number_to_key_mapping(transaction, key_lookup_col, number);
transaction.delete(key_lookup_col, hash.as_ref());
}
/// Place a number mapping into the database. This maps number to current perceived
/// block hash at that position.
pub fn insert_number_to_key_mapping + Clone, H: AsRef<[u8]>>(
transaction: &mut DBTransaction,
key_lookup_col: Option,
number: N,
hash: H,
) {
transaction.put_vec(
key_lookup_col,
number_index_key(number.clone()).as_ref(),
number_and_hash_to_lookup_key(number, hash),
)
}
/// Insert a hash to key mapping in the database.
pub fn insert_hash_to_key_mapping, H: AsRef<[u8]> + Clone>(
transaction: &mut DBTransaction,
key_lookup_col: Option,
number: N,
hash: H,
) {
transaction.put_vec(
key_lookup_col,
hash.clone().as_ref(),
number_and_hash_to_lookup_key(number, hash),
)
}
/// Convert block id to block lookup key.
/// block lookup key is the DB-key header, block and justification are stored under.
/// looks up lookup key by hash from DB as necessary.
pub fn block_id_to_lookup_key(
db: &KeyValueDB,
key_lookup_col: Option,
id: BlockId
) -> Result