client: fix decode block number as u32 (#3130)

* client: fix panic on decode block number as u32

* client: add test for number_index_key

* client: add another test at client level

* client: address review grumbles
This commit is contained in:
André Silva
2019-07-18 15:55:14 +01:00
committed by GitHub
parent e8a2fee6d6
commit 991e9ae263
4 changed files with 81 additions and 45 deletions
+48 -22
View File
@@ -31,8 +31,8 @@ use parity_codec::Decode;
use trie::DBValue;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{
Block as BlockT, Header as HeaderT, Zero, UniqueSaturatedFrom,
UniqueSaturatedInto, CheckedConversion
Block as BlockT, Header as HeaderT, Zero,
UniqueSaturatedFrom, UniqueSaturatedInto,
};
#[cfg(feature = "kvdb-rocksdb")]
use crate::DatabaseSettings;
@@ -84,25 +84,31 @@ pub type NumberIndexKey = [u8; 4];
///
/// 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: TryInto<u32>>(n: N) -> NumberIndexKey {
let n = n.checked_into::<u32>().unwrap();
[
pub fn number_index_key<N: TryInto<u32>>(n: N) -> client::error::Result<NumberIndexKey> {
let n = n.try_into().map_err(|_|
client::error::Error::Backend("Block number cannot be converted to u32".into())
)?;
Ok([
(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<N, H>(number: N, hash: H) -> Vec<u8> where
pub fn number_and_hash_to_lookup_key<N, H>(
number: N,
hash: H,
) -> client::error::Result<Vec<u8>> where
N: TryInto<u32>,
H: AsRef<[u8]>
H: AsRef<[u8]>,
{
let mut lookup_key = number_index_key(number).to_vec();
let mut lookup_key = number_index_key(number)?.to_vec();
lookup_key.extend_from_slice(hash.as_ref());
lookup_key
Ok(lookup_key)
}
/// Convert block lookup key into block number.
@@ -124,8 +130,9 @@ pub fn remove_number_to_key_mapping<N: TryInto<u32>>(
transaction: &mut DBTransaction,
key_lookup_col: Option<u32>,
number: N,
) {
transaction.delete(key_lookup_col, number_index_key(number).as_ref())
) -> client::error::Result<()> {
transaction.delete(key_lookup_col, number_index_key(number)?.as_ref());
Ok(())
}
/// Remove key mappings.
@@ -134,9 +141,10 @@ pub fn remove_key_mappings<N: TryInto<u32>, H: AsRef<[u8]>>(
key_lookup_col: Option<u32>,
number: N,
hash: H,
) {
remove_number_to_key_mapping(transaction, key_lookup_col, number);
) -> client::error::Result<()> {
remove_number_to_key_mapping(transaction, key_lookup_col, number)?;
transaction.delete(key_lookup_col, hash.as_ref());
Ok(())
}
/// Place a number mapping into the database. This maps number to current perceived
@@ -146,12 +154,13 @@ pub fn insert_number_to_key_mapping<N: TryInto<u32> + Clone, H: AsRef<[u8]>>(
key_lookup_col: Option<u32>,
number: N,
hash: H,
) {
) -> client::error::Result<()> {
transaction.put_vec(
key_lookup_col,
number_index_key(number.clone()).as_ref(),
number_and_hash_to_lookup_key(number, hash),
)
number_index_key(number.clone())?.as_ref(),
number_and_hash_to_lookup_key(number, hash)?,
);
Ok(())
}
/// Insert a hash to key mapping in the database.
@@ -160,12 +169,13 @@ pub fn insert_hash_to_key_mapping<N: TryInto<u32>, H: AsRef<[u8]> + Clone>(
key_lookup_col: Option<u32>,
number: N,
hash: H,
) {
) -> client::error::Result<()> {
transaction.put_vec(
key_lookup_col,
hash.clone().as_ref(),
number_and_hash_to_lookup_key(number, hash),
)
number_and_hash_to_lookup_key(number, hash)?,
);
Ok(())
}
/// Convert block id to block lookup key.
@@ -182,7 +192,7 @@ pub fn block_id_to_lookup_key<Block>(
let res = match id {
BlockId::Number(n) => db.get(
key_lookup_col,
number_index_key(n).as_ref(),
number_index_key(n)?.as_ref(),
),
BlockId::Hash(h) => db.get(key_lookup_col, h.as_ref()),
};
@@ -318,3 +328,19 @@ pub fn read_meta<Block>(db: &dyn KeyValueDB, col_meta: Option<u32>, col_header:
genesis_hash,
})
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_primitives::testing::{Block as RawBlock, ExtrinsicWrapper};
type Block = RawBlock<ExtrinsicWrapper<u32>>;
#[test]
fn number_index_key_doesnt_panic() {
let id = BlockId::<Block>::Number(72340207214430721);
match id {
BlockId::Number(n) => number_index_key(n).expect_err("number should overflow u32"),
_ => unreachable!(),
};
}
}