Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ impl<'x> OpenBlock<'x> {
parent: &Header,
author: Address,
extra_data: Bytes,
is_epoch_begin: bool,
) -> Result<Self, Error> {
let number = parent.number() + 1;
let state = TopLevelState::from_existing(db, *parent.state_root()).map_err(StateError::from)?;
Expand All @@ -150,8 +149,6 @@ impl<'x> OpenBlock<'x> {
engine.machine().populate_from_parent(&mut r.block.header, parent);
engine.populate_from_parent(&mut r.block.header, parent);

engine.on_new_block(&mut r.block, is_epoch_begin)?;

Ok(r)
}

Expand Down Expand Up @@ -442,9 +439,8 @@ pub fn enact<C: ChainTimeInfo + FindActionHandler>(
client: &C,
db: StateDB,
parent: &Header,
is_epoch_begin: bool,
) -> Result<LockedBlock, Error> {
let mut b = OpenBlock::try_new(engine, db, parent, Address::default(), vec![], is_epoch_begin)?;
let mut b = OpenBlock::try_new(engine, db, parent, Address::default(), vec![])?;

b.populate_from(header);
b.push_transactions(transactions, client, parent.number(), parent.timestamp())?;
Expand All @@ -464,7 +460,7 @@ mod tests {
let scheme = Scheme::new_test();
let genesis_header = scheme.genesis_header();
let db = scheme.ensure_genesis_state(get_temp_state_db()).unwrap();
let b = OpenBlock::try_new(&*scheme.engine, db, &genesis_header, Address::default(), vec![], false).unwrap();
let b = OpenBlock::try_new(&*scheme.engine, db, &genesis_header, Address::default(), vec![]).unwrap();
let parent_transactions_root = *genesis_header.transactions_root();
let b = b.close_and_lock(parent_transactions_root).unwrap();
let _ = b.seal(&*scheme.engine, vec![]);
Expand Down
152 changes: 2 additions & 150 deletions core/src/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::mem;
use std::sync::Arc;

use ctypes::BlockNumber;
Expand All @@ -25,14 +24,13 @@ use rlp::RlpStream;

use super::block_info::BestBlockChanged;
use super::body_db::{BodyDB, BodyProvider};
use super::extras::{BlockDetails, EpochTransitions, TransactionAddress, EPOCH_KEY_PREFIX};
use super::extras::{BlockDetails, TransactionAddress};
use super::headerchain::{HeaderChain, HeaderProvider};
use super::invoice_db::{InvoiceDB, InvoiceProvider};
use super::route::{tree_route, ImportRoute};
use crate::blockchain_info::BlockChainInfo;
use crate::consensus::epoch::Transition as EpochTransition;
use crate::consensus::CodeChainEngine;
use crate::db::{self, Readable, Writable};
use crate::db;
use crate::encoded;
use crate::invoice::Invoice;
use crate::transaction::LocalizedTransaction;
Expand All @@ -54,8 +52,6 @@ pub struct BlockChain {
body_db: BodyDB,
invoice_db: InvoiceDB,

db: Arc<KeyValueDB>,

pending_best_block_hash: RwLock<Option<H256>>,
pending_best_proposal_block_hash: RwLock<Option<H256>>,
}
Expand Down Expand Up @@ -97,8 +93,6 @@ impl BlockChain {
body_db: BodyDB::new(&genesis_block, db.clone()),
invoice_db: InvoiceDB::new(db.clone()),

db,

pending_best_block_hash: RwLock::new(None),
pending_best_proposal_block_hash: RwLock::new(None),
}
Expand Down Expand Up @@ -342,148 +336,6 @@ impl BlockChain {
pub fn best_proposal_header(&self) -> encoded::Header {
self.headerchain.best_proposal_header()
}

/// Insert an epoch transition. Provide an epoch number being transitioned to
/// and epoch transition object.
///
/// The block the transition occurred at should have already been inserted into the chain.
pub fn insert_epoch_transition(&self, batch: &mut DBTransaction, epoch_num: u64, transition: EpochTransition) {
let mut transitions = match self.db.read(db::COL_EXTRA, &epoch_num) {
Some(existing) => existing,
None => EpochTransitions {
number: epoch_num,
candidates: Vec::with_capacity(1),
},
};

// ensure we don't write any duplicates.
if transitions.candidates.iter().find(|c| c.block_hash == transition.block_hash).is_none() {
transitions.candidates.push(transition);
batch.write(db::COL_EXTRA, &epoch_num, &transitions);
}
}

/// Iterate over all epoch transitions.
/// This will only return transitions within the canonical chain.
#[allow(dead_code)]
pub fn epoch_transitions(&self) -> EpochTransitionIter {
let iter = self.db.iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]);
EpochTransitionIter {
chain: self,
prefix_iter: iter,
}
}

/// Get a specific epoch transition by block number and provided block hash.
pub fn epoch_transition(&self, block_num: u64, block_hash: H256) -> Option<EpochTransition> {
ctrace!(BLOCKCHAIN, "Loading epoch transition at block {}, {}", block_num, block_hash);

self.db.read(db::COL_EXTRA, &block_num).and_then(|transitions: EpochTransitions| {
transitions.candidates.into_iter().find(|c| c.block_hash == block_hash)
})
}

/// Get the transition to the epoch the given parent hash is part of
/// or transitions to.
/// This will give the epoch that any children of this parent belong to.
///
/// The block corresponding the the parent hash must be stored already.
#[allow(dead_code)]
pub fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition> {
// slow path: loop back block by block
#[allow(clippy::identity_conversion)]
// This is a false alarm. https://github.com/rust-lang/rust-clippy/issues/3944
for hash in self.ancestry_iter(parent_hash)? {
let details = self.block_details(&hash)?;

// look for transition in database.
if let Some(transition) = self.epoch_transition(details.number, hash) {
return Some(transition)
}

// canonical hash -> fast breakout:
// get the last epoch transition up to this block.
//
// if `block_hash` is canonical it will only return transitions up to
// the parent.
if self.block_hash(details.number)? == hash {
return self.epoch_transitions().map(|(_, t)| t).take_while(|t| t.block_number <= details.number).last()
}
}

// should never happen as the loop will encounter genesis before concluding.
None
}

/// Iterator that lists `first` and then all of `first`'s ancestors, by hash.
#[allow(dead_code)]
pub fn ancestry_iter(&self, first: H256) -> Option<AncestryIter> {
if self.is_known(&first) {
Some(AncestryIter {
current: first,
chain: self,
})
} else {
None
}
}
}

/// An iterator which walks the blockchain towards the genesis.
#[derive(Clone)]
pub struct AncestryIter<'a> {
current: H256,
chain: &'a BlockChain,
}

impl<'a> Iterator for AncestryIter<'a> {
type Item = H256;
fn next(&mut self) -> Option<H256> {
if self.current.is_zero() {
None
} else {
self.chain.block_details(&self.current).map(|details| mem::replace(&mut self.current, details.parent))
}
}
}

type TransitionIterInternal<'a> = Box<Iterator<Item = (Box<[u8]>, Box<[u8]>)> + 'a>;
/// An iterator which walks all epoch transitions.
/// Returns epoch transitions.
#[allow(dead_code)]
pub struct EpochTransitionIter<'a> {
chain: &'a BlockChain,
prefix_iter: TransitionIterInternal<'a>,
}

impl<'a> Iterator for EpochTransitionIter<'a> {
type Item = (u64, EpochTransition);

fn next(&mut self) -> Option<Self::Item> {
loop {
// some epochs never occurred on the main chain.
let (key, val) = self.prefix_iter.next()?;

// iterator may continue beyond values beginning with this
// prefix.
if !key.starts_with(&EPOCH_KEY_PREFIX[..]) {
return None
}

let transitions: EpochTransitions = ::rlp::decode(&val[..]);

// if there are multiple candidates, at most one will be on the
// canon chain.
for transition in transitions.candidates.into_iter() {
let is_in_canon_chain =
self.chain.block_hash(transition.block_number).map_or(false, |hash| hash == transition.block_hash);

if is_in_canon_chain {
return Some((transitions.number, transition))
}
}
}
}
}

/// Interface for querying blocks by hash and by number.
Expand Down
47 changes: 2 additions & 45 deletions core/src/blockchain/extras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::io::Write;
use std::ops::{self, Add, AddAssign, Deref, Sub, SubAssign};
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};

use ctypes::BlockNumber;
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
use primitives::{H256, H264, U256};

use crate::consensus::epoch::Transition as EpochTransition;
use crate::db::Key;
use crate::types::TransactionId;

Expand All @@ -36,8 +33,7 @@ enum ExtrasIndex {
ParcelAddress = 2,
/// Transaction address index
TransactionAddress = 3,
/// Epoch transition data index.
EpochTransitions = 4,
// (Reserved) = 4,
// (Reserved) = 5,
}

Expand Down Expand Up @@ -97,38 +93,6 @@ impl Key<TransactionAddresses> for H256 {
}
}

/// length of epoch keys.
const EPOCH_KEY_LEN: usize = DB_PREFIX_LEN + 16;

/// epoch key prefix.
/// used to iterate over all epoch transitions in order from genesis.
pub const EPOCH_KEY_PREFIX: &[u8; DB_PREFIX_LEN] =
&[ExtrasIndex::EpochTransitions as u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);

impl ops::Deref for EpochTransitionsKey {
type Target = [u8];

fn deref(&self) -> &[u8] {
&self.0[..]
}
}

impl Key<EpochTransitions> for u64 {
type Target = EpochTransitionsKey;

fn key(&self) -> Self::Target {
let mut arr = [0u8; EPOCH_KEY_LEN];
arr[..DB_PREFIX_LEN].copy_from_slice(&EPOCH_KEY_PREFIX[..]);

write!(&mut arr[DB_PREFIX_LEN..], "{:016x}", self)
.expect("format arg is valid; no more than 16 chars will be written; qed");

EpochTransitionsKey(arr)
}
}

/// Familial details concerning a block
#[derive(Debug, Clone, RlpEncodable, RlpDecodable)]
pub struct BlockDetails {
Expand Down Expand Up @@ -161,13 +125,6 @@ pub struct TransactionAddresses {
addresses: Vec<TransactionAddress>,
}

/// Candidate transitions to an epoch with specific number.
#[derive(Clone, RlpEncodable, RlpDecodable)]
pub struct EpochTransitions {
pub number: u64,
pub candidates: Vec<EpochTransition>,
}

impl TransactionAddresses {
pub fn new(address: TransactionAddress) -> Self {
Self {
Expand Down
2 changes: 0 additions & 2 deletions core/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,14 +821,12 @@ impl BlockProducer for Client {
let parent_hash = self.block_hash(&parent_block_id).expect("parent exist always");
let parent_header = chain.block_header(&parent_hash).expect("parent exist always");

let is_epoch_begin = chain.epoch_transition(parent_header.number(), parent_hash).is_some();
OpenBlock::try_new(
engine,
self.state_db.read().clone(&parent_header.state_root()),
&parent_header,
author,
extra_data,
is_epoch_begin,
).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed")
}
}
Expand Down
34 changes: 2 additions & 32 deletions core/src/client/importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ use rlp::Encodable;

use super::{BlockChainTrait, Client, ClientConfig};
use crate::block::{enact, IsBlock, LockedBlock};
use crate::blockchain::{BlockChain, BodyProvider, HeaderProvider, ImportRoute};
use crate::consensus::epoch::Transition as EpochTransition;
use crate::blockchain::{BodyProvider, HeaderProvider, ImportRoute};
use crate::consensus::CodeChainEngine;
use crate::encoded;
use crate::error::Error;
Expand Down Expand Up @@ -207,8 +206,6 @@ impl Importer {
client.db().write_buffered(batch);
chain.commit();

self.check_epoch_end(block.header(), &chain, client);

if hash == chain.best_block_hash() {
let mut state_db = client.state_db().write();
let state = block.state();
Expand All @@ -218,27 +215,6 @@ impl Importer {
route
}

// check for ending of epoch and write transition if it occurs.
fn check_epoch_end(&self, header: &Header, chain: &BlockChain, client: &Client) {
let is_epoch_end = self.engine.is_epoch_end(header, &(|hash| chain.block_header(&hash)));

if let Some(proof) = is_epoch_end {
cdebug!(CLIENT, "Epoch transition at block {}", header.hash());

let mut batch = DBTransaction::new();
chain.insert_epoch_transition(&mut batch, header.number(), EpochTransition {
block_hash: header.hash(),
block_number: header.number(),
proof,
});

// always write the batch directly since epoch transition proofs are
// fetched from a DB iterator and DB iterators are only available on
// flushed data.
client.db().write(batch).expect("DB flush failed");
}
}

fn check_and_close_block(&self, block: &PreverifiedBlock, client: &Client) -> Result<LockedBlock, ()> {
let engine = &*self.engine;
let header = &block.header;
Expand Down Expand Up @@ -304,8 +280,7 @@ impl Importer {
// Enact Verified Block
let db = client.state_db().read().clone(&parent.state_root());

let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some();
let enact_result = enact(&block.header, &block.transactions, engine, client, db, &parent, is_epoch_begin);
let enact_result = enact(&block.header, &block.transactions, engine, client, db, &parent);
let locked_block = enact_result.map_err(|e| {
cwarn!(CLIENT, "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
})?;
Expand Down Expand Up @@ -425,15 +400,10 @@ impl Importer {
let chain = client.block_chain();

let mut batch = DBTransaction::new();
// FIXME: Check if this line is still necessary.
// self.check_epoch_end_signal(header, &chain, &mut batch);
let route = chain.insert_header(&mut batch, &HeaderView::new(&header.rlp_bytes()), self.engine.borrow());
client.db().write_buffered(batch);
chain.commit();

// FIXME: Check if this line is still necessary.
// self.check_epoch_end(&header, &chain, client);

route
}
}
Loading