use chrono::{DateTime, Utc};
use exonum::{
blockchain::{Block, CallProof},
crypto::Hash,
helpers::Height,
merkledb::BinaryValue,
messages::{Precommit, Verified},
runtime::{AnyTx, CallInfo, ExecutionStatus, InstanceId},
};
use serde_derive::{Deserialize, Serialize};
use std::ops::Range;
use crate::median_precommits_time;
pub mod websocket;
pub const MAX_BLOCKS_PER_REQUEST: usize = 1000;
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct BlocksRange {
pub range: Range<Height>,
pub blocks: Vec<BlockInfo>,
}
impl BlocksRange {
#[doc(hidden)] pub fn new(range: Range<Height>, blocks: Vec<BlockInfo>) -> Self {
Self { range, blocks }
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct TxInfo {
pub tx_hash: Hash,
pub call_info: CallInfo,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct BlockInfo {
#[serde(flatten)]
pub block: Block,
#[serde(skip_serializing_if = "Option::is_none")]
pub precommits: Option<Vec<Verified<Precommit>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub txs: Option<Vec<TxInfo>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time: Option<DateTime<Utc>>,
}
impl From<crate::BlockInfo<'_>> for BlockInfo {
fn from(inner: crate::BlockInfo<'_>) -> Self {
Self {
block: inner.header().clone(),
precommits: Some(inner.precommits().to_vec()),
txs: Some(
inner
.transaction_hashes()
.iter()
.enumerate()
.map(|(idx, &tx_hash)| TxInfo {
tx_hash,
call_info: inner
.transaction(idx)
.unwrap()
.message()
.payload()
.call_info
.clone(),
})
.collect(),
),
time: Some(median_precommits_time(&inner.precommits())),
}
}
}
impl BlockInfo {
#[doc(hidden)] pub fn summary(block: crate::BlockInfo<'_>, query: &BlocksQuery) -> Self {
BlockInfo {
txs: None,
time: if query.add_blocks_time {
Some(median_precommits_time(&block.precommits()))
} else {
None
},
precommits: if query.add_precommits {
Some(block.precommits().to_vec())
} else {
None
},
block: block.into_header(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[non_exhaustive]
pub struct BlocksQuery {
pub count: usize,
pub latest: Option<Height>,
pub earliest: Option<Height>,
#[serde(default)]
pub skip_empty_blocks: bool,
#[serde(default)]
pub add_blocks_time: bool,
#[serde(default)]
pub add_precommits: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct BlockQuery {
pub height: Height,
}
impl BlockQuery {
pub fn new(height: Height) -> Self {
Self { height }
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct TransactionHex {
pub tx_body: String,
}
impl TransactionHex {
pub fn new(transaction: &Verified<AnyTx>) -> Self {
Self {
tx_body: hex::encode(transaction.to_bytes()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct TransactionResponse {
pub tx_hash: Hash,
}
impl TransactionResponse {
pub fn new(tx_hash: Hash) -> Self {
Self { tx_hash }
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct TransactionQuery {
pub hash: Hash,
}
impl TransactionQuery {
pub fn new(hash: Hash) -> Self {
Self { hash }
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[non_exhaustive]
pub struct TransactionStatusQuery {
pub hash: Hash,
#[serde(default)]
pub with_proof: bool,
}
impl TransactionStatusQuery {
pub fn new(hash: Hash) -> Self {
Self {
hash,
with_proof: false,
}
}
pub fn with_proof(mut self) -> Self {
self.with_proof = true;
self
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[non_exhaustive]
pub struct CallStatusQuery {
pub height: Height,
pub service_id: InstanceId,
#[serde(default)]
pub with_proof: bool,
}
impl CallStatusQuery {
pub fn new(height: Height, service_id: InstanceId) -> Self {
Self {
height,
service_id,
with_proof: false,
}
}
pub fn with_proof(mut self) -> Self {
self.with_proof = true;
self
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum CallStatusResponse {
Simple(ExecutionStatus),
Proof(CallProof),
}