-
Notifications
You must be signed in to change notification settings - Fork 17
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
Write proc-macro to automatically declare and implement the Rpc
trait.
#62
Comments
Hey @richardpringle 👋🏻 I have one question about the proc macro implementation. In timestampvm-rs, the Rpc trait is declared twice, with different sets of methods, one has only the Do you want to implement all of the methods available, even though users may not need them, #[derive(Rpc)]
struct Api {}
fn main() {
let api = Api {};
api.ping();
api.propose_block();
api.last_accepted();
api.get_block();
} or each method to be a different macro, and the devs to choose which ones to implement, something like: #[derive(Ping, GetBlock)]
struct Api {}
fn main() {
let api = Api {};
api.ping();
api.get_block();
api.propose_block(); // method not found
api.last_accepted(); // method not found
} |
Actually now that i'm deep diving into the issue, I realized maybe I'm missing some contex of what the final goal is. For example the implementation of last_accepted for |
The initial goal is to prevent the repetition. Something like this: use avalanche_types::rpc;
#[rpc]
impl<A> ChainService<A>
where
A: Send + Sync + Clone + 'static, // not sure that all of these would be needed
{
#[rpc(name = "ping", alias("timestampvm.ping"))]
fn ping(&self) -> BoxFuture<Result<crate::api::PingResponse>> {
log::debug!("ping called");
Box::pin(async move { Ok(crate::api::PingResponse { success: true }) })
}
#[rpc(name = "proposeBlock", alias("timestampvm.proposeBlock"))]
fn propose_block(&self, args: ProposeBlockArgs) -> BoxFuture<Result<ProposeBlockResponse>> {
log::debug!("propose_block called");
let vm = self.vm.clone();
Box::pin(async move {
vm.propose_block(args.data)
.await
.map_err(create_jsonrpc_error)?;
Ok(ProposeBlockResponse { success: true })
})
}
#[rpc(name = "lastAccepted", alias("timestampvm.lastAccepted"))]
fn last_accepted(&self) -> BoxFuture<Result<LastAcceptedResponse>> {
log::debug!("last accepted method called");
let vm = self.vm.clone();
Box::pin(async move {
let vm_state = vm.state.read().await;
if let Some(state) = &vm_state.state {
let last_accepted = state
.get_last_accepted_block_id()
.await
.map_err(create_jsonrpc_error)?;
return Ok(LastAcceptedResponse { id: last_accepted });
}
Err(Error {
code: ErrorCode::InternalError,
message: String::from("no state manager found"),
data: None,
})
})
}
#[rpc(name = "getBlock", alias("timestampvm.getBlock"))]
fn get_block(&self, args: GetBlockArgs) -> BoxFuture<Result<GetBlockResponse>> {
let blk_id = ids::Id::from_str(&args.id).unwrap();
log::info!("get_block called for {}", blk_id);
let vm = self.vm.clone();
Box::pin(async move {
let vm_state = vm.state.read().await;
if let Some(state) = &vm_state.state {
let block = state
.get_block(&blk_id)
.await
.map_err(create_jsonrpc_error)?;
return Ok(GetBlockResponse { block });
}
Err(Error {
code: ErrorCode::InternalError,
message: String::from("no state manager found"),
data: None,
})
})
}
} But I'm not sure how feasible this is. Right now, that We might need to take a step back and look at how this interacts with I would skip this issue for now. If you want, you could migrate to |
Right now, one has to create an
Rpc
trait, define all the methods, then define the implementation. It would be way nicer if we could just have oneimpl
block that both defined the trait as well as the implementation. This should be pretty easy to accomplish with our own proc-macro.TODO:
write example of desired output
The text was updated successfully, but these errors were encountered: