db refactor finished

This commit is contained in:
debris 2017-04-21 15:26:19 +02:00
parent f4c958e9f2
commit 09f25c4f2f
12 changed files with 188 additions and 107 deletions

View File

@ -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>;

View File

@ -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)
}

View File

@ -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]

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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(())
}
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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;