db refactor finished
This commit is contained in:
parent
f4c958e9f2
commit
09f25c4f2f
|
@ -13,7 +13,7 @@ pub trait ForkChain {
|
|||
|
||||
pub trait BlockChain {
|
||||
/// Inserts new block into blockchain
|
||||
fn insert(&self, block: &IndexedBlock) -> Result<(), Error>;
|
||||
fn insert(&self, block: IndexedBlock) -> Result<(), Error>;
|
||||
|
||||
/// Canonizes block with given hash
|
||||
fn canonize(&self, block_hash: &H256) -> Result<(), Error>;
|
||||
|
|
|
@ -9,12 +9,11 @@ use chain::{
|
|||
OutPoint, TransactionOutput
|
||||
};
|
||||
use ser::{
|
||||
deserialize, serialize, serialize_list, Serializable, Deserializable,
|
||||
DeserializableList
|
||||
deserialize, serialize, serialize_list, Serializable, Deserializable, List
|
||||
};
|
||||
use kv::{
|
||||
KeyValueDatabase, OverlayDatabase, Transaction as DBTransaction, Location, Value, DiskDatabase,
|
||||
DatabaseConfig, MemoryDatabase, AutoFlushingOverlayDatabase
|
||||
DatabaseConfig, MemoryDatabase, AutoFlushingOverlayDatabase, KeyValue, Key, KeyState
|
||||
};
|
||||
use best_block::BestBlock;
|
||||
use {
|
||||
|
@ -84,9 +83,10 @@ impl BlockChainDatabase<MemoryDatabase> {
|
|||
pub fn init_test_chain(blocks: Vec<IndexedBlock>) -> Self {
|
||||
let store = BlockChainDatabase::open(MemoryDatabase::default());
|
||||
|
||||
for block in &blocks {
|
||||
for block in blocks {
|
||||
let hash = block.hash().clone();
|
||||
store.insert(block).unwrap();
|
||||
store.canonize(block.hash()).unwrap();
|
||||
store.canonize(&hash).unwrap();
|
||||
}
|
||||
store
|
||||
}
|
||||
|
@ -105,14 +105,16 @@ impl<T> BlockChainDatabase<AutoFlushingOverlayDatabase<T>> where T: KeyValueData
|
|||
|
||||
impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||
fn read_best_block(db: &T) -> Option<BestBlock> {
|
||||
let best_number = db.get(COL_META.into(), &serialize(&KEY_BEST_BLOCK_NUMBER));
|
||||
let best_hash = db.get(COL_META.into(), &serialize(&KEY_BEST_BLOCK_HASH));
|
||||
//let best_number = db.get(COL_META.into(), &serialize(&KEY_BEST_BLOCK_NUMBER));
|
||||
//let best_hash = db.get(COL_META.into(), &serialize(&KEY_BEST_BLOCK_HASH));
|
||||
let best_number = db.get(&Key::Meta(KEY_BEST_BLOCK_NUMBER)).map(KeyState::into_option).map(|x| x.and_then(Value::as_meta));
|
||||
let best_hash = db.get(&Key::Meta(KEY_BEST_BLOCK_HASH)).map(KeyState::into_option).map(|x| x.and_then(Value::as_meta));
|
||||
|
||||
match (best_number, best_hash) {
|
||||
(Ok(None), Ok(None)) => None,
|
||||
(Ok(Some(number)), Ok(Some(hash))) => Some(BestBlock {
|
||||
number: deserialize(&*number).expect("Inconsistent DB. Invalid best block number."),
|
||||
hash: deserialize(&*hash).expect("Inconsistent DB. Invalid best block hash."),
|
||||
number: deserialize(&**number).expect("Inconsistent DB. Invalid best block number."),
|
||||
hash: deserialize(&**hash).expect("Inconsistent DB. Invalid best block hash."),
|
||||
}),
|
||||
_ => panic!("Inconsistent DB"),
|
||||
}
|
||||
|
@ -207,24 +209,31 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
Err(Error::AncientFork)
|
||||
}
|
||||
|
||||
pub fn insert(&self, block: &IndexedBlock) -> Result<(), Error> {
|
||||
pub fn insert(&self, block: IndexedBlock) -> Result<(), Error> {
|
||||
if self.contains_block(block.hash().clone().into()) {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let parent_hash = &block.header.raw.previous_header_hash;
|
||||
let parent_hash = block.header.raw.previous_header_hash.clone();
|
||||
if !self.contains_block(parent_hash.clone().into()) && !parent_hash.is_zero() {
|
||||
return Err(Error::UnknownParent);
|
||||
}
|
||||
|
||||
let mut update = DBTransaction::new();
|
||||
update.insert(COL_BLOCK_HEADERS.into(), block.hash(), &block.header.raw);
|
||||
for tx in &block.transactions {
|
||||
update.insert(COL_TRANSACTIONS.into(), &tx.hash, &tx.raw);
|
||||
update.insert(KeyValue::BlockHeader(block.hash().clone(), block.header.raw));
|
||||
//update.insert(COL_BLOCK_HEADERS.into(), block.hash(), &block.header.raw);
|
||||
//let tx_hashes = serialize_list::<H256, &H256>(&block.transactions.iter().map(|tx| &tx.hash).collect::<Vec<_>>());
|
||||
//update.insert_raw(COL_BLOCK_TRANSACTIONS.into(), &**block.hash(), &tx_hashes);
|
||||
let tx_hashes = block.transactions.iter().map(|tx| tx.hash.clone()).collect::<Vec<_>>();
|
||||
update.insert(KeyValue::BlockTransactions(block.header.hash.clone(), List::from(tx_hashes)));
|
||||
|
||||
for tx in block.transactions.into_iter() {
|
||||
//update.insert(COL_TRANSACTIONS.into(), &tx.hash, &tx.raw);
|
||||
update.insert(KeyValue::Transaction(tx.hash, tx.raw));
|
||||
}
|
||||
|
||||
let tx_hashes = serialize_list::<H256, &H256>(&block.transactions.iter().map(|tx| &tx.hash).collect::<Vec<_>>());
|
||||
update.insert_raw(COL_BLOCK_TRANSACTIONS.into(), &**block.hash(), &tx_hashes);
|
||||
//let tx_hashes = serialize_list::<H256, &H256>(&block.transactions.iter().map(|tx| &tx.hash).collect::<Vec<_>>());
|
||||
//update.insert_raw(COL_BLOCK_TRANSACTIONS.into(), &**block.hash(), &tx_hashes);
|
||||
self.db.write(update).map_err(Error::DatabaseError)
|
||||
}
|
||||
|
||||
|
@ -255,10 +264,14 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
trace!(target: "db", "canonize {:?}", new_best_block);
|
||||
|
||||
let mut update = DBTransaction::new();
|
||||
update.insert(COL_BLOCK_HASHES.into(), &new_best_block.number, &new_best_block.hash);
|
||||
update.insert(COL_BLOCK_NUMBERS.into(), &new_best_block.hash, &new_best_block.number);
|
||||
update.insert(COL_META.into(), &KEY_BEST_BLOCK_HASH, &new_best_block.hash);
|
||||
update.insert(COL_META.into(), &KEY_BEST_BLOCK_NUMBER, &new_best_block.number);
|
||||
//update.insert(COL_BLOCK_HASHES.into(), &new_best_block.number, &new_best_block.hash);
|
||||
//update.insert(COL_BLOCK_NUMBERS.into(), &new_best_block.hash, &new_best_block.number);
|
||||
//update.insert(COL_META.into(), &KEY_BEST_BLOCK_HASH, &new_best_block.hash);
|
||||
//update.insert(COL_META.into(), &KEY_BEST_BLOCK_NUMBER, &new_best_block.number);
|
||||
update.insert(KeyValue::BlockHash(new_best_block.number, new_best_block.hash.clone()));
|
||||
update.insert(KeyValue::BlockNumber(new_best_block.hash.clone(), new_best_block.number));
|
||||
update.insert(KeyValue::Meta(KEY_BEST_BLOCK_HASH, serialize(&new_best_block.hash)));
|
||||
update.insert(KeyValue::Meta(KEY_BEST_BLOCK_NUMBER, serialize(&new_best_block.number)));
|
||||
|
||||
let mut modified_meta: HashMap<H256, TransactionMeta> = HashMap::new();
|
||||
if let Some(tx) = block.transactions.first() {
|
||||
|
@ -287,8 +300,9 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
for (hash, meta) in modified_meta.iter() {
|
||||
update.insert(COL_TRANSACTIONS_META.into(), hash, meta);
|
||||
for (hash, meta) in modified_meta.into_iter() {
|
||||
update.insert(KeyValue::TransactionMeta(hash, meta));
|
||||
//update.insert(COL_TRANSACTIONS_META.into(), hash, meta);
|
||||
}
|
||||
|
||||
self.db.write(update).map_err(Error::DatabaseError)?;
|
||||
|
@ -318,10 +332,14 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
trace!(target: "db", "decanonize, new best: {:?}", new_best_block);
|
||||
|
||||
let mut update = DBTransaction::new();
|
||||
update.delete(COL_BLOCK_HASHES.into(), &block_number);
|
||||
update.delete(COL_BLOCK_NUMBERS.into(), &block_hash);
|
||||
update.insert(COL_META.into(), &KEY_BEST_BLOCK_HASH, &new_best_block.hash);
|
||||
update.insert(COL_META.into(), &KEY_BEST_BLOCK_NUMBER, &new_best_block.number);
|
||||
//update.delete(COL_BLOCK_HASHES.into(), &block_number);
|
||||
//update.delete(COL_BLOCK_NUMBERS.into(), &block_hash);
|
||||
//update.insert(COL_META.into(), &KEY_BEST_BLOCK_HASH, &new_best_block.hash);
|
||||
//update.insert(COL_META.into(), &KEY_BEST_BLOCK_NUMBER, &new_best_block.number);
|
||||
update.delete(Key::BlockHash(block_number));
|
||||
update.delete(Key::BlockNumber(block_hash.clone()));
|
||||
update.insert(KeyValue::Meta(KEY_BEST_BLOCK_HASH, serialize(&new_best_block.hash)));
|
||||
update.insert(KeyValue::Meta(KEY_BEST_BLOCK_NUMBER, serialize(&new_best_block.number)));
|
||||
|
||||
let mut modified_meta: HashMap<H256, TransactionMeta> = HashMap::new();
|
||||
for tx in block.transactions.iter().skip(1) {
|
||||
|
@ -343,12 +361,14 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
for (hash, meta) in modified_meta.iter() {
|
||||
update.insert(COL_TRANSACTIONS_META.into(), hash, meta);
|
||||
for (hash, meta) in modified_meta {
|
||||
//update.insert(COL_TRANSACTIONS_META.into(), hash, meta);
|
||||
update.insert(KeyValue::TransactionMeta(hash, meta));
|
||||
}
|
||||
|
||||
for tx in &block.transactions {
|
||||
update.delete(COL_TRANSACTIONS_META.into(), &tx.hash);
|
||||
for tx in block.transactions {
|
||||
//update.delete(COL_TRANSACTIONS_META.into(), &tx.hash);
|
||||
update.delete(Key::TransactionMeta(tx.hash));
|
||||
}
|
||||
|
||||
self.db.write(update).map_err(Error::DatabaseError)?;
|
||||
|
@ -356,12 +376,15 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
Ok(block_hash)
|
||||
}
|
||||
|
||||
fn get_raw<K>(&self, location: Location, key: &K) -> Option<Value> where K: Serializable {
|
||||
self.db.get(location, &serialize(key)).expect("db query to be fine")
|
||||
}
|
||||
//fn get_raw<K>(&self, location: Location, key: &K) -> Option<Value> where K: Serializable {
|
||||
//self.db.get(location, &serialize(key)).expect("db query to be fine")
|
||||
//}
|
||||
|
||||
fn get<K, V>(&self, location: Location, key: &K) -> Option<V> where K: Serializable, V: Deserializable {
|
||||
self.get_raw(location, key).map(|val| deserialize(&*val).expect("db value to be fine"))
|
||||
//fn get<K, V>(&self, location: Location, key: &K) -> Option<V> where K: Serializable, V: Deserializable {
|
||||
//self.get_raw(location, key).map(|val| deserialize(&*val).expect("db value to be fine"))
|
||||
//}
|
||||
fn get(&self, key: Key) -> Option<Value> {
|
||||
self.db.get(&key).expect("db value to be fine").into_option()
|
||||
}
|
||||
|
||||
fn resolve_hash(&self, block_ref: BlockRef) -> Option<H256> {
|
||||
|
@ -374,24 +397,30 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
|
||||
impl<T> BlockHeaderProvider for BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||
fn block_header_bytes(&self, block_ref: BlockRef) -> Option<Bytes> {
|
||||
self.resolve_hash(block_ref)
|
||||
.and_then(|hash| self.get_raw(COL_BLOCK_HEADERS.into(), &hash))
|
||||
.map(|raw| (&*raw).into())
|
||||
self.block_header(block_ref).map(|header| serialize(&header))
|
||||
//.and_then(|hash| self.get_raw(COL_BLOCK_HEADERS.into(), &hash))
|
||||
//.map(|raw| (&*raw).into())
|
||||
}
|
||||
|
||||
fn block_header(&self, block_ref: BlockRef) -> Option<BlockHeader> {
|
||||
self.resolve_hash(block_ref)
|
||||
.and_then(|hash| self.get(COL_BLOCK_HEADERS.into(), &hash))
|
||||
.and_then(|hash| self.get(Key::BlockHeader(hash)))
|
||||
.and_then(Value::as_block_header)
|
||||
//.and_then(|hash| self.get(COL_BLOCK_HEADERS.into(), &hash))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BlockProvider for BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||
fn block_number(&self, hash: &H256) -> Option<u32> {
|
||||
self.get(COL_BLOCK_NUMBERS.into(), hash)
|
||||
self.get(Key::BlockNumber(hash.clone()))
|
||||
.and_then(Value::as_block_number)
|
||||
//self.get(COL_BLOCK_NUMBERS.into(), hash)
|
||||
}
|
||||
|
||||
fn block_hash(&self, number: u32) -> Option<H256> {
|
||||
self.get(COL_BLOCK_HASHES.into(), &number)
|
||||
self.get(Key::BlockHash(number))
|
||||
.and_then(Value::as_block_hash)
|
||||
//self.get(COL_BLOCK_HASHES.into(), &number)
|
||||
}
|
||||
|
||||
fn block(&self, block_ref: BlockRef) -> Option<Block> {
|
||||
|
@ -407,22 +436,31 @@ impl<T> BlockProvider for BlockChainDatabase<T> where T: KeyValueDatabase {
|
|||
|
||||
fn contains_block(&self, block_ref: BlockRef) -> bool {
|
||||
self.resolve_hash(block_ref)
|
||||
.and_then(|block_hash| self.get_raw(COL_BLOCK_HEADERS.into(), &block_hash))
|
||||
.and_then(|hash| self.get(Key::BlockHeader(hash)))
|
||||
.is_some()
|
||||
//.and_then(|block_hash| self.get_raw(COL_BLOCK_HEADERS.into(), &block_hash))
|
||||
//.is_some()
|
||||
}
|
||||
|
||||
fn block_transaction_hashes(&self, block_ref: BlockRef) -> Vec<H256> {
|
||||
self.resolve_hash(block_ref)
|
||||
.and_then(|block_hash| self.get(COL_BLOCK_TRANSACTIONS.into(), &block_hash))
|
||||
.map(|hashes: DeserializableList<H256>| hashes.into())
|
||||
.and_then(|hash| self.get(Key::BlockTransactions(hash)))
|
||||
.and_then(Value::as_block_transactions)
|
||||
.map(List::into)
|
||||
.unwrap_or_default()
|
||||
//.and_then(|block_hash| self.get(COL_BLOCK_TRANSACTIONS.into(), &block_hash))
|
||||
//.map(|hashes: DeserializableList<H256>| hashes.into())
|
||||
//.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn block_transactions(&self, block_ref: BlockRef) -> Vec<Transaction> {
|
||||
self.block_transaction_hashes(block_ref)
|
||||
.iter()
|
||||
.filter_map(|hash| self.get(COL_TRANSACTIONS.into(), hash))
|
||||
.into_iter()
|
||||
.filter_map(|hash| self.get(Key::Transaction(hash)))
|
||||
.filter_map(Value::as_transaction)
|
||||
.collect()
|
||||
//.filter_map(|hash| self.get(COL_TRANSACTIONS.into(), hash))
|
||||
//.collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,8 +468,12 @@ impl<T> IndexedBlockProvider for BlockChainDatabase<T> where T: KeyValueDatabase
|
|||
fn indexed_block_header(&self, block_ref: BlockRef) -> Option<IndexedBlockHeader> {
|
||||
self.resolve_hash(block_ref)
|
||||
.and_then(|block_hash| {
|
||||
self.get(COL_BLOCK_HEADERS.into(), &block_hash)
|
||||
self.get(Key::BlockHeader(block_hash.clone()))
|
||||
.and_then(Value::as_block_header)
|
||||
.map(|header| IndexedBlockHeader::new(block_hash, header))
|
||||
//unimplemented!();
|
||||
//self.get(COL_BLOCK_HEADERS.into(), &block_hash)
|
||||
//.map(|header| IndexedBlockHeader::new(block_hash, header))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -450,8 +492,11 @@ impl<T> IndexedBlockProvider for BlockChainDatabase<T> where T: KeyValueDatabase
|
|||
self.block_transaction_hashes(block_ref)
|
||||
.into_iter()
|
||||
.filter_map(|hash| {
|
||||
self.get(COL_TRANSACTIONS.into(), &hash)
|
||||
self.get(Key::Transaction(hash.clone()))
|
||||
.and_then(Value::as_transaction)
|
||||
.map(|tx| IndexedTransaction::new(hash, tx))
|
||||
//self.get(COL_TRANSACTIONS.into(), &hash)
|
||||
//.map(|tx| IndexedTransaction::new(hash, tx))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -459,18 +504,23 @@ impl<T> IndexedBlockProvider for BlockChainDatabase<T> where T: KeyValueDatabase
|
|||
|
||||
impl<T> TransactionMetaProvider for BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||
fn transaction_meta(&self, hash: &H256) -> Option<TransactionMeta> {
|
||||
self.get(COL_TRANSACTIONS_META.into(), hash)
|
||||
self.get(Key::TransactionMeta(hash.clone()))
|
||||
.and_then(Value::as_transaction_meta)
|
||||
//self.get(COL_TRANSACTIONS_META.into(), hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TransactionProvider for BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||
fn transaction_bytes(&self, hash: &H256) -> Option<Bytes> {
|
||||
self.get_raw(COL_TRANSACTIONS.into(), hash)
|
||||
.map(|raw| (&*raw).into())
|
||||
self.transaction(hash).map(|tx| serialize(&tx))
|
||||
//self.get_raw(COL_TRANSACTIONS.into(), hash)
|
||||
//.map(|raw| (&*raw).into())
|
||||
}
|
||||
|
||||
fn transaction(&self, hash: &H256) -> Option<Transaction> {
|
||||
self.get(COL_TRANSACTIONS.into(), hash)
|
||||
self.get(Key::Transaction(hash.clone()))
|
||||
.and_then(Value::as_transaction)
|
||||
//self.get(COL_TRANSACTIONS.into(), hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,7 +540,7 @@ impl<T> TransactionOutputProvider for BlockChainDatabase<T> where T: KeyValueDat
|
|||
}
|
||||
|
||||
impl<T> BlockChain for BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||
fn insert(&self, block: &IndexedBlock) -> Result<(), Error> {
|
||||
fn insert(&self, block: IndexedBlock) -> Result<(), Error> {
|
||||
BlockChainDatabase::insert(self, block)
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ mod tests {
|
|||
batch.insert_raw(Location::DB, key2, b"dog");
|
||||
db.write(batch).unwrap();
|
||||
|
||||
assert_eq!(&*db.get(Location::DB, key1).unwrap().unwrap(), b"cat");
|
||||
assert_eq!(&*db.get(&RawKey::new(Location::DB,key1 as &[u8])).unwrap().unwrap(), b"cat");
|
||||
|
||||
let contents: Vec<_> = db.iter(Location::DB).collect();
|
||||
assert_eq!(contents.len(), 2);
|
||||
|
@ -328,7 +328,7 @@ mod tests {
|
|||
batch.delete_raw(Location::DB, key1);
|
||||
db.write(batch).unwrap();
|
||||
|
||||
assert_eq!(db.get(Location::DB, key1).unwrap(), None);
|
||||
assert_eq!(db.get(&RawKey::new(Location::DB, key1 as &[u8])).unwrap(), None);
|
||||
|
||||
let mut batch = RawTransaction::default();
|
||||
batch.insert_raw(Location::DB, key1, b"cat");
|
||||
|
@ -338,7 +338,7 @@ mod tests {
|
|||
transaction.insert_raw(Location::DB, key3, b"elephant");
|
||||
transaction.delete_raw(Location::DB, key1);
|
||||
db.write(transaction).unwrap();
|
||||
assert_eq!(&*db.get(Location::DB, key3).unwrap().unwrap(), b"elephant");
|
||||
assert_eq!(&*db.get(&RawKey::new(Location::DB, key3 as &[u8])).unwrap().unwrap(), b"elephant");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -229,6 +229,15 @@ pub struct RawKey {
|
|||
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 {
|
||||
|
@ -281,4 +290,21 @@ 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ mod block_origin;
|
|||
mod block_provider;
|
||||
mod block_ref;
|
||||
mod block_chain;
|
||||
//mod block_chain_db;
|
||||
mod block_chain_db;
|
||||
mod error;
|
||||
mod block_impls;
|
||||
mod store;
|
||||
|
@ -29,7 +29,7 @@ pub use block_origin::{BlockOrigin, SideChainOrigin};
|
|||
pub use block_provider::{BlockHeaderProvider, BlockProvider, IndexedBlockProvider};
|
||||
pub use block_ref::BlockRef;
|
||||
pub use block_chain::{BlockChain, ForkChain, Forkable};
|
||||
//pub use block_chain_db::{BlockChainDatabase, ForkChainDatabase};
|
||||
pub use block_chain_db::{BlockChainDatabase, ForkChainDatabase};
|
||||
pub use error::Error;
|
||||
pub use store::{AsSubstore, Store, SharedStore, CanonStore};
|
||||
pub use transaction_meta::TransactionMeta;
|
||||
|
|
|
@ -13,9 +13,9 @@ fn insert_block() {
|
|||
let b1: IndexedBlock = test_data::block_h1().into();
|
||||
let b2: IndexedBlock = test_data::block_h2().into();
|
||||
|
||||
store.insert(&b0).unwrap();
|
||||
store.insert(&b1).unwrap();
|
||||
store.insert(&b2).unwrap();
|
||||
store.insert(b0.clone()).unwrap();
|
||||
store.insert(b1.clone()).unwrap();
|
||||
store.insert(b2.clone()).unwrap();
|
||||
|
||||
assert_eq!(0, store.best_block().number);
|
||||
assert!(store.best_block().hash.is_zero());
|
||||
|
@ -55,9 +55,9 @@ fn reopen_db() {
|
|||
|
||||
{
|
||||
let store = BlockChainDatabase::open(shared_database.clone());
|
||||
store.insert(&b0).unwrap();
|
||||
store.insert(&b1).unwrap();
|
||||
store.insert(&b2).unwrap();
|
||||
store.insert(b0.clone()).unwrap();
|
||||
store.insert(b1.clone()).unwrap();
|
||||
store.insert(b2.clone()).unwrap();
|
||||
|
||||
store.canonize(b0.hash()).unwrap();
|
||||
store.canonize(b1.hash()).unwrap();
|
||||
|
@ -80,9 +80,9 @@ fn switch_to_simple_fork() {
|
|||
let b1: IndexedBlock = test_data::block_h1().into();
|
||||
let b2: IndexedBlock = test_data::block_h2().into();
|
||||
|
||||
store.insert(&b0).unwrap();
|
||||
store.insert(&b1).unwrap();
|
||||
store.insert(&b2).unwrap();
|
||||
store.insert(b0.clone()).unwrap();
|
||||
store.insert(b1.clone()).unwrap();
|
||||
store.insert(b2.clone()).unwrap();
|
||||
|
||||
store.canonize(b0.hash()).unwrap();
|
||||
store.canonize(b1.hash()).unwrap();
|
||||
|
|
|
@ -30,8 +30,9 @@ pub fn init_db(cfg: &Config, db: &db::SharedStore) -> Result<(), String> {
|
|||
Some(ref db_genesis_block_hash) if db_genesis_block_hash != genesis_block.hash() => Err("Trying to open database with incompatible genesis block".into()),
|
||||
Some(_) => Ok(()),
|
||||
None => {
|
||||
db.insert(&genesis_block).expect("Failed to insert genesis block to the database");
|
||||
db.canonize(genesis_block.hash()).expect("Failed to canonize genesis block");
|
||||
let hash = genesis_block.hash().clone();
|
||||
db.insert(genesis_block).expect("Failed to insert genesis block to the database");
|
||||
db.canonize(&hash).expect("Failed to canonize genesis block");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,8 +85,9 @@ impl BlocksWriter {
|
|||
return Err(err);
|
||||
}
|
||||
} else {
|
||||
self.storage.insert(&block).map_err(Error::Database)?;
|
||||
self.storage.canonize(block.hash()).map_err(Error::Database)?;
|
||||
let hash = block.hash().clone();
|
||||
self.storage.insert(block).map_err(Error::Database)?;
|
||||
self.storage.canonize(&hash).map_err(Error::Database)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,10 +124,11 @@ impl VerificationSink for BlocksWriterSink {
|
|||
|
||||
impl BlockVerificationSink for BlocksWriterSink {
|
||||
fn on_block_verification_success(&self, block: chain::IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
if let Err(err) = self.data.storage.insert(&block) {
|
||||
let hash = block.hash().clone();
|
||||
if let Err(err) = self.data.storage.insert(block) {
|
||||
*self.data.err.lock() = Some(Error::Database(err));
|
||||
}
|
||||
if let Err(err) = self.data.storage.canonize(block.hash()) {
|
||||
if let Err(err) = self.data.storage.canonize(&hash) {
|
||||
*self.data.err.lock() = Some(Error::Database(err));
|
||||
}
|
||||
|
||||
|
|
|
@ -333,8 +333,7 @@ impl Chain {
|
|||
}
|
||||
|
||||
/// Insert new best block to storage
|
||||
pub fn insert_best_block(&mut self, block: &IndexedBlock) -> Result<BlockInsertionResult, db::Error> {
|
||||
trace!(target: "sync", "insert_best_block {:?} best_block: {:?}", block.hash().reversed(), self.storage.best_block());
|
||||
pub fn insert_best_block(&mut self, block: IndexedBlock) -> Result<BlockInsertionResult, db::Error> {
|
||||
assert_eq!(Some(self.storage.best_block().hash), self.storage.block_hash(self.storage.best_block().number));
|
||||
let block_origin = self.storage.block_origin(&block.header)?;
|
||||
trace!(target: "sync", "insert_best_block {:?} origin: {:?}", block.hash().reversed(), block_origin);
|
||||
|
@ -345,7 +344,7 @@ impl Chain {
|
|||
},
|
||||
// case 1: block has been added to the main branch
|
||||
db::BlockOrigin::CanonChain { .. } => {
|
||||
self.storage.insert(block)?;
|
||||
self.storage.insert(block.clone())?;
|
||||
self.storage.canonize(block.hash())?;
|
||||
|
||||
// remember new best block hash
|
||||
|
@ -379,7 +378,7 @@ impl Chain {
|
|||
// case 2: block has been added to the side branch with reorganization to this branch
|
||||
db::BlockOrigin::SideChainBecomingCanonChain(origin) => {
|
||||
let fork = self.storage.fork(origin.clone())?;
|
||||
fork.store().insert(block)?;
|
||||
fork.store().insert(block.clone())?;
|
||||
fork.store().canonize(block.hash())?;
|
||||
self.storage.switch_to_fork(fork)?;
|
||||
|
||||
|
@ -445,11 +444,12 @@ impl Chain {
|
|||
},
|
||||
// case 3: block has been added to the side branch without reorganization to this branch
|
||||
db::BlockOrigin::SideChain(_origin) => {
|
||||
let block_hash = block.hash().clone();
|
||||
self.storage.insert(block)?;
|
||||
|
||||
// remove inserted block + handle possible reorganization in headers chain
|
||||
// TODO: mk, not sure if it's needed here at all
|
||||
self.headers_chain.block_inserted_to_storage(block.hash(), &self.best_storage_block.hash);
|
||||
self.headers_chain.block_inserted_to_storage(&block_hash, &self.best_storage_block.hash);
|
||||
|
||||
// no transactions were accepted
|
||||
// no transactions to reverify
|
||||
|
@ -791,7 +791,7 @@ mod tests {
|
|||
assert!(chain.information().scheduled == 3 && chain.information().requested == 1
|
||||
&& chain.information().verifying == 1 && chain.information().stored == 1);
|
||||
// insert new best block to the chain
|
||||
chain.insert_best_block(&test_data::block_h1().into()).expect("Db error");
|
||||
chain.insert_best_block(test_data::block_h1().into()).expect("Db error");
|
||||
assert!(chain.information().scheduled == 3 && chain.information().requested == 1
|
||||
&& chain.information().verifying == 1 && chain.information().stored == 2);
|
||||
assert_eq!(db.best_block().number, 1);
|
||||
|
@ -807,13 +807,13 @@ mod tests {
|
|||
let block1 = test_data::block_h1();
|
||||
let block1_hash = block1.hash();
|
||||
|
||||
chain.insert_best_block(&block1.into()).expect("Error inserting new block");
|
||||
chain.insert_best_block(block1.into()).expect("Error inserting new block");
|
||||
assert_eq!(chain.block_locator_hashes(), vec![block1_hash.clone(), genesis_hash.clone()]);
|
||||
|
||||
let block2 = test_data::block_h2();
|
||||
let block2_hash = block2.hash();
|
||||
|
||||
chain.insert_best_block(&block2.into()).expect("Error inserting new block");
|
||||
chain.insert_best_block(block2.into()).expect("Error inserting new block");
|
||||
assert_eq!(chain.block_locator_hashes(), vec![block2_hash.clone(), block1_hash.clone(), genesis_hash.clone()]);
|
||||
|
||||
let blocks0 = test_data::build_n_empty_blocks_from_genesis(11, 0);
|
||||
|
@ -930,7 +930,7 @@ mod tests {
|
|||
assert_eq!(chain.information().transactions.transactions_count, 1);
|
||||
|
||||
// when block is inserted to the database => all accepted transactions are removed from mempool && verifying queue
|
||||
chain.insert_best_block(&b1.into()).expect("block accepted");
|
||||
chain.insert_best_block(b1.into()).expect("block accepted");
|
||||
|
||||
assert_eq!(chain.information().transactions.transactions_count, 0);
|
||||
assert!(!chain.forget_verifying_transaction(&tx1_hash));
|
||||
|
@ -999,15 +999,15 @@ mod tests {
|
|||
chain.insert_verified_transaction(tx2.into());
|
||||
|
||||
// no reorg
|
||||
let result = chain.insert_best_block(&b1.into()).expect("no error");
|
||||
let result = chain.insert_best_block(b1.into()).expect("no error");
|
||||
assert_eq!(result.transactions_to_reverify.len(), 0);
|
||||
|
||||
// no reorg
|
||||
let result = chain.insert_best_block(&b2.into()).expect("no error");
|
||||
let result = chain.insert_best_block(b2.into()).expect("no error");
|
||||
assert_eq!(result.transactions_to_reverify.len(), 0);
|
||||
|
||||
// reorg
|
||||
let result = chain.insert_best_block(&b3.into()).expect("no error");
|
||||
let result = chain.insert_best_block(b3.into()).expect("no error");
|
||||
assert_eq!(result.transactions_to_reverify.len(), 2);
|
||||
assert!(result.transactions_to_reverify.iter().any(|ref tx| &tx.hash == &tx1_hash));
|
||||
assert!(result.transactions_to_reverify.iter().any(|ref tx| &tx.hash == &tx2_hash));
|
||||
|
@ -1048,18 +1048,18 @@ mod tests {
|
|||
chain.insert_verified_transaction(tx4.into());
|
||||
chain.insert_verified_transaction(tx5.into());
|
||||
|
||||
assert_eq!(chain.insert_best_block(&b0.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b0.hash()]));
|
||||
assert_eq!(chain.insert_best_block(b0.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b0.hash()]));
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(&b1.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b1.hash()]));
|
||||
assert_eq!(chain.insert_best_block(b1.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b1.hash()]));
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(&b2.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b2.hash()]));
|
||||
assert_eq!(chain.insert_best_block(b2.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b2.hash()]));
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(&b3.clone().into()).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.insert_best_block(b3.clone().into()).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(&b4.clone().into()).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.insert_best_block(b4.clone().into()).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
// order matters
|
||||
let insert_result = chain.insert_best_block(&b5.clone().into()).expect("block accepted");
|
||||
let insert_result = chain.insert_best_block(b5.clone().into()).expect("block accepted");
|
||||
let transactions_to_reverify_hashes: Vec<_> = insert_result
|
||||
.transactions_to_reverify
|
||||
.into_iter()
|
||||
|
@ -1090,7 +1090,7 @@ mod tests {
|
|||
chain.insert_verified_transaction(tx2.clone().into());
|
||||
chain.insert_verified_transaction(tx3.clone().into());
|
||||
// insert verified block with tx1
|
||||
chain.insert_best_block(&b0.into()).expect("no error");
|
||||
chain.insert_best_block(b0.into()).expect("no error");
|
||||
// => tx2 is removed from memory pool, but tx3 remains
|
||||
assert_eq!(chain.information().transactions.transactions_count, 1);
|
||||
}
|
||||
|
|
|
@ -1013,6 +1013,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
// remove flags
|
||||
let needs_relay = !self.do_not_relay.remove(block.hash());
|
||||
|
||||
let block_hash = block.hash().clone();
|
||||
// insert block to the storage
|
||||
match {
|
||||
// remove block from verification queue
|
||||
|
@ -1020,7 +1021,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
// or it is removed earlier, when block was removed from the verifying queue
|
||||
if self.chain.forget_block_with_state_leave_header(block.hash(), BlockState::Verifying) != HashPosition::Missing {
|
||||
// block was in verification queue => insert to storage
|
||||
self.chain.insert_best_block(&block)
|
||||
self.chain.insert_best_block(block)
|
||||
} else {
|
||||
Ok(BlockInsertionResult::default())
|
||||
}
|
||||
|
@ -1037,7 +1038,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
}
|
||||
|
||||
// awake threads, waiting for this block insertion
|
||||
self.awake_waiting_threads(block.hash());
|
||||
self.awake_waiting_threads(&block_hash);
|
||||
|
||||
// continue with synchronization
|
||||
self.execute_synchronization_tasks(None, None);
|
||||
|
@ -1065,7 +1066,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
},
|
||||
Err(e) => {
|
||||
// process as irrecoverable failure
|
||||
panic!("Block {} insertion failed with error {:?}", block.hash().to_reversed_str(), e);
|
||||
panic!("Block {} insertion failed with error {:?}", block_hash.to_reversed_str(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1715,7 +1716,7 @@ pub mod tests {
|
|||
fn sync_after_db_insert_nonfatal_fail() {
|
||||
let block = test_data::block_h2();
|
||||
let storage = BlockChainDatabase::init_test_chain(vec![test_data::genesis().into()]);
|
||||
assert!(storage.insert(&test_data::block_h2().into()).is_err());
|
||||
assert!(storage.insert(test_data::block_h2().into()).is_err());
|
||||
let best_genesis = storage.best_block();
|
||||
|
||||
let (_, core, sync) = create_sync(Some(Arc::new(storage)), None);
|
||||
|
|
|
@ -563,7 +563,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn server_getblocks_responds_inventory_when_have_unknown_blocks() {
|
||||
let (storage, _, executor, _, server) = create_synchronization_server();
|
||||
storage.insert(&test_data::block_h1().into()).expect("Db write error");
|
||||
storage.insert(test_data::block_h1().into()).expect("Db write error");
|
||||
storage.canonize(&test_data::block_h1().hash()).unwrap();
|
||||
// when asking for blocks hashes
|
||||
server.execute(ServerTask::GetBlocks(0, types::GetBlocks {
|
||||
|
@ -599,7 +599,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn server_getheaders_responds_headers_when_have_unknown_blocks() {
|
||||
let (storage, _, executor, _, server) = create_synchronization_server();
|
||||
storage.insert(&test_data::block_h1().into()).expect("Db write error");
|
||||
storage.insert(test_data::block_h1().into()).expect("Db write error");
|
||||
storage.canonize(&test_data::block_h1().hash()).unwrap();
|
||||
// when asking for blocks hashes
|
||||
let dummy_id = 0;
|
||||
|
@ -743,7 +743,7 @@ pub mod tests {
|
|||
fn server_responds_with_nonempty_inventory_when_getdata_stop_hash_filled() {
|
||||
let (storage, _, executor, _, server) = create_synchronization_server();
|
||||
{
|
||||
storage.insert(&test_data::block_h1().into()).expect("no error");
|
||||
storage.insert(test_data::block_h1().into()).expect("no error");
|
||||
storage.canonize(&test_data::block_h1().hash()).unwrap();
|
||||
}
|
||||
// when asking with stop_hash
|
||||
|
@ -765,7 +765,7 @@ pub mod tests {
|
|||
fn server_responds_with_nonempty_headers_when_getdata_stop_hash_filled() {
|
||||
let (storage, _, executor, _, server) = create_synchronization_server();
|
||||
{
|
||||
storage.insert(&test_data::block_h1().into()).expect("no error");
|
||||
storage.insert(test_data::block_h1().into()).expect("no error");
|
||||
storage.canonize(&test_data::block_h1().hash()).unwrap();
|
||||
}
|
||||
// when asking with stop_hash
|
||||
|
@ -806,8 +806,8 @@ pub mod tests {
|
|||
let b2_hash = b2.hash();
|
||||
|
||||
// This peer will provide blocks
|
||||
storage.insert(&b1.clone().into()).expect("no error");
|
||||
storage.insert(&b2.clone().into()).expect("no error");
|
||||
storage.insert(b1.clone().into()).expect("no error");
|
||||
storage.insert(b2.clone().into()).expect("no error");
|
||||
storage.canonize(&b1.hash()).unwrap();
|
||||
storage.canonize(&b2.hash()).unwrap();
|
||||
|
||||
|
@ -902,7 +902,7 @@ pub mod tests {
|
|||
let b1_hash = b1.hash();
|
||||
|
||||
// This peer will provide blocks
|
||||
storage.insert(&b1.clone().into()).expect("no error");
|
||||
storage.insert(b1.clone().into()).expect("no error");
|
||||
storage.canonize(&b1.hash()).unwrap();
|
||||
|
||||
// This peer will receive compact block
|
||||
|
|
|
@ -322,13 +322,14 @@ mod tests {
|
|||
|
||||
// waiting 100 blocks for genesis coinbase to become valid
|
||||
for _ in 0..100 {
|
||||
let block = test_data::block_builder()
|
||||
let block: IndexedBlock = test_data::block_builder()
|
||||
.transaction().coinbase().build()
|
||||
.merkled_header().parent(genesis.hash()).build()
|
||||
.build()
|
||||
.into();
|
||||
storage.insert(&block).expect("All dummy blocks should be inserted");
|
||||
storage.canonize(block.hash()).unwrap();
|
||||
let hash = block.hash().clone();
|
||||
storage.insert(block).expect("All dummy blocks should be inserted");
|
||||
storage.canonize(&hash).unwrap();
|
||||
}
|
||||
|
||||
let best_hash = storage.best_block().hash;
|
||||
|
|
Loading…
Reference in New Issue