Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
Problem: client code uses a custom tendermint client (CRO-101)
Browse files Browse the repository at this point in the history
Solution:
- migrate to tendermint-rs library
  • Loading branch information
yihuang committed Nov 13, 2019
1 parent 0655292 commit 21765ee
Show file tree
Hide file tree
Showing 32 changed files with 658 additions and 575 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# IDE
.vscode
.idea
/tags

# TODOR
.todor
Expand Down
246 changes: 246 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client-cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use structopt::StructOpt;
use chain_core::init::coin::Coin;
use chain_core::state::account::StakedStateAddress;
use client_common::storage::SledStorage;
use client_common::tendermint::types::GenesisExt;
use client_common::tendermint::{Client, WebsocketRpcClient};
use client_common::{ErrorKind, Result, ResultExt, Storage};
#[cfg(not(feature = "mock-enc-dec"))]
Expand Down
1 change: 1 addition & 0 deletions client-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jsonrpc = { version = "0.11", optional = true }
serde_json = { version = "1.0", optional = true }
parity-scale-codec = { features = ["derive"], version = "1.0" }
websocket = { version = "0.24", default-features = false, features = ["sync"], optional = true }
tendermint = { git = "https://github.com/crypto-com/tendermint-rs.git", rev = "bb27fdc5dd0ce59767badab246d1d4c203cf3d23" }

[features]
default = ["sled", "websocket-rpc"]
Expand Down
5 changes: 2 additions & 3 deletions client-common/src/block_header.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use chrono::{DateTime, Utc};

use chain_core::tx::data::TxId;
use chain_tx_filter::BlockFilter;

use crate::tendermint::types::Time;
use crate::Transaction;

/// Structure for representing a block header on Crypto.com Chain
Expand All @@ -13,7 +12,7 @@ pub struct BlockHeader {
/// Block height
pub block_height: u64,
/// Block time
pub block_time: DateTime<Utc>,
pub block_time: Time,
/// List of successfully committed transaction ids in this block
pub transaction_ids: Vec<TxId>,
/// Bloom filter for view keys and staking addresses
Expand Down
10 changes: 9 additions & 1 deletion client-common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,15 @@ impl Error {
impl fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.kind, self.message)
write!(
f,
"{}: {}, {}",
self.kind,
self.message,
self.origin
.as_ref()
.map_or("".to_owned(), |err| err.to_string())
)
}
}

Expand Down
5 changes: 2 additions & 3 deletions client-common/src/tendermint/client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::tendermint::types::QueryResult;
use crate::tendermint::types::*;
use crate::Result;

Expand Down Expand Up @@ -26,8 +25,8 @@ pub trait Client: Send + Sync {
) -> Result<Vec<BlockResults>>;

/// Makes `broadcast_tx_sync` call to tendermint
fn broadcast_transaction(&self, transaction: &[u8]) -> Result<BroadcastTxResult>;
fn broadcast_transaction(&self, transaction: &[u8]) -> Result<BroadcastTxResponse>;

/// Makes `abci_query` call to tendermint
fn query(&self, path: &str, data: &[u8]) -> Result<QueryResult>;
fn query(&self, path: &str, data: &[u8]) -> Result<AbciQuery>;
}
40 changes: 26 additions & 14 deletions client-common/src/tendermint/http_rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ impl RpcClient {

impl Client for RpcClient {
fn genesis(&self) -> Result<Genesis> {
self.call("genesis", Default::default())
Ok(self
.call::<GenesisResponse>("genesis", Default::default())?
.genesis)
}

fn status(&self) -> Result<Status> {
Expand All @@ -115,18 +117,20 @@ impl Client for RpcClient {

fn block(&self, height: u64) -> Result<Block> {
let params = [json!(height.to_string())];
self.call("block", &params)
Ok(self.call::<BlockResponse>("block", &params)?.block)
}

fn block_batch<'a, T: Iterator<Item = &'a u64>>(&self, heights: T) -> Result<Vec<Block>> {
let params = heights
.map(|height| ("block", vec![json!(height.to_string())]))
.collect::<Vec<(&str, Vec<Value>)>>();
let response = self.call_batch::<Block>(&params)?;

response
.into_iter()
.map(|block| block.chain(|| (ErrorKind::InvalidInput, "Block information not found")))
let mut rsps = self.call_batch::<BlockResponse>(&params)?;
rsps.drain(..)
.map(|rsp| {
rsp.chain(|| (ErrorKind::InvalidInput, "Block information not found"))
.map(|rsp_| rsp_.block)
})
.collect::<Result<Vec<Block>>>()
}

Expand Down Expand Up @@ -157,29 +161,37 @@ impl Client for RpcClient {
.collect::<Result<Vec<BlockResults>>>()
}

fn broadcast_transaction(&self, transaction: &[u8]) -> Result<BroadcastTxResult> {
fn broadcast_transaction(&self, transaction: &[u8]) -> Result<BroadcastTxResponse> {
let params = [json!(transaction)];
self.call::<BroadcastTxResult>("broadcast_tx_sync", &params)
self.call::<BroadcastTxResponse>("broadcast_tx_sync", &params)
.and_then(|result| {
if result.code != 0 {
Err(Error::new(ErrorKind::TendermintRpcError, result.log))
if result.code.is_err() {
Err(Error::new(
ErrorKind::TendermintRpcError,
result.log.to_string(),
))
} else {
Ok(result)
}
})
}

fn query(&self, path: &str, data: &[u8]) -> Result<QueryResult> {
fn query(&self, path: &str, data: &[u8]) -> Result<AbciQuery> {
let params = [
json!(path),
json!(hex::encode(data)),
json!(null),
json!(null),
];
let result = self.call::<QueryResult>("abci_query", &params)?;
let result = self
.call::<AbciQueryResponse>("abci_query", &params)?
.response;

if result.code() != 0 {
return Err(Error::new(ErrorKind::TendermintRpcError, result.log()));
if result.code.is_err() {
return Err(Error::new(
ErrorKind::TendermintRpcError,
result.log.to_string(),
));
}

Ok(result)
Expand Down
109 changes: 97 additions & 12 deletions client-common/src/tendermint/types.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,98 @@
//! Structures used in Tendermint RPC (auto-generated)
mod block;
//! Structures used in Tendermint RPC
mod block_results;
mod broadcast_tx_result;
mod genesis;
mod query;
mod status;
pub use block::*;
pub use block_results::*;
pub use broadcast_tx_result::*;
pub use genesis::*;
pub use query::*;
pub use status::*;
pub mod mock;

use base64::decode;
use parity_scale_codec::Decode;
use serde::{Deserialize, Serialize};

use crate::{ErrorKind, Result, ResultExt, Transaction};
use chain_core::init::config::InitConfig;
use chain_core::tx::fee::LinearFee;
use chain_core::tx::{TxAux, TxEnclaveAux};

pub use self::block_results::*;
pub use tendermint::rpc::endpoint::{
abci_query::AbciQuery, abci_query::Response as AbciQueryResponse,
block::Response as BlockResponse, broadcast::tx_sync::Response as BroadcastTxResponse,
status::Response as Status,
};
pub use tendermint::rpc::endpoint::{broadcast, status};
pub use tendermint::{
abci, abci::transaction::Data, abci::Code, block::Header, block::Height, Block,
Genesis as GenericGenesis, Hash, Time,
};

/// crypto-com instantiated genesis type
pub type Genesis = GenericGenesis<InitConfig>;

/// crypto-com instantiated genesis type
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GenesisResponse {
/// Genesis data
pub genesis: Genesis,
}

/// crypto-chain specific methods.
pub trait BlockExt {
/// Returns un-encrypted transactions in a block (this may also contain invalid transactions)
fn unencrypted_transactions(&self) -> Result<Vec<Transaction>>;
}

impl BlockExt for Block {
/// NOTE: Un-encrypted transactions only contain deposit stake and unbond stake transactions
fn unencrypted_transactions(&self) -> Result<Vec<Transaction>> {
self.data
.iter()
.map(|raw| -> Result<TxAux> {
TxAux::decode(&mut raw.clone().into_vec().as_slice()).chain(|| {
(
ErrorKind::DeserializationError,
"Unable to decode transactions from bytes in a block",
)
})
})
.filter_map(|tx_aux_result| match tx_aux_result {
Err(e) => Some(Err(e)),
Ok(tx_aux) => match tx_aux {
TxAux::EnclaveTx(TxEnclaveAux::DepositStakeTx { tx, .. }) => {
Some(Ok(Transaction::DepositStakeTransaction(tx)))
}
TxAux::UnbondStakeTx(tx, _) => {
Some(Ok(Transaction::UnbondStakeTransaction(tx)))
}
_ => None,
},
})
.collect::<Result<Vec<Transaction>>>()
}
}

/// crypto-chain specific methods.
pub trait GenesisExt {
/// get fee policy
fn fee_policy(&self) -> LinearFee;
}

impl GenesisExt for Genesis {
fn fee_policy(&self) -> LinearFee {
self.app_state.network_params.initial_fee_policy
}
}

/// crypto-chain specific methods.
pub trait AbciQueryExt {
/// decode query result with base64
fn bytes(&self) -> Result<Vec<u8>>;
}

impl AbciQueryExt for AbciQuery {
fn bytes(&self) -> Result<Vec<u8>> {
Ok(decode(&self.value).chain(|| {
(
ErrorKind::DeserializationError,
"Unable to decode base64 bytes on query result",
)
})?)
}
}
Loading

0 comments on commit 21765ee

Please sign in to comment.