expected nbits method & support

This commit is contained in:
NikVolf 2016-11-22 18:26:00 +03:00
parent 29a3e91304
commit 34a582b8e9
4 changed files with 53 additions and 1 deletions

View File

@ -14,6 +14,9 @@ pub trait BlockProvider {
/// resolves header bytes by block reference (number/hash) /// resolves header bytes by block reference (number/hash)
fn block_header_bytes(&self, block_ref: BlockRef) -> Option<Bytes>; fn block_header_bytes(&self, block_ref: BlockRef) -> Option<Bytes>;
/// resolves header bytes by block reference (number/hash)
fn block_header(&self, block_ref: BlockRef) -> Option<chain::BlockHeader>;
/// resolves deserialized block body by block reference (number/hash) /// resolves deserialized block body by block reference (number/hash)
fn block(&self, block_ref: BlockRef) -> Option<chain::Block>; fn block(&self, block_ref: BlockRef) -> Option<chain::Block>;

View File

@ -40,6 +40,9 @@ const MAX_FORK_ROUTE_PRESET: usize = 128;
pub trait Store : BlockProvider + BlockStapler + TransactionProvider + TransactionMetaProvider { pub trait Store : BlockProvider + BlockStapler + TransactionProvider + TransactionMetaProvider {
/// get best block /// get best block
fn best_block(&self) -> Option<BestBlock>; fn best_block(&self) -> Option<BestBlock>;
/// get best header
fn best_header(&self) -> Option<chain::BlockHeader>;
} }
/// Blockchain storage with rocksdb database /// Blockchain storage with rocksdb database
@ -165,7 +168,6 @@ impl Storage {
}) })
} }
/// update transactions metadata in the specified database transaction /// update transactions metadata in the specified database transaction
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &[chain::Transaction]) fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &[chain::Transaction])
-> Result<(), Error> -> Result<(), Error>
@ -385,6 +387,12 @@ impl BlockProvider for Storage {
self.resolve_hash(block_ref).and_then(|h| self.get(COL_BLOCK_HEADERS, &*h)) self.resolve_hash(block_ref).and_then(|h| self.get(COL_BLOCK_HEADERS, &*h))
} }
fn block_header(&self, block_ref: BlockRef) -> Option<chain::BlockHeader> {
self.block_header_bytes(block_ref).map(
|bytes| deserialize::<_, chain::BlockHeader>(bytes.as_ref())
.expect("Error deserializing header, possible db corruption"))
}
fn block_transaction_hashes(&self, block_ref: BlockRef) -> Vec<H256> { fn block_transaction_hashes(&self, block_ref: BlockRef) -> Vec<H256> {
self.resolve_hash(block_ref) self.resolve_hash(block_ref)
.map(|h| self.block_transaction_hashes_by_hash(&h)) .map(|h| self.block_transaction_hashes_by_hash(&h))
@ -596,6 +604,12 @@ impl Store for Storage {
fn best_block(&self) -> Option<BestBlock> { fn best_block(&self) -> Option<BestBlock> {
self.best_block.read().clone() self.best_block.read().clone()
} }
fn best_header(&self) -> Option<chain::BlockHeader> {
self.best_block.read().as_ref().and_then(
|bb| Some(self.block_header_by_hash(&bb.hash).expect("Best block exists but no such header. Race condition?")),
)
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -81,6 +81,13 @@ impl BlockProvider for TestStorage {
.map(|ref block| serialization::serialize(block.header())) .map(|ref block| serialization::serialize(block.header()))
} }
fn block_header(&self, block_ref: BlockRef) -> Option<chain::BlockHeader> {
let data = self.data.read();
self.resolve_hash(block_ref)
.and_then(|ref h| data.blocks.get(h))
.map(|ref block| block.header().clone())
}
fn block_transaction_hashes(&self, block_ref: BlockRef) -> Vec<H256> { fn block_transaction_hashes(&self, block_ref: BlockRef) -> Vec<H256> {
let data = self.data.read(); let data = self.data.read();
self.resolve_hash(block_ref) self.resolve_hash(block_ref)
@ -174,5 +181,11 @@ impl Store for TestStorage {
fn best_block(&self) -> Option<BestBlock> { fn best_block(&self) -> Option<BestBlock> {
self.data.read().best_block.clone() self.data.read().best_block.clone()
} }
fn best_header(&self) -> Option<chain::BlockHeader> {
self.data.read().best_block.as_ref().and_then(
|bb| Some(self.block_header(BlockRef::Hash(bb.hash.clone())).expect("Best block exists but no such header. Race condition?"))
)
}
} }

View File

@ -54,6 +54,12 @@ impl ChainVerifier {
} }
fn ordered_verify(&self, block: &chain::Block, at_height: u32) -> Result<(), Error> { fn ordered_verify(&self, block: &chain::Block, at_height: u32) -> Result<(), Error> {
// check that difficulty matches the adjusted level
if let Some(expected_nbits) = self.expected_nbits() {
if !self.skip_pow && expected_nbits != block.header().nbits {
return Err(Error::Difficulty);
}
}
let coinbase_spends = block.transactions()[0].total_spends(); let coinbase_spends = block.transactions()[0].total_spends();
@ -258,6 +264,22 @@ impl ChainVerifier {
}, },
} }
} }
fn expected_nbits(&self) -> Option<u32> {
let best_header = match self.store.best_header() {
Some(bb) => bb,
None => { return None; }
};
if self.store.best_block().expect("At least genesis should exist at this point").number < 2016 {
return Some(best_header.nbits);
}
// todo: calculate difficulty adjustment
Some(best_header.nbits)
}
} }
impl Verify for ChainVerifier { impl Verify for ChainVerifier {