Skip to content

Commit

Permalink
Merge pull request #2981 from input-output-hk/add-tracking-tips-explo…
Browse files Browse the repository at this point in the history
…rer-multiverse

Add tracking tips explorer multiverse
  • Loading branch information
Mikhail Zabaluev authored Feb 8, 2021
2 parents 55f80fd + fead9eb commit 0fb223f
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 216 deletions.
54 changes: 22 additions & 32 deletions jormungandr/src/explorer/error.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
use crate::blockcfg::HeaderHash;
use crate::{blockchain::StorageError, intercom};
use thiserror::Error;

error_chain! {
foreign_links {
StorageError(StorageError);
// FIXME: fold into StorageError with more generic work in intercom streaming
StreamingError(intercom::Error);
}
errors {
BlockNotFound(hash: String) {
description("block not found"),
display("block '{}' cannot be found in the explorer", hash)
}
AncestorNotFound(hash: String) {
description("ancestor of block is not in explorer"),
display("ancestor of block '{}' cannot be found in the explorer", hash)
}
TransactionAlreadyExists(id: String) {
description("tried to index already existing transaction")
display("transaction '{}' is already indexed", id)
}
BlockAlreadyExists(id: String) {
description("tried to index already indexed block")
display("block '{}' is already indexed", id)
}
ChainLengthBlockAlreadyExists(chain_length: u32) {
description("tried to index already indexed chainlength in the given branch")
display("chain length: {} is already indexed", chain_length)
}
BootstrapError(msg: String) {
description("failed to initialize explorer's database from storage")
display("the explorer's database couldn't be initialized: {}", msg)
}
}
#[derive(Debug, Error)]
pub enum ExplorerError {
#[error("block {0} not found in explorer")]
BlockNotFound(HeaderHash),
#[error("ancestor of block '{0}' not found in explorer")]
AncestorNotFound(HeaderHash),
#[error("transaction '{0}' is already indexed")]
TransactionAlreadyExists(crate::blockcfg::FragmentId),
#[error("tried to index block '{0}' twice")]
BlockAlreadyExists(HeaderHash),
#[error("block with {0} chain length already exists in explorer branch")]
ChainLengthBlockAlreadyExists(crate::blockcfg::ChainLength),
#[error("the explorer's database couldn't be initialized: {0}")]
BootstrapError(String),
#[error("storage error")]
StorageError(#[from] StorageError),
#[error("streaming error")]
StreamingError(#[from] intercom::Error),
}

pub type Result<T> = std::result::Result<T, ExplorerError>;
73 changes: 48 additions & 25 deletions jormungandr/src/explorer/graphql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub use juniper::http::GraphQLRequest;
use juniper::{EmptyMutation, EmptySubscription, FieldResult, GraphQLUnion, RootNode};
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use std::sync::Arc;

#[derive(Clone)]
pub struct Block {
Expand All @@ -47,7 +48,7 @@ impl Block {
Block { hash }
}

async fn get_explorer_block(&self, db: &ExplorerDB) -> FieldResult<ExplorerBlock> {
async fn get_explorer_block(&self, db: &ExplorerDB) -> FieldResult<Arc<ExplorerBlock>> {
db.get_block(&self.hash).await.ok_or_else(|| {
ErrorKind::InternalError("Couldn't find block's contents in explorer".to_owned()).into()
})
Expand Down Expand Up @@ -216,8 +217,8 @@ enum Leader {
BftLeader(BftLeader),
}

impl From<&ExplorerBlock> for Block {
fn from(block: &ExplorerBlock) -> Block {
impl From<Arc<ExplorerBlock>> for Block {
fn from(block: Arc<ExplorerBlock>) -> Block {
Block::from_valid_hash(block.id())
}
}
Expand Down Expand Up @@ -262,8 +263,11 @@ impl Transaction {
async fn from_id(id: FragmentId, context: &Context) -> FieldResult<Transaction> {
let block_hash = context
.db
.find_block_hash_by_transaction(&id)
.get_main_tip()
.await
.1
.state()
.find_block_hash_by_transaction(&id)
.ok_or_else(|| ErrorKind::NotFound(format!("transaction not found: {}", &id,)))?;

Ok(Transaction {
Expand All @@ -289,13 +293,16 @@ impl Transaction {
}
}

async fn get_block(&self, context: &Context) -> FieldResult<ExplorerBlock> {
async fn get_block(&self, context: &Context) -> FieldResult<Arc<ExplorerBlock>> {
let block_id = match self.block_hash {
Some(block_id) => block_id,
None => context
.db
.find_block_hash_by_transaction(&self.id)
.get_main_tip()
.await
.1
.state()
.find_block_hash_by_transaction(&self.id)
.ok_or_else(|| {
ErrorKind::InternalError("Transaction's block was not found".to_owned())
})?,
Expand Down Expand Up @@ -340,7 +347,7 @@ impl Transaction {
/// The block this transaction is in
pub async fn block(&self, context: &Context) -> FieldResult<Block> {
let block = self.get_block(context).await?;
Ok(Block::from(&block))
Ok(Block::from(block))
}

pub async fn inputs(&self, context: &Context) -> FieldResult<Vec<TransactionInput>> {
Expand Down Expand Up @@ -467,8 +474,11 @@ impl Address {
) -> FieldResult<TransactionConnection> {
let transactions = context
.db
.get_transactions_by_address(&self.id)
.get_main_tip()
.await
.1
.state()
.transactions_by_address(&self.id)
.unwrap_or_else(PersistentSequence::<FragmentId>::new);

let boundaries = if transactions.len() > 0 {
Expand Down Expand Up @@ -564,8 +574,8 @@ impl Proposal {
#[derive(Clone)]
pub struct Pool {
id: certificate::PoolId,
data: Option<StakePoolData>,
blocks: Option<PersistentSequence<HeaderHash>>,
data: Option<Arc<StakePoolData>>,
blocks: Option<Arc<PersistentSequence<HeaderHash>>>,
}

impl Pool {
Expand Down Expand Up @@ -596,7 +606,7 @@ impl Pool {
}
}

fn new_with_data(id: certificate::PoolId, data: StakePoolData) -> Self {
fn new_with_data(id: certificate::PoolId, data: Arc<StakePoolData>) -> Self {
Pool {
id,
blocks: None,
Expand Down Expand Up @@ -669,7 +679,7 @@ impl Pool {
.db
.get_stake_pool_data(&self.id)
.await
.map(|data| PoolRegistration::from(data.registration))
.map(|data| PoolRegistration::from(data.registration.clone()))
.ok_or_else(|| ErrorKind::NotFound("Stake pool not found".to_owned()).into()),
}
}
Expand All @@ -682,7 +692,11 @@ impl Pool {
.get_stake_pool_data(&self.id)
.await
.ok_or_else(|| ErrorKind::NotFound("Stake pool not found".to_owned()).into())
.map(|data| data.retirement.map(PoolRetirement::from)),
.map(|data| {
data.retirement
.as_ref()
.map(|r| PoolRetirement::from(r.clone()))
}),
}
}
}
Expand All @@ -699,7 +713,7 @@ impl Status {
}

pub async fn latest_block(&self, context: &Context) -> FieldResult<Block> {
latest_block(context).await.map(|b| Block::from(&b))
latest_block(context).await.map(Block::from)
}

pub async fn epoch_stability_depth(&self, context: &Context) -> String {
Expand Down Expand Up @@ -873,11 +887,14 @@ impl Epoch {
PaginationInterval::Empty => unreachable!("No blocks found (not even genesis)"),
PaginationInterval::Inclusive(range) => context
.db
.get_main_tip()
.await
.1
.state()
.get_block_hash_range(
(range.lower_bound + epoch_lower_bound).into(),
(range.upper_bound + epoch_lower_bound + 1).into(),
)
.await
.iter()
.map(|(hash, index)| (*hash, u32::from(*index) - epoch_lower_bound))
.collect(),
Expand Down Expand Up @@ -1053,15 +1070,15 @@ impl VotePlanStatus {
.into())
}

pub fn vote_plan_from_data(vote_plan: super::indexing::ExplorerVotePlan) -> Self {
pub fn vote_plan_from_data(vote_plan: Arc<super::indexing::ExplorerVotePlan>) -> Self {
let super::indexing::ExplorerVotePlan {
id,
vote_start,
vote_end,
committee_end,
payload_type,
proposals,
} = vote_plan;
} = (*vote_plan).clone();

VotePlanStatus {
id: VotePlanId::from(id),
Expand Down Expand Up @@ -1249,8 +1266,11 @@ impl Query {
) -> FieldResult<Option<Block>> {
Ok(context
.db
.find_block_by_chain_length(length.try_into()?)
.get_main_tip()
.await
.1
.state()
.find_block_by_chain_length(length.try_into()?)
.map(Block::from_valid_hash))
}

Expand Down Expand Up @@ -1288,8 +1308,11 @@ impl Query {
let b = range.upper_bound.checked_add(1).unwrap().into();
context
.db
.get_block_hash_range(a, b)
.get_main_tip()
.await
.1
.state()
.get_block_hash_range(a, b)
.iter_mut()
.map(|(hash, chain_length)| (*hash, u32::from(*chain_length)))
.collect()
Expand Down Expand Up @@ -1325,7 +1348,7 @@ impl Query {
after: Option<IndexCursor>,
context: &Context,
) -> FieldResult<PoolConnection> {
let mut stake_pools = context.db.get_stake_pools().await;
let mut stake_pools = context.db.get_main_tip().await.1.state().get_stake_pools();

// Although it's probably not a big performance concern
// There are a few alternatives to not have to sort this
Expand Down Expand Up @@ -1368,7 +1391,7 @@ impl Query {
(
Pool::new_with_data(
certificate::PoolId::clone(pool_id),
StakePoolData::clone(stake_pool_data),
Arc::clone(stake_pool_data),
),
i,
)
Expand All @@ -1394,7 +1417,7 @@ impl Query {
after: Option<IndexCursor>,
context: &Context,
) -> FieldResult<VotePlanConnection> {
let mut vote_plans = context.db.get_vote_plans().await;
let mut vote_plans = context.db.get_main_tip().await.1.state().get_vote_plans();

vote_plans.sort_unstable_by_key(|(id, _data)| id.clone());

Expand Down Expand Up @@ -1430,7 +1453,7 @@ impl Query {
.map(|i: u32| {
let (_pool_id, vote_plan_data) = &vote_plans[usize::try_from(i).unwrap()];
(
VotePlanStatus::vote_plan_from_data(vote_plan_data.as_ref().clone()),
VotePlanStatus::vote_plan_from_data(Arc::clone(vote_plan_data)),
i,
)
})
Expand All @@ -1453,9 +1476,9 @@ pub fn create_schema() -> Schema {
Schema::new(Query {}, EmptyMutation::new(), EmptySubscription::new())
}

async fn latest_block(context: &Context) -> FieldResult<ExplorerBlock> {
async fn latest_block(context: &Context) -> FieldResult<Arc<ExplorerBlock>> {
async {
let hash = context.db.get_latest_block_hash().await;
let hash = context.db.get_main_tip().await.0;
context.db.get_block(&hash).await
}
.await
Expand Down
Loading

0 comments on commit 0fb223f

Please sign in to comment.