use bytes::Bytes; use hash::H256; use ser::{deserialize, serialize, List}; use zebra_chain::{BlockHeader, Transaction as ChainTransaction}; use zebra_storage::{EpochRef, EpochTag, SaplingTreeState, SproutTreeState, TransactionMeta}; pub const COL_COUNT: u32 = 16; pub const COL_META: u32 = 0; pub const COL_BLOCK_HASHES: u32 = 1; pub const COL_BLOCK_HEADERS: u32 = 2; pub const COL_BLOCK_TRANSACTIONS: u32 = 3; pub const COL_TRANSACTIONS: u32 = 4; pub const COL_TRANSACTIONS_META: u32 = 5; pub const COL_BLOCK_NUMBERS: u32 = 6; pub const COL_SPROUT_NULLIFIERS: u32 = 7; pub const COL_SAPLING_NULLIFIERS: u32 = 8; pub const COL_SPROUT_BLOCK_ROOTS: u32 = 9; pub const COL_TREE_STATES: u32 = 10; pub const COL_CONFIGURATION: u32 = 11; #[derive(Debug)] pub enum Operation { Insert(KeyValue), Delete(Key), } #[derive(Debug)] pub enum KeyValue { Meta(&'static str, Bytes), BlockHash(u32, H256), BlockHeader(H256, BlockHeader), BlockTransactions(H256, List), Transaction(H256, ChainTransaction), TransactionMeta(H256, TransactionMeta), BlockNumber(H256, u32), Configuration(&'static str, Bytes), Nullifier(EpochRef), SproutTreeState(H256, SproutTreeState), SaplingTreeState(H256, SaplingTreeState), SproutBlockRoot(H256, H256), } #[derive(Debug)] pub enum Key { Meta(&'static str), BlockHash(u32), BlockHeader(H256), BlockTransactions(H256), Transaction(H256), TransactionMeta(H256), BlockNumber(H256), Configuration(&'static str), Nullifier(EpochRef), TreeRoot(EpochRef), SproutBlockRoot(H256), } #[derive(Debug, Clone)] pub enum Value { Meta(Bytes), BlockHash(H256), BlockHeader(BlockHeader), BlockTransactions(List), Transaction(ChainTransaction), TransactionMeta(TransactionMeta), BlockNumber(u32), Configuration(Bytes), Empty, SproutTreeState(SproutTreeState), SaplingTreeState(SaplingTreeState), SproutTreeRoot(H256), } impl Value { pub fn for_key(key: &Key, bytes: &[u8]) -> Result { match *key { Key::Meta(_) => deserialize(bytes).map(Value::Meta), Key::BlockHash(_) => deserialize(bytes).map(Value::BlockHash), Key::BlockHeader(_) => deserialize(bytes).map(Value::BlockHeader), Key::BlockTransactions(_) => deserialize(bytes).map(Value::BlockTransactions), Key::Transaction(_) => deserialize(bytes).map(Value::Transaction), Key::TransactionMeta(_) => deserialize(bytes).map(Value::TransactionMeta), Key::BlockNumber(_) => deserialize(bytes).map(Value::BlockNumber), Key::Configuration(_) => deserialize(bytes).map(Value::Configuration), Key::Nullifier(_) => Ok(Value::Empty), Key::TreeRoot(tag) => match tag.epoch() { EpochTag::Sprout => deserialize(bytes).map(Value::SproutTreeState), EpochTag::Sapling => deserialize(bytes).map(Value::SaplingTreeState), }, Key::SproutBlockRoot(_) => deserialize(bytes).map(Value::SproutTreeRoot), } .map_err(|e| format!("{:?}", e)) } pub fn as_meta(self) -> Option { match self { Value::Meta(bytes) => Some(bytes), _ => None, } } pub fn as_block_hash(self) -> Option { match self { Value::BlockHash(block_hash) => Some(block_hash), _ => None, } } pub fn as_block_header(self) -> Option { match self { Value::BlockHeader(block_header) => Some(block_header), _ => None, } } pub fn as_block_transactions(self) -> Option> { match self { Value::BlockTransactions(list) => Some(list), _ => None, } } pub fn as_transaction(self) -> Option { match self { Value::Transaction(transaction) => Some(transaction), _ => None, } } pub fn as_transaction_meta(self) -> Option { match self { Value::TransactionMeta(meta) => Some(meta), _ => None, } } pub fn as_block_number(self) -> Option { match self { Value::BlockNumber(number) => Some(number), _ => None, } } pub fn as_configuration(self) -> Option { match self { Value::Configuration(bytes) => Some(bytes), _ => None, } } pub fn as_sprout_tree_state(self) -> Option { match self { Value::SproutTreeState(tree_state) => Some(tree_state), _ => None, } } pub fn as_sapling_tree_state(self) -> Option { match self { Value::SaplingTreeState(tree_state) => Some(tree_state), _ => None, } } pub fn as_sprout_block_root(self) -> Option { match self { Value::SproutTreeRoot(v) => Some(v), _ => None, } } } #[derive(Debug, Clone)] pub enum KeyState { Insert(V), Delete, Unknown, } impl Default for KeyState { fn default() -> Self { KeyState::Unknown } } impl KeyState { pub fn map(self, f: F) -> KeyState where F: FnOnce(V) -> U, { match self { KeyState::Insert(value) => KeyState::Insert(f(value)), KeyState::Delete => KeyState::Delete, KeyState::Unknown => KeyState::Unknown, } } pub fn into_option(self) -> Option { match self { KeyState::Insert(value) => Some(value), KeyState::Delete => None, KeyState::Unknown => None, } } pub fn into_operation(self, key: K, insert: I, delete: D) -> Option where I: FnOnce(K, V) -> KeyValue, D: FnOnce(K) -> Key, { match self { KeyState::Insert(value) => Some(Operation::Insert(insert(key, value))), KeyState::Delete => Some(Operation::Delete(delete(key))), KeyState::Unknown => None, } } } #[derive(Debug)] pub struct Transaction { pub operations: Vec, } impl Default for Transaction { fn default() -> Self { Transaction { operations: Vec::with_capacity(32), } } } impl Transaction { pub fn new() -> Self { Transaction::default() } pub fn insert(&mut self, insert: KeyValue) { self.operations.push(Operation::Insert(insert)); } pub fn delete(&mut self, delete: Key) { self.operations.push(Operation::Delete(delete)); } } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum Location { DB, Column(u32), } impl From for Location { fn from(column: u32) -> Location { Location::Column(column) } } pub enum RawOperation { Insert(RawKeyValue), Delete(RawKey), } pub struct RawKeyValue { pub location: Location, pub key: Bytes, pub value: Bytes, } impl<'a> From<&'a KeyValue> for RawKeyValue { fn from(i: &'a KeyValue) -> Self { let (location, key, value) = match *i { KeyValue::Meta(ref key, ref value) => (COL_META, serialize(key), serialize(value)), KeyValue::BlockHash(ref key, ref value) => { (COL_BLOCK_HASHES, serialize(key), serialize(value)) } KeyValue::BlockHeader(ref key, ref value) => { (COL_BLOCK_HEADERS, serialize(key), serialize(value)) } KeyValue::BlockTransactions(ref key, ref value) => { (COL_BLOCK_TRANSACTIONS, serialize(key), serialize(value)) } KeyValue::Transaction(ref key, ref value) => { (COL_TRANSACTIONS, serialize(key), serialize(value)) } KeyValue::TransactionMeta(ref key, ref value) => { (COL_TRANSACTIONS_META, serialize(key), serialize(value)) } KeyValue::Nullifier(ref key) => match key.epoch() { EpochTag::Sprout => (COL_SPROUT_NULLIFIERS, serialize(key.hash()), Bytes::new()), EpochTag::Sapling => (COL_SAPLING_NULLIFIERS, serialize(key.hash()), Bytes::new()), }, KeyValue::BlockNumber(ref key, ref value) => { (COL_BLOCK_NUMBERS, serialize(key), serialize(value)) } KeyValue::SproutTreeState(ref key, ref value) => { (COL_TREE_STATES, serialize(key), serialize(value)) } KeyValue::SaplingTreeState(ref key, ref value) => { (COL_TREE_STATES, serialize(key), serialize(value)) } KeyValue::SproutBlockRoot(ref key, ref value) => { (COL_SPROUT_BLOCK_ROOTS, serialize(key), serialize(value)) } KeyValue::Configuration(ref key, ref value) => { (COL_CONFIGURATION, serialize(key), serialize(value)) } }; RawKeyValue { location: location.into(), key: key, value: value, } } } pub struct RawKey { pub location: Location, pub key: Bytes, } impl RawKey { pub fn new(location: Location, key: B) -> Self where B: Into, { RawKey { location: location, key: key.into(), } } } impl<'a> From<&'a Key> for RawKey { fn from(d: &'a Key) -> Self { let (location, key) = match *d { Key::Meta(ref key) => (COL_META, serialize(key)), Key::BlockHash(ref key) => (COL_BLOCK_HASHES, serialize(key)), Key::BlockHeader(ref key) => (COL_BLOCK_HEADERS, serialize(key)), Key::BlockTransactions(ref key) => (COL_BLOCK_TRANSACTIONS, serialize(key)), Key::Transaction(ref key) => (COL_TRANSACTIONS, serialize(key)), Key::TransactionMeta(ref key) => (COL_TRANSACTIONS_META, serialize(key)), Key::Nullifier(ref key) => match key.epoch() { EpochTag::Sprout => (COL_SPROUT_NULLIFIERS, serialize(key.hash())), EpochTag::Sapling => (COL_SAPLING_NULLIFIERS, serialize(key.hash())), }, Key::TreeRoot(ref key) => (COL_TREE_STATES, serialize(key.hash())), Key::BlockNumber(ref key) => (COL_BLOCK_NUMBERS, serialize(key)), Key::SproutBlockRoot(ref key) => (COL_SPROUT_BLOCK_ROOTS, serialize(key)), Key::Configuration(ref key) => (COL_CONFIGURATION, serialize(key)), }; RawKey { location: location.into(), key: key, } } } impl<'a> From<&'a Operation> for RawOperation { fn from(o: &'a Operation) -> Self { match *o { Operation::Insert(ref insert) => RawOperation::Insert(insert.into()), Operation::Delete(ref delete) => RawOperation::Delete(delete.into()), } } } pub struct RawTransaction { pub operations: Vec, } impl<'a> From<&'a Transaction> for RawTransaction { fn from(tx: &'a Transaction) -> Self { RawTransaction { operations: tx.operations.iter().map(Into::into).collect(), } } } impl Default for RawTransaction { fn default() -> Self { RawTransaction { operations: Vec::with_capacity(32), } } } impl RawTransaction { pub fn new() -> RawTransaction { RawTransaction::default() } pub fn insert_raw(&mut self, location: Location, key: &[u8], value: &[u8]) { let operation = RawOperation::Insert(RawKeyValue { location: location, key: key.into(), value: value.into(), }); self.operations.push(operation); } pub fn delete_raw(&mut self, location: Location, key: &[u8]) { let operation = RawOperation::Delete(RawKey { location: location, key: key.into(), }); self.operations.push(operation); } }