Skip to content

Commit

Permalink
0.0.12: add support for generic handlers
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Batschelet <[email protected]>
  • Loading branch information
hexfusion committed Mar 25, 2023
1 parent 9fa094b commit f4da57c
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 41 deletions.
4 changes: 2 additions & 2 deletions tests/e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ homepage = "https://avax.network"
[dependencies]

[dev-dependencies]
avalanche-installer = "0.0.50"
avalanche-installer = "0.0.54"
avalanche-network-runner-sdk = "0.3.0" # https://crates.io/crates/avalanche-network-runner-sdk
avalanche-types = { version = "0.0.319", features = ["jsonrpc_client", "subnet"] } # https://crates.io/crates/avalanche-types
avalanche-types = { version = "0.0.322", features = ["jsonrpc_client", "subnet"] } # https://crates.io/crates/avalanche-types
env_logger = "0.10.0"
log = "0.4.17"
random-manager = "0.0.5"
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
use avalanche_network_runner_sdk::{BlockchainSpec, Client, GlobalConfig, StartRequest};
use avalanche_types::{ids, jsonrpc::client::info as avalanche_sdk_info, subnet};

const AVALANCHEGO_VERSION: &str = "v1.9.11";
const AVALANCHEGO_VERSION: &str = "v1.9.14";

#[tokio::test]
async fn e2e() {
Expand Down
3 changes: 2 additions & 1 deletion timestampvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ repository = "https://github.com/ava-labs/timestampvm-rs"
readme = "../README.md"

[dependencies]
avalanche-types = { version = "0.0.319", features = ["subnet", "codec_base64"] } # https://crates.io/crates/avalanche-types
avalanche-types = { version = "0.0.322", features = ["subnet", "codec_base64"] } # https://crates.io/crates/avalanche-types
base64 = { version = "0.21.0" }
bytes = "1.4.0"
chrono = "0.4.23"
clap = { version = "4.1.8", features = ["cargo", "derive"] } # https://github.com/clap-rs/clap/releases
derivative = "2.2.0"
Expand Down
53 changes: 47 additions & 6 deletions timestampvm/src/api/chain_handlers.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
//! Implements chain/VM specific handlers.
//! To be served via `[HOST]/ext/bc/[CHAIN ID]/rpc`.
use std::str::FromStr;
use std::{io, marker::PhantomData, str::FromStr};

use crate::{block::Block, vm::Vm};
use avalanche_types::ids;
use jsonrpc_core::{BoxFuture, Error, ErrorCode, Result};
use avalanche_types::{ids, proto::http::Element, subnet::rpc::http::handle::Handle};
use bytes::Bytes;
use jsonrpc_core::{BoxFuture, Error, ErrorCode, IoHandler, Result};
use jsonrpc_derive::rpc;
use serde::{Deserialize, Serialize};

use super::de_request;

/// Defines RPCs specific to the chain.
#[rpc]
pub trait Rpc {
Expand Down Expand Up @@ -60,17 +63,18 @@ pub struct GetBlockResponse {
}

/// Implements API services for the chain-specific handlers.
pub struct Service<A> {
#[derive(Clone)]
pub struct ChainService<A> {
pub vm: Vm<A>,
}

impl<A> Service<A> {
impl<A> ChainService<A> {
pub fn new(vm: Vm<A>) -> Self {
Self { vm }
}
}

impl<A> Rpc for Service<A>
impl<A> Rpc for ChainService<A>
where
A: Send + Sync + Clone + 'static,
{
Expand Down Expand Up @@ -140,6 +144,43 @@ where
}
}

#[derive(Clone, Debug)]
pub struct ChainHandler<T> {
pub handler: IoHandler,
_marker: PhantomData<T>,
}

impl<T: Rpc> ChainHandler<T> {
pub fn new(service: T) -> Self {
let mut handler = jsonrpc_core::IoHandler::new();
handler.extend_with(Rpc::to_delegate(service));
Self {
handler,
_marker: PhantomData,
}
}
}

#[tonic::async_trait]
impl<T> Handle for ChainHandler<T>
where
T: Rpc + Send + Sync + Clone + 'static,
{
async fn request(
&self,
req: &Bytes,
_headers: &[Element],
) -> std::io::Result<(Bytes, Vec<Element>)> {
match self.handler.handle_request(&de_request(&req)?).await {
Some(resp) => Ok((Bytes::from(resp), Vec::new())),
None => Err(io::Error::new(
io::ErrorKind::Other,
"failed to handle request",
)),
}
}
}

fn create_jsonrpc_error(e: std::io::Error) -> Error {
let mut error = Error::new(ErrorCode::InternalError);
error.message = format!("{}", e);
Expand Down
20 changes: 20 additions & 0 deletions timestampvm/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,29 @@
pub mod chain_handlers;
pub mod static_handlers;

use std::io;

use bytes::Bytes;
use jsonrpc_core::MethodCall;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct PingResponse {
pub success: bool,
}

/// Deserializes JSON-RPC method call.
pub fn de_request(req: &Bytes) -> io::Result<String> {
let method_call: MethodCall = serde_json::from_slice(req).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("failed to deserialize request: {e}"),
)
})?;
serde_json::to_string(&method_call).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("failed to serialize request: {e}"),
)
})
}
54 changes: 42 additions & 12 deletions timestampvm/src/api/static_handlers.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
//! Implements static handlers specific to this VM.
//! To be served via `[HOST]/ext/vm/[VM ID]/static`.
use crate::vm::Vm;
use jsonrpc_core::{BoxFuture, Result};
use std::io;

use avalanche_types::{proto::http::Element, subnet::rpc::http::handle::Handle};
use bytes::Bytes;
use jsonrpc_core::{BoxFuture, IoHandler, Result};
use jsonrpc_derive::rpc;

use super::de_request;

/// Defines static handler RPCs for this VM.
#[rpc]
pub trait Rpc {
Expand All @@ -13,22 +18,47 @@ pub trait Rpc {
}

/// Implements API services for the static handlers.
pub struct Service<A> {
pub vm: Vm<A>,
}
#[derive(Default)]
pub struct StaticService {}

impl<A> Service<A> {
pub fn new(vm: Vm<A>) -> Self {
Self { vm }
impl StaticService {
pub fn new() -> Self {
Self {}
}
}

impl<A> Rpc for Service<A>
where
A: Send + Sync + Clone + 'static,
{
impl Rpc for StaticService {
fn ping(&self) -> BoxFuture<Result<crate::api::PingResponse>> {
log::debug!("ping called");
Box::pin(async move { Ok(crate::api::PingResponse { success: true }) })
}
}
#[derive(Clone)]
pub struct StaticHandler {
pub handler: IoHandler,
}

impl StaticHandler {
pub fn new(service: StaticService) -> Self {
let mut handler = jsonrpc_core::IoHandler::new();
handler.extend_with(Rpc::to_delegate(service));
Self { handler }
}
}

#[tonic::async_trait]
impl Handle for StaticHandler {
async fn request(
&self,
req: &Bytes,
_headers: &[Element],
) -> std::io::Result<(Bytes, Vec<Element>)> {
match self.handler.handle_request(&de_request(&req)?).await {
Some(resp) => Ok((Bytes::from(resp), Vec::new())),
None => Err(io::Error::new(
io::ErrorKind::Other,
"failed to handle request",
)),
}
}
}
53 changes: 34 additions & 19 deletions timestampvm/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ use std::{
sync::Arc,
};

use crate::{api, block::Block, genesis::Genesis, state};
use crate::{
api::{
chain_handlers::{ChainHandler, ChainService},
static_handlers::{StaticHandler, StaticService},
},
block::Block,
genesis::Genesis,
state,
};
use avalanche_types::{
choices, ids,
subnet::{
Expand All @@ -19,6 +27,7 @@ use avalanche_types::{
engine::common::{
appsender::AppSender,
engine::{AppHandler, CrossChainAppHandler, NetworkAppHandler},
http_handler::{HttpHandler, LockOptions},
vm::{CommonVm, Connector},
},
},
Expand Down Expand Up @@ -205,6 +214,8 @@ where
{
type DatabaseManager = DatabaseManager;
type AppSender = A;
type ChainHandler = ChainHandler<ChainService<A>>;
type StaticHandler = StaticHandler;

async fn initialize(
&mut self,
Expand Down Expand Up @@ -285,32 +296,36 @@ where
/// Creates static handlers.
async fn create_static_handlers(
&mut self,
) -> io::Result<HashMap<String, snow::engine::common::http_handler::HttpHandler>> {
let svc = api::static_handlers::Service::new(self.clone());
let mut handler = jsonrpc_core::IoHandler::new();
handler.extend_with(api::static_handlers::Rpc::to_delegate(svc));

let http_handler = snow::engine::common::http_handler::HttpHandler::new_from_u8(0, handler)
.map_err(|_| Error::from(ErrorKind::InvalidData))?;

) -> io::Result<HashMap<String, HttpHandler<Self::StaticHandler>>> {
let handler = StaticHandler::new(StaticService::new());
let mut handlers = HashMap::new();
handlers.insert("/static".to_string(), http_handler);
handlers.insert(
"/static".to_string(),
HttpHandler {
lock_option: LockOptions::WriteLock,
handler,
server_addr: None,
},
);

Ok(handlers)
}

/// Creates VM-specific handlers.
async fn create_handlers(
&mut self,
) -> io::Result<HashMap<String, snow::engine::common::http_handler::HttpHandler>> {
let svc = api::chain_handlers::Service::new(self.clone());
let mut handler = jsonrpc_core::IoHandler::new();
handler.extend_with(api::chain_handlers::Rpc::to_delegate(svc));

let http_handler = snow::engine::common::http_handler::HttpHandler::new_from_u8(0, handler)
.map_err(|_| Error::from(ErrorKind::InvalidData))?;

) -> io::Result<HashMap<String, HttpHandler<Self::ChainHandler>>> {
let handler = ChainHandler::new(ChainService::new(self.clone()));
let mut handlers = HashMap::new();
handlers.insert("/rpc".to_string(), http_handler);
handlers.insert(
"/rpc".to_string(),
HttpHandler {
lock_option: LockOptions::WriteLock,
handler,
server_addr: None,
},
);

Ok(handlers)
}
}
Expand Down

0 comments on commit f4da57c

Please sign in to comment.