Skip to content

Commit

Permalink
Revap subcoin RPC
Browse files Browse the repository at this point in the history
  • Loading branch information
liuchengxu committed Sep 20, 2024
1 parent 67be29c commit 6cc5dbe
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 77 deletions.
14 changes: 6 additions & 8 deletions crates/subcoin-node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ pub fn gen_rpc_module(
use sc_rpc::chain::ChainApiServer;
use sc_rpc::state::{ChildStateApiServer, StateApiServer};
use sc_rpc::system::SystemApiServer;
use subcoin_rpc::blockchain::{Blockchain, BlockchainApiServer};
use subcoin_rpc::subcoin::{Subcoin, SubcoinApiServer};

let mut module = RpcModule::new(());

Expand All @@ -46,12 +44,12 @@ pub fn gen_rpc_module(
// module.merge(frame_system).map_err(into_service_error)?;

// Subcoin RPCs.
let blockchain =
Blockchain::<_, _, subcoin_service::TransactionAdapter>::new(client.clone()).into_rpc();
let subcoin = Subcoin::new(client.clone(), network_handle).into_rpc();

module.merge(blockchain).map_err(into_service_error)?;
module.merge(subcoin).map_err(into_service_error)?;
subcoin_rpc::SubcoinRpc::<_, _, subcoin_service::TransactionAdapter>::new(
client.clone(),
network_handle,
)
.merge_into(&mut module)
.map_err(into_service_error)?;

Ok(module)
}
3 changes: 0 additions & 3 deletions crates/subcoin-rpc/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ use bitcoin::consensus::encode::FromHexError;
use jsonrpsee::types::error::ErrorObject;
use jsonrpsee::types::ErrorObjectOwned;

/// Chain RPC Result type.
pub type Result<T> = std::result::Result<T, Error>;

/// Chain RPC errors.
#[derive(Debug, thiserror::Error)]
pub enum Error {
Expand Down
60 changes: 57 additions & 3 deletions crates/subcoin-rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
pub mod blockchain;
pub mod error;
pub mod subcoin;
mod blockchain;
mod error;
mod network;
mod raw_transactions;

use blockchain::{Blockchain, BlockchainApiServer};
use network::{Network, NetworkApiServer};
use raw_transactions::{RawTransactions, RawTransactionsApiServer};
use sc_client_api::{AuxStore, BlockBackend, HeaderBackend};
use sp_runtime::traits::Block as BlockT;
use std::sync::Arc;
use subcoin_network::NetworkHandle;
use subcoin_primitives::BitcoinTransactionAdapter;

/// Subcoin RPC.
pub struct SubcoinRpc<Block, Client, TransactionAdapter> {
/// Blockchain RPC.
pub blockchain: Blockchain<Block, Client, TransactionAdapter>,
/// Raw transactions RPC.
pub raw_transactions: RawTransactions<Block, Client>,
/// Network RPC.
pub network: Network<Block, Client>,
}

impl<Block, Client, TransactionAdapter> SubcoinRpc<Block, Client, TransactionAdapter>
where
Block: BlockT + 'static,
Client: HeaderBackend<Block> + BlockBackend<Block> + AuxStore + 'static,
TransactionAdapter: BitcoinTransactionAdapter<Block> + Send + Sync + 'static,
{
/// Creates a new instance of [`SubcoinRpc`].
pub fn new(client: Arc<Client>, network_handle: NetworkHandle) -> Self {
Self {
blockchain: Blockchain::<_, _, TransactionAdapter>::new(client.clone()),
raw_transactions: RawTransactions::new(client.clone(), network_handle.clone()),
network: Network::new(client, network_handle),
}
}

/// Merges the entire Subcoin RPCs into the given RPC module.
pub fn merge_into(
self,
module: &mut jsonrpsee::Methods,
) -> Result<(), jsonrpsee::server::RegisterMethodError> {
let Self {
blockchain,
raw_transactions,
network,
} = self;

module.merge(blockchain.into_rpc())?;
module.merge(raw_transactions.into_rpc())?;
module.merge(network.into_rpc())?;

Ok(())
}
}
91 changes: 91 additions & 0 deletions crates/subcoin-rpc/src/network.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use crate::error::Error;
use jsonrpsee::proc_macros::rpc;
use sc_client_api::{AuxStore, BlockBackend, HeaderBackend};
use serde::{Deserialize, Serialize};
use sp_runtime::traits::Block as BlockT;
use std::marker::PhantomData;
use std::sync::Arc;
use subcoin_network::{NetworkHandle, NetworkStatus, PeerSync, PeerSyncState};

#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NetworkPeers {
total: usize,
available: usize,
discouraged: usize,
peer_best: Option<u32>,
sync_peers: Vec<PeerSync>,
}

#[rpc(client, server)]
pub trait NetworkApi {
/// Get overall network status.
#[method(name = "network_status")]
async fn network_status(&self) -> Result<Option<NetworkStatus>, Error>;

/// Get the sync peers.
#[method(name = "network_peers")]
async fn network_peers(&self) -> Result<NetworkPeers, Error>;
}

/// This struct provides the Network API.
pub struct Network<Block, Client> {
#[allow(unused)]
client: Arc<Client>,
network_handle: NetworkHandle,
_phantom: PhantomData<Block>,
}

impl<Block, Client> Network<Block, Client>
where
Block: BlockT + 'static,
Client: HeaderBackend<Block> + BlockBackend<Block> + AuxStore + 'static,
{
/// Constructs a new instance of [`Network`].
pub fn new(client: Arc<Client>, network_handle: NetworkHandle) -> Self {
Self {
client,
network_handle,
_phantom: Default::default(),
}
}
}

#[async_trait::async_trait]
impl<Block, Client> NetworkApiServer for Network<Block, Client>
where
Block: BlockT + 'static,
Client: HeaderBackend<Block> + BlockBackend<Block> + AuxStore + 'static,
{
async fn network_peers(&self) -> Result<NetworkPeers, Error> {
let sync_peers = self.network_handle.sync_peers().await;
let total = sync_peers.len();
let mut available = 0;
let mut discouraged = 0;
let mut peer_best = 0;

for peer in &sync_peers {
match peer.state {
PeerSyncState::Available => available += 1,
PeerSyncState::Discouraged => discouraged += 1,
_ => {}
}

if peer.best_number > peer_best {
peer_best = peer.best_number;
}
}

Ok(NetworkPeers {
total,
available,
discouraged,
peer_best: if peer_best > 0 { Some(peer_best) } else { None },
sync_peers,
})
}

async fn network_status(&self) -> Result<Option<NetworkStatus>, Error> {
Ok(self.network_handle.status().await)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,48 @@ use bitcoin::consensus::encode::{deserialize_hex, serialize_hex};
use bitcoin::{Transaction, Txid};
use jsonrpsee::proc_macros::rpc;
use sc_client_api::{AuxStore, BlockBackend, HeaderBackend};
use serde::{Deserialize, Serialize};
use sp_runtime::traits::Block as BlockT;
use std::marker::PhantomData;
use std::sync::Arc;
use subcoin_network::{
NetworkHandle, NetworkStatus, PeerSync, PeerSyncState, SendTransactionResult,
};

#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NetworkPeers {
total: usize,
available: usize,
discouraged: usize,
peer_best: Option<u32>,
sync_peers: Vec<PeerSync>,
}
use subcoin_network::{NetworkHandle, SendTransactionResult};

#[rpc(client, server)]
pub trait SubcoinApi {
pub trait RawTransactionsApi {
/// Returns a JSON object representing the serialized, hex-encoded transaction.
///
/// # Arguments
///
/// - `raw_tx`: The transaction hex string.
#[method(name = "subcoin_decodeRawTransaction", blocking)]
#[method(name = "rawtx_decodeRawTransaction", blocking)]
fn decode_raw_transaction(&self, raw_tx: String) -> Result<serde_json::Value, Error>;

/// Returns the raw transaction data for given txid.
#[method(name = "subcoin_getRawTransaction")]
#[method(name = "rawtx_getRawTransaction")]
async fn get_raw_transaction(&self, txid: Txid) -> Result<Option<String>, Error>;

/// Get overall network status.
#[method(name = "subcoin_networkStatus")]
async fn network_status(&self) -> Result<Option<NetworkStatus>, Error>;

/// Get the sync peers.
#[method(name = "subcoin_networkPeers")]
async fn network_peers(&self) -> Result<NetworkPeers, Error>;

/// Submits a raw transaction (serialized, hex-encoded) to local node and network.
///
/// # Arguments
///
/// - `raw_tx`: The hex string of the raw transaction.
#[method(name = "subcoin_sendRawTransaction")]
#[method(name = "rawtx_sendRawTransaction")]
async fn send_raw_transaction(&self, raw_tx: String) -> Result<SendTransactionResult, Error>;
}

/// This struct provides the Subcoin API.
pub struct Subcoin<Block, Client> {
/// This struct provides the RawTransactions API.
pub struct RawTransactions<Block, Client> {
#[allow(unused)]
client: Arc<Client>,
network_handle: NetworkHandle,
_phantom: PhantomData<Block>,
}

impl<Block, Client> Subcoin<Block, Client>
impl<Block, Client> RawTransactions<Block, Client>
where
Block: BlockT + 'static,
Client: HeaderBackend<Block> + BlockBackend<Block> + AuxStore + 'static,
{
/// Constructs a new instance of [`Subcoin`].
/// Constructs a new instance of [`RawTransactions`].
pub fn new(client: Arc<Client>, network_handle: NetworkHandle) -> Self {
Self {
client,
Expand All @@ -76,7 +55,7 @@ where
}

#[async_trait::async_trait]
impl<Block, Client> SubcoinApiServer for Subcoin<Block, Client>
impl<Block, Client> RawTransactionsApiServer for RawTransactions<Block, Client>
where
Block: BlockT + 'static,
Client: HeaderBackend<Block> + BlockBackend<Block> + AuxStore + 'static,
Expand All @@ -91,38 +70,6 @@ where
Ok(maybe_transaction.as_ref().map(serialize_hex))
}

async fn network_peers(&self) -> Result<NetworkPeers, Error> {
let sync_peers = self.network_handle.sync_peers().await;
let total = sync_peers.len();
let mut available = 0;
let mut discouraged = 0;
let mut peer_best = 0;

for peer in &sync_peers {
match peer.state {
PeerSyncState::Available => available += 1,
PeerSyncState::Discouraged => discouraged += 1,
_ => {}
}

if peer.best_number > peer_best {
peer_best = peer.best_number;
}
}

Ok(NetworkPeers {
total,
available,
discouraged,
peer_best: if peer_best > 0 { Some(peer_best) } else { None },
sync_peers,
})
}

async fn network_status(&self) -> Result<Option<NetworkStatus>, Error> {
Ok(self.network_handle.status().await)
}

async fn send_raw_transaction(&self, raw_tx: String) -> Result<SendTransactionResult, Error> {
Ok(self
.network_handle
Expand Down

0 comments on commit 6cc5dbe

Please sign in to comment.