double spend consistency test
This commit is contained in:
parent
4f2b5be34f
commit
b8adad56c3
|
@ -80,7 +80,7 @@ pub struct Storage {
|
||||||
best_block: RwLock<Option<BestBlock>>,
|
best_block: RwLock<Option<BestBlock>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum MetaError {
|
pub enum MetaError {
|
||||||
UnsupportedVersion,
|
UnsupportedVersion,
|
||||||
}
|
}
|
||||||
|
@ -95,29 +95,29 @@ pub enum Error {
|
||||||
/// Invalid meta info (while opening the database)
|
/// Invalid meta info (while opening the database)
|
||||||
Meta(MetaError),
|
Meta(MetaError),
|
||||||
/// Database blockchain consistency error
|
/// Database blockchain consistency error
|
||||||
Consistency(ConsitencyError),
|
Consistency(ConsistencyError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
fn unknown_hash(h: &H256) -> Self {
|
fn unknown_hash(h: &H256) -> Self {
|
||||||
Error::Consistency(ConsitencyError::Unknown(h.clone()))
|
Error::Consistency(ConsistencyError::Unknown(h.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unknown_number(n: u32) -> Self {
|
fn unknown_number(n: u32) -> Self {
|
||||||
Error::Consistency(ConsitencyError::UnknownNumber(n))
|
Error::Consistency(ConsistencyError::UnknownNumber(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn double_spend(h: &H256) -> Self {
|
fn double_spend(h: &H256) -> Self {
|
||||||
Error::Consistency(ConsitencyError::DoubleSpend(h.clone()))
|
Error::Consistency(ConsistencyError::DoubleSpend(h.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not_main(h: &H256) -> Self {
|
fn not_main(h: &H256) -> Self {
|
||||||
Error::Consistency(ConsitencyError::NotMain(h.clone()))
|
Error::Consistency(ConsistencyError::NotMain(h.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ConsitencyError {
|
pub enum ConsistencyError {
|
||||||
/// Unknown hash
|
/// Unknown hash
|
||||||
Unknown(H256),
|
Unknown(H256),
|
||||||
/// Unknown number
|
/// Unknown number
|
||||||
|
@ -342,7 +342,7 @@ impl Storage {
|
||||||
let mut meta =
|
let mut meta =
|
||||||
try!(
|
try!(
|
||||||
self.transaction_meta(&input.previous_output.hash)
|
self.transaction_meta(&input.previous_output.hash)
|
||||||
.ok_or(Error::Consistency(ConsitencyError::UnknownSpending(input.previous_output.hash.clone())))
|
.ok_or(Error::Consistency(ConsistencyError::UnknownSpending(input.previous_output.hash.clone())))
|
||||||
);
|
);
|
||||||
|
|
||||||
if meta.is_spent(input.previous_output.index as usize) {
|
if meta.is_spent(input.previous_output.index as usize) {
|
||||||
|
@ -435,7 +435,7 @@ impl Storage {
|
||||||
next_hash = try!(self.block_header_by_hash(&next_hash).ok_or(Error::unknown_hash(hash)))
|
next_hash = try!(self.block_header_by_hash(&next_hash).ok_or(Error::unknown_hash(hash)))
|
||||||
.previous_header_hash;
|
.previous_header_hash;
|
||||||
}
|
}
|
||||||
Err(Error::Consistency(ConsitencyError::ForkTooLong))
|
Err(Error::Consistency(ConsistencyError::ForkTooLong))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_number(&self) -> Option<u32> {
|
fn best_number(&self) -> Option<u32> {
|
||||||
|
@ -487,7 +487,7 @@ impl Storage {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut now_best = try!(self.best_number().ok_or(Error::Consistency(ConsitencyError::NoBestBlock)));
|
let mut now_best = try!(self.best_number().ok_or(Error::Consistency(ConsistencyError::NoBestBlock)));
|
||||||
|
|
||||||
// decanonizing main chain to the split point
|
// decanonizing main chain to the split point
|
||||||
loop {
|
loop {
|
||||||
|
@ -682,7 +682,7 @@ impl Store for Storage {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::{Storage, Store, UpdateContext};
|
use super::{Storage, Store, UpdateContext, Error, ConsistencyError};
|
||||||
use devtools::RandomTempPath;
|
use devtools::RandomTempPath;
|
||||||
use chain::{Block, RepresentH256};
|
use chain::{Block, RepresentH256};
|
||||||
use super::super::{BlockRef, BlockLocation};
|
use super::super::{BlockRef, BlockLocation};
|
||||||
|
@ -1290,6 +1290,46 @@ mod tests {
|
||||||
assert_eq!(None, location);
|
assert_eq!(None, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn double_spend() {
|
||||||
|
let path = RandomTempPath::create_dir();
|
||||||
|
let store = Storage::new(path.as_path()).unwrap();
|
||||||
|
|
||||||
|
let genesis = test_data::genesis();
|
||||||
|
store.insert_block(&genesis).unwrap();
|
||||||
|
let genesis_coinbase = genesis.transactions()[0].hash();
|
||||||
|
|
||||||
|
let block = test_data::block_builder()
|
||||||
|
.header().parent(genesis.hash()).build()
|
||||||
|
.transaction().coinbase().build()
|
||||||
|
.transaction()
|
||||||
|
.input().hash(genesis_coinbase.clone()).build()
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
store.insert_block(&block).expect("inserting first block in the double spend test should not fail");
|
||||||
|
|
||||||
|
let _dup_block = test_data::block_builder()
|
||||||
|
.header().parent(block.hash()).build()
|
||||||
|
.transaction().coinbase().build()
|
||||||
|
.transaction()
|
||||||
|
.input().hash(genesis_coinbase.clone()).build()
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let insert_result = store.insert_block(&block);
|
||||||
|
if insert_result.is_ok() { panic!("Insert should fail because of the double-spend"); }
|
||||||
|
|
||||||
|
let _ = insert_result.map_err(|e| {
|
||||||
|
let should_be = ConsistencyError::DoubleSpend(genesis_coinbase);
|
||||||
|
|
||||||
|
if let Error::Consistency(consistency_error) = e {
|
||||||
|
assert_eq!(should_be, consistency_error, "Store should return double spend consistency return");
|
||||||
|
}
|
||||||
|
else { panic!("Insert should fail because of the double-spend"); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fork_route() {
|
fn fork_route() {
|
||||||
let path = RandomTempPath::create_dir();
|
let path = RandomTempPath::create_dir();
|
||||||
|
|
Loading…
Reference in New Issue