Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/66/polka storage provider print start time of the provider #86

Merged
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f5f7c24
feat: provider rpc client wip
cernicc Jun 18, 2024
2cca531
fix: rename constant
cernicc Jun 18, 2024
52a6de8
feat: add method specific params
cernicc Jun 19, 2024
a20e65d
fix: remove unused dep
cernicc Jun 19, 2024
7b768c4
Merge branch 'develop' into feat/66/polka-storage-provider-print-star…
cernicc Jun 19, 2024
1005568
fix: taplo
cernicc Jun 20, 2024
e0c2196
feat: remove uptimeme
cernicc Jun 20, 2024
dcebcc6
fix: use url from params
cernicc Jun 20, 2024
6a3990f
fix: add logging
cernicc Jun 20, 2024
cc34cf5
fix: small changes
cernicc Jun 20, 2024
221d885
chore: add comment
cernicc Jun 20, 2024
92d5756
fix: remove unused import
cernicc Jun 20, 2024
1ac85ee
fix: pr suggestions
cernicc Jun 21, 2024
cf46461
Merge branch 'develop' into feat/66/polka-storage-provider-print-star…
cernicc Jun 26, 2024
92d7ce0
fix: pr suggestions
cernicc Jun 26, 2024
ba82300
Merge remote-tracking branch 'origin/develop' into feat/66/polka-stor…
cernicc Jun 26, 2024
cdfa193
fix: change request params to generic
cernicc Jun 26, 2024
7188abc
feat: refactor
cernicc Jun 27, 2024
c349014
Merge remote-tracking branch 'origin/develop' into feat/66/polka-stor…
cernicc Jun 27, 2024
b3e1c9f
fix: after merge
cernicc Jun 27, 2024
3bccbff
feat: add custom rpc client error
cernicc Jun 27, 2024
ab60f49
chore: some comments
cernicc Jun 27, 2024
e1494bf
fix: remove unused bounds
cernicc Jun 27, 2024
98f6872
fix: some pr suggestions
cernicc Jun 27, 2024
4a07a9b
fix: pr related
cernicc Jun 27, 2024
a689022
fix: V0 enum
cernicc Jun 27, 2024
5fedadb
Merge branch 'develop' into feat/66/polka-storage-provider-print-star…
cernicc Jun 28, 2024
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", t

async-channel = "2.3.1"
async-stream = "0.3.5"
async-trait = "0.1.80"
base64 = "0.22.1"
bitflags = "2.5.0"
byteorder = "1.5.0"
Expand Down
4 changes: 3 additions & 1 deletion cli/polka-storage-provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ repository.workspace = true
version = "0.1.0"

[dependencies]
async-trait = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
clap = { workspace = true, features = ["derive"] }
jsonrpsee = { workspace = true, features = ["server"] }
jsonrpsee = { workspace = true, features = ["http-client", "server", "ws-client"] }
sc-cli = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
Expand All @@ -21,6 +22,7 @@ tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
url = { workspace = true }
uuid = { workspace = true }

[lints]
workspace = true
7 changes: 6 additions & 1 deletion cli/polka-storage-provider/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use clap::Parser;

use crate::commands::{InfoCommand, InitCommand, RunCommand, WalletCommand};
use crate::{
commands::{InfoCommand, InitCommand, RunCommand, WalletCommand},
rpc::RPC_SERVER_DEFAULT_BIND_ADDR,
};

/// A CLI application that facilitates management operations over a running full
/// node and other components.
Expand All @@ -9,6 +12,8 @@ use crate::commands::{InfoCommand, InitCommand, RunCommand, WalletCommand};
pub(crate) struct Cli {
#[command(subcommand)]
pub subcommand: SubCommand,
#[arg(short, long, default_value_t = format!("http://{RPC_SERVER_DEFAULT_BIND_ADDR}"))]
cernicc marked this conversation as resolved.
Show resolved Hide resolved
pub rpc_server_url: String,
}

/// Supported sub-commands.
Expand Down
33 changes: 29 additions & 4 deletions cli/polka-storage-provider/src/commands/info.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
use std::fmt::{self, Display, Formatter};

use chrono::{DateTime, Utc};
use clap::Parser;

use crate::Error;
use crate::{
rpc::{methods::common::Info, RpcClient, RpcMethodExt},
Error,
};

/// Command to display information about the storage provider.
#[derive(Debug, Clone, Parser)]
pub(crate) struct InfoCommand;

impl InfoCommand {
pub async fn run(&self) -> Result<(), Error> {
// TODO(#66,@cernicc,31/05/2024): Print start time of the provider
pub async fn run(&self, client: &RpcClient) -> Result<(), Error> {
// TODO(#67,@cernicc,07/06/2024): Print polkadot address used by the provider
unimplemented!()

// Get server info
let server_info = Info::call(client, ()).await?;

let node_status_info = NodeStatusInfo {
start_time: server_info.start_time,
};

println!("{}", node_status_info);

Ok(())
}
}

struct NodeStatusInfo {
start_time: DateTime<Utc>,
}

impl Display for NodeStatusInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(f, "Started at: {}", self.start_time)
}
}
7 changes: 3 additions & 4 deletions cli/polka-storage-provider/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ use tracing::info;
use url::Url;

use crate::{
rpc::{start_rpc, RpcServerState},
rpc::{start_rpc, RpcServerState, RPC_SERVER_DEFAULT_BIND_ADDR},
substrate, Error,
};

const SERVER_DEFAULT_BIND_ADDR: &str = "127.0.0.1:8000";
const FULL_NODE_DEFAULT_RPC_ADDR: &str = "ws://127.0.0.1:9944";

/// Command to start the storage provider.
Expand All @@ -19,8 +18,8 @@ pub(crate) struct RunCommand {
/// RPC API endpoint used by the parachain node.
#[arg(short = 'n', long, default_value = FULL_NODE_DEFAULT_RPC_ADDR)]
pub node_rpc_address: Url,
/// Address used for RPC. By default binds on localhost on port 8000.
#[arg(short = 'a', long, default_value = SERVER_DEFAULT_BIND_ADDR)]
/// Address and port used for RPC server.
#[arg(short = 'a', long, default_value = RPC_SERVER_DEFAULT_BIND_ADDR)]
pub listen_addr: SocketAddr,
}

Expand Down
11 changes: 9 additions & 2 deletions cli/polka-storage-provider/src/commands/runner.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
use std::str::FromStr;

use clap::Parser;
use url::Url;

use super::WalletCommand;
use crate::{cli::SubCommand, Cli, Error};
use crate::{cli::SubCommand, rpc::RpcClient, Cli, Error};

/// Parses command line arguments into the service configuration and runs the specified
/// command with it.
pub(crate) async fn run() -> Result<(), Error> {
// CLI arguments parsed and mapped to the struct.
let cli_arguments: Cli = Cli::parse();

// Rpc client used to interact with the node
let rpc_url = Url::from_str(&cli_arguments.rpc_server_url)?;
cernicc marked this conversation as resolved.
Show resolved Hide resolved
let rpc_client = RpcClient::new(rpc_url);

match &cli_arguments.subcommand {
SubCommand::Init(cmd) => cmd.run().await,
SubCommand::Run(cmd) => cmd.run().await,
SubCommand::Info(cmd) => cmd.run().await,
SubCommand::Info(cmd) => cmd.run(&rpc_client).await,
SubCommand::Wallet(cmd) => match cmd {
WalletCommand::GenerateNodeKey(cmd) => Ok(cmd.run()?),
WalletCommand::Generate(cmd) => Ok(cmd.run()?),
Expand Down
6 changes: 6 additions & 0 deletions cli/polka-storage-provider/src/error.rs
cernicc marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ pub enum Error {
#[error("FromEnv error: {0}")]
EnvError(#[from] tracing_subscriber::filter::FromEnvError),

#[error("URL parse error: {0}")]
ParseUrl(#[from] url::ParseError),

#[error("Substrate error: {0}")]
Substrate(#[from] subxt::Error),

#[error(transparent)]
SubstrateCli(#[from] sc_cli::Error),

#[error("JSON-RPC client error: {0}")]
JsonRpcClient(#[from] jsonrpsee::core::ClientError),
}
73 changes: 66 additions & 7 deletions cli/polka-storage-provider/src/rpc.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,108 @@
use std::{future::Future, net::SocketAddr, sync::Arc};
use std::{fmt::Debug, future::Future, net::SocketAddr, sync::Arc};

use chrono::Utc;
use client::Request;
use error::ServerError;
use jsonrpsee::{
core::ClientError,
server::{Server, ServerHandle},
types::Params,
RpcModule,
};
use methods::create_module;
use serde::{Deserialize, Serialize};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tracing::{debug, debug_span, error, Instrument};
use uuid::Uuid;

use crate::{substrate, Error};

mod client;
pub mod error;
pub mod methods;

pub use client::RpcClient;

/// Default address to bind the RPC server to.
pub const RPC_SERVER_DEFAULT_BIND_ADDR: &str = "127.0.0.1:8000";

/// A definition of an RPC method handler which can be registered with an [`RpcModule`].
pub trait RpcMethod {
/// Method name.
const NAME: &'static str;
/// See [`ApiVersion`].
const API_VERSION: ApiVersion;
/// Successful response type.
type Ok: Serialize;
type Ok: Debug + Serialize + DeserializeOwned;
/// Parameters type.
type Params: Debug + Serialize + DeserializeOwned;

/// Logic for this method.
fn handle(
ctx: Arc<RpcServerState>,
params: Params,
params: Self::Params,
) -> impl Future<Output = Result<Self::Ok, ServerError>> + Send;
}

pub trait RpcMethodExt: RpcMethod {
/// Register this method with an [`RpcModule`].
fn register_async(module: &mut RpcModule<RpcServerState>) -> &mut jsonrpsee::MethodCallback
where
Self::Ok: Clone + 'static,
Self::Params: Debug + Send,
{
module
.register_async_method(Self::NAME, move |params, ctx| async move {
let ok = Self::handle(ctx, params).await?;
Result::<_, jsonrpsee::types::ErrorObjectOwned>::Ok(ok)
// Try to deserialize the params
let span =
debug_span!("rpc", id = %Uuid::new_v4(), method = Self::NAME, params = ?params);
jmg-duarte marked this conversation as resolved.
Show resolved Hide resolved
let entered = span.enter();

let params = params.parse().map_err(|e| {
tracing::error!("Failed to parse params: {:?}", e);
ServerError::invalid_params("Failed to parse params", None)
})?;
drop(entered);

// Handle the method
let result = Self::handle(ctx, params).instrument(span.clone()).await;

match &result {
Ok(ok) => {
span.in_scope(|| debug!(response = ?ok, "handled successfully"));
}
Err(err) => {
span.in_scope(|| error!(err = ?err, "error ocurred while handling"));
}
}
cernicc marked this conversation as resolved.
Show resolved Hide resolved

Result::<_, jsonrpsee::types::ErrorObjectOwned>::Ok(result?)
})
.expect("method should be valid") // This is safe because we know the method registered is valid.
}

/// Create a request for this method.
///
/// Returns [`Err`] if any of the parameters fail to serialize.
fn request(params: Self::Params) -> Result<Request<Self::Ok>, serde_json::Error> {
let params = serde_json::to_value(params)?;

Ok(Request {
method_name: Self::NAME,
params,
result_type: std::marker::PhantomData,
api_version: Self::API_VERSION,
})
}

/// Call the method with the provided client and params.
async fn call(client: &RpcClient, params: Self::Params) -> Result<Self::Ok, ClientError> {
let response = client.call(Self::request(params)?).await?;
Ok(response)
}
}

/// Blanket implementation for all types that implement [`RpcMethod`].
impl<T> RpcMethodExt for T where T: RpcMethod {}

/// Available API versions.
///
/// These are significant because they are expressed in the URL path against
Expand Down
Loading