Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Kouprin committed May 21, 2020
1 parent ad79d8d commit b500daf
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 92 deletions.
2 changes: 2 additions & 0 deletions pytest/lib/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ def check_refmap(self):
self.kill()

def check_store(self):
# TODO #2597 enable
return
if self.is_check_store:
res = self.json_rpc('adv_check_store', [])
if not 'result' in res:
Expand Down
10 changes: 8 additions & 2 deletions test-utils/store-validator-bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::Path;
use std::process;
use std::sync::Arc;

use ansi_term::Color::{Green, Red};
use ansi_term::Color::{Green, Red, White, Yellow};
use clap::{App, Arg, SubCommand};

use near_chain::RuntimeAdapter;
Expand Down Expand Up @@ -55,7 +55,13 @@ fn main() {
Green.bold().paint(store_validator.tests_done().to_string())
);
for error in store_validator.errors.iter() {
println!("{}: {}", Red.bold().paint(&error.col.to_string()), error.msg);
println!(
"{} > {} > {} > {}",
Red.bold().paint(&error.func.to_string()),
Yellow.bold().paint(&error.col.unwrap().to_string()),
White.bold().paint(error.key.as_ref().unwrap()),
error.reason
);
}
if store_validator.is_failed() {
println!("Errors found: {}", Red.bold().paint(store_validator.num_failed().to_string()));
Expand Down
34 changes: 28 additions & 6 deletions test-utils/store-validator/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
use std::convert::TryFrom;
use std::sync::Arc;

use borsh::BorshDeserialize;

use near_chain_configs::GenesisConfig;
use near_primitives::borsh;
use near_primitives::hash::CryptoHash;
use near_primitives::sharding::ChunkHash;
use near_store::{DBCol, ShardTries, Store};

mod validate;

#[derive(Debug)]
pub struct ErrorMessage {
pub col: DBCol,
pub msg: String,
pub col: Option<DBCol>,
pub key: Option<String>,
pub func: String,
pub reason: String,
}

impl ErrorMessage {
fn new(col: DBCol, msg: String) -> Self {
Self { col, msg }
fn new(func: String, reason: String) -> Self {
Self { col: None, key: None, func, reason }
}
}

Expand Down Expand Up @@ -45,6 +53,15 @@ impl StoreValidator {
pub fn tests_done(&self) -> u64 {
self.tests
}
fn col_to_key(col: DBCol, key: &[u8]) -> String {
match col {
DBCol::ColBlockHeader | DBCol::ColBlock => {
format!("{:?}", CryptoHash::try_from(key.as_ref()))
}
DBCol::ColChunks => format!("{:?}", ChunkHash::try_from_slice(key.as_ref())),
_ => format!("{:?}", key),
}
}
pub fn validate(&mut self) {
self.check(&validate::nothing, &[0], &[0], DBCol::ColBlockMisc);
for (key, value) in self.store.clone().iter(DBCol::ColBlockHeader) {
Expand Down Expand Up @@ -75,7 +92,7 @@ impl StoreValidator {

fn check(
&mut self,
f: &dyn Fn(&StoreValidator, &[u8], &[u8]) -> Result<(), String>,
f: &dyn Fn(&StoreValidator, &[u8], &[u8]) -> Result<(), ErrorMessage>,
key: &[u8],
value: &[u8],
col: DBCol,
Expand All @@ -84,7 +101,12 @@ impl StoreValidator {
self.tests += 1;
match result {
Ok(_) => {}
Err(msg) => self.errors.push(ErrorMessage::new(col, msg)),
Err(e) => {
let mut e = e;
e.col = Some(col);
e.key = Some(Self::col_to_key(col, key));
self.errors.push(e)
}
}
}
}
169 changes: 85 additions & 84 deletions test-utils/store-validator/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use near_store::{
WrappedTrieChanges, TAIL_KEY,
};

use crate::StoreValidator;
use crate::{ErrorMessage, StoreValidator};

macro_rules! get_parent_function_name {
() => {{
Expand All @@ -30,26 +30,34 @@ macro_rules! get_parent_function_name {
std::any::type_name::<T>()
}
let name = type_name_of(f);
&name[..name.len() - 3]
(&name[..name.len() - 3].split("::").last().unwrap()).to_string()
}};
}

macro_rules! err(($x:expr) => (Err(format!("{}: {}", get_parent_function_name!(), $x))));
macro_rules! err {
($($x: tt),*) => (
Err(ErrorMessage::new(get_parent_function_name!(), format!($($x),*)))
)
}

macro_rules! unwrap_or_err {
($obj: expr, $ret: expr) => {
($obj: expr, $($x: tt),*) => {
match $obj {
Ok(value) => value,
Err(err) => {
return err!(err);
Err(e) => {
return Err(ErrorMessage::new(get_parent_function_name!(), format!("{}, error: {}", format!($($x),*), e)))
}
}
};
}

// All validations start here

pub(crate) fn nothing(_sv: &StoreValidator, _key: &[u8], _value: &[u8]) -> Result<(), String> {
pub(crate) fn nothing(
_sv: &StoreValidator,
_key: &[u8],
_value: &[u8],
) -> Result<(), ErrorMessage> {
// Make sure that validation is executed
Ok(())
}
Expand All @@ -58,85 +66,82 @@ pub(crate) fn block_header_validity(
_sv: &StoreValidator,
key: &[u8],
value: &[u8],
) -> Result<(), String> {
let block_hash = CryptoHash::try_from(key.as_ref()).unwrap();
match BlockHeader::try_from_slice(value) {
Ok(header) => {
if header.hash() != block_hash {
err!(format!("Invalid Block Header hash stored, {:?}", block_hash))
} else {
Ok(())
}
}
Err(e) => err!(format!("Can't get Block Header from storage, {:?}, {:?}", block_hash, e)),
) -> Result<(), ErrorMessage> {
let block_hash =
unwrap_or_err!(CryptoHash::try_from(key.as_ref()), "Can't deserialize Block Hash");
let header =
unwrap_or_err!(BlockHeader::try_from_slice(value), "Can't deserialize Block Header");
if header.hash() != block_hash {
return err!("Invalid Block Header stored, hash = {:?}, header = {:?}", block_hash, header);
}
Ok(())
}

pub(crate) fn block_hash_validity(
_sv: &StoreValidator,
key: &[u8],
value: &[u8],
) -> Result<(), String> {
let block_hash = CryptoHash::try_from(key.as_ref()).unwrap();
match Block::try_from_slice(value) {
Ok(block) => {
if block.hash() != block_hash {
err!(format!("Invalid Block hash stored, {:?}", block_hash))
} else {
Ok(())
}
}
Err(e) => err!(format!("Can't get Block Header from storage, {:?}, {:?}", block_hash, e)),
) -> Result<(), ErrorMessage> {
let block_hash =
unwrap_or_err!(CryptoHash::try_from(key.as_ref()), "Can't deserialize Block Hash");
let block = unwrap_or_err!(Block::try_from_slice(value), "Can't deserialize Block");
if block.hash() != block_hash {
return err!("Invalid Block stored, hash = {:?}, block = {:?}", block_hash, block);
}
Ok(())
}

pub(crate) fn block_header_exists(
sv: &StoreValidator,
key: &[u8],
_value: &[u8],
) -> Result<(), String> {
let block_hash = CryptoHash::try_from(key.as_ref()).unwrap();
match sv.store.get_ser::<BlockHeader>(ColBlockHeader, block_hash.as_ref()) {
Ok(Some(_header)) => Ok(()),
Ok(None) => err!(format!("Block Header not found, {:?}", block_hash)),
Err(e) => err!(format!("Can't get Block Header from storage, {:?}, {:?}", block_hash, e)),
) -> Result<(), ErrorMessage> {
let block_hash =
unwrap_or_err!(CryptoHash::try_from(key.as_ref()), "Can't deserialize Block Hash");
let header = unwrap_or_err!(
sv.store.get_ser::<BlockHeader>(ColBlockHeader, block_hash.as_ref()),
"Can't get Block Header from storage"
);
match header {
Some(_) => Ok(()),
None => err!("Block Header not found"),
}
}

pub(crate) fn chunk_hash_validity(
_sv: &StoreValidator,
key: &[u8],
value: &[u8],
) -> Result<(), String> {
let chunk_hash = ChunkHash::try_from_slice(key.as_ref()).unwrap();
match ShardChunk::try_from_slice(value) {
Ok(shard_chunk) => {
if shard_chunk.chunk_hash != chunk_hash {
err!(format!("Invalid ShardChunk hash stored, {:?}", chunk_hash))
} else {
Ok(())
}
}
Err(e) => err!(format!("Can't get ShardChunk from storage, {:?}, {:?}", chunk_hash, e)),
) -> Result<(), ErrorMessage> {
let chunk_hash =
unwrap_or_err!(ChunkHash::try_from_slice(key.as_ref()), "Can't deserialize Chunk Hash");
let shard_chunk =
unwrap_or_err!(ShardChunk::try_from_slice(value), "Can't deserialize ShardChunk");
if shard_chunk.chunk_hash != chunk_hash {
return err!("Invalid ShardChunk stored");
}
Ok(())
}

pub(crate) fn block_of_chunk_exists(
sv: &StoreValidator,
_key: &[u8],
value: &[u8],
) -> Result<(), String> {
) -> Result<(), ErrorMessage> {
let shard_chunk =
unwrap_or_err!(ShardChunk::try_from_slice(value), "Can't deserialize ShardChunk");
let height = shard_chunk.header.height_included;
if height == sv.config.genesis_height {
return Ok(());
}
match sv.store.get_ser::<HashMap<EpochId, HashSet<CryptoHash>>>(
ColBlockPerHeight,
&index_to_bytes(height),
) {
Ok(Some(map)) => {
let map = unwrap_or_err!(
sv.store.get_ser::<HashMap<EpochId, HashSet<CryptoHash>>>(
ColBlockPerHeight,
&index_to_bytes(height),
),
"Can't get Map from storage on height {:?}, no one is responsible for ShardChunk {:?}",
height,
shard_chunk
);
match map {
Some(map) => {
for (_, set) in map {
for block_hash in set {
match sv.store.get_ser::<Block>(ColBlock, block_hash.as_ref()) {
Expand All @@ -150,56 +155,52 @@ pub(crate) fn block_of_chunk_exists(
}
}
}
err!(format!("No Block on height {:?} accepts ShardChunk {:?}", height, shard_chunk))
err!("No Block on height {:?} accepts ShardChunk {:?}", height, shard_chunk)
}
Ok(None) => err!(format!("Map not found on height {:?}, no one is responsible for ShardChunk {:?}", height, shard_chunk)),
Err(e) => err!(format!("Can't get Map from storage on height {:?}, no one is responsible for ShardChunk {:?}, {:?}", height, shard_chunk, e)),
None => err!(
"Map is empty on height {:?}, no one is responsible for ShardChunk {:?}",
height,
shard_chunk
),
}
}

pub(crate) fn block_height_cmp_tail(
sv: &StoreValidator,
key: &[u8],
_key: &[u8],
value: &[u8],
) -> Result<(), String> {
let block_hash = CryptoHash::try_from(key.as_ref()).unwrap();
let tail = match sv.store.get_ser::<BlockHeight>(ColBlockMisc, TAIL_KEY) {
Ok(Some(tail)) => tail,
Ok(None) => sv.config.genesis_height,
Err(_) => return err!("Can't get Tail from storage"),
};
match Block::try_from_slice(value) {
Ok(block) => {
if block.header.inner_lite.height < tail
&& block.header.inner_lite.height != sv.config.genesis_height
{
err!(format!(
"Invalid block height stored: {:?}, tail: {:?}",
block.header.inner_lite.height, tail
))
} else {
Ok(())
}
}
Err(e) => {
err!(format!("Can't get Block from storage, {:?}, {:?}", block_hash.to_string(), e))
}
) -> Result<(), ErrorMessage> {
let tail = unwrap_or_err!(
sv.store.get_ser::<BlockHeight>(ColBlockMisc, TAIL_KEY),
"Can't get Tail from storage"
)
.unwrap_or(sv.config.genesis_height);
let block = unwrap_or_err!(Block::try_from_slice(value), "Can't deserialize Block");
if block.header.inner_lite.height < tail
&& block.header.inner_lite.height != sv.config.genesis_height
{
return err!(
"Invalid block height stored: {}, tail: {:?}",
(block.header.inner_lite.height),
tail
);
}
Ok(())
}

pub(crate) fn chunks_state_roots_in_trie(
sv: &StoreValidator,
_key: &[u8],
value: &[u8],
) -> Result<(), String> {
) -> Result<(), ErrorMessage> {
let shard_chunk: ShardChunk =
unwrap_or_err!(ShardChunk::try_from_slice(value), "Can't deserialize ShardChunk");
let shard_id = shard_chunk.header.inner.shard_id;
let state_root = shard_chunk.header.inner.prev_state_root;
let trie = sv.shard_tries.get_trie_for_shard(shard_id);
let trie = TrieIterator::new(&trie, &state_root).unwrap();
for item in trie {
unwrap_or_err!(item, format!("Can't find ShardChunk {} in Trie", shard_chunk));
unwrap_or_err!(item, "Can't find ShardChunk {:?} in Trie", shard_chunk);
}
Ok(())
}

0 comments on commit b500daf

Please sign in to comment.