411 lines
12 KiB
Rust
411 lines
12 KiB
Rust
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<H256>),
|
|
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<H256>),
|
|
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<Self, String> {
|
|
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<Bytes> {
|
|
match self {
|
|
Value::Meta(bytes) => Some(bytes),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_block_hash(self) -> Option<H256> {
|
|
match self {
|
|
Value::BlockHash(block_hash) => Some(block_hash),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_block_header(self) -> Option<BlockHeader> {
|
|
match self {
|
|
Value::BlockHeader(block_header) => Some(block_header),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_block_transactions(self) -> Option<List<H256>> {
|
|
match self {
|
|
Value::BlockTransactions(list) => Some(list),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_transaction(self) -> Option<ChainTransaction> {
|
|
match self {
|
|
Value::Transaction(transaction) => Some(transaction),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_transaction_meta(self) -> Option<TransactionMeta> {
|
|
match self {
|
|
Value::TransactionMeta(meta) => Some(meta),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_block_number(self) -> Option<u32> {
|
|
match self {
|
|
Value::BlockNumber(number) => Some(number),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_configuration(self) -> Option<Bytes> {
|
|
match self {
|
|
Value::Configuration(bytes) => Some(bytes),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_sprout_tree_state(self) -> Option<SproutTreeState> {
|
|
match self {
|
|
Value::SproutTreeState(tree_state) => Some(tree_state),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_sapling_tree_state(self) -> Option<SaplingTreeState> {
|
|
match self {
|
|
Value::SaplingTreeState(tree_state) => Some(tree_state),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn as_sprout_block_root(self) -> Option<H256> {
|
|
match self {
|
|
Value::SproutTreeRoot(v) => Some(v),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum KeyState<V> {
|
|
Insert(V),
|
|
Delete,
|
|
Unknown,
|
|
}
|
|
|
|
impl<V> Default for KeyState<V> {
|
|
fn default() -> Self {
|
|
KeyState::Unknown
|
|
}
|
|
}
|
|
|
|
impl<V> KeyState<V> {
|
|
pub fn map<U, F>(self, f: F) -> KeyState<U>
|
|
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<V> {
|
|
match self {
|
|
KeyState::Insert(value) => Some(value),
|
|
KeyState::Delete => None,
|
|
KeyState::Unknown => None,
|
|
}
|
|
}
|
|
|
|
pub fn into_operation<K, I, D>(self, key: K, insert: I, delete: D) -> Option<Operation>
|
|
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<Operation>,
|
|
}
|
|
|
|
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<u32> 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<B>(location: Location, key: B) -> Self
|
|
where
|
|
B: Into<Bytes>,
|
|
{
|
|
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<RawOperation>,
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|