pallet进阶(10)-自定义RPC接口

自定义RPC接口

1. pallet内容

其中实现一个rpc的功能函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#![cfg_attr(not(feature = "std"), no_std)]

pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}

#[pallet::storage]
pub type Proofs<T: Config> = StorageMap<_, Blake2_128Concat, u32, u128>;

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
ClaimCreated(u32, u128),
}

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(0)]
pub fn create_claim(origin: OriginFor<T>, id: u32, claim: u128, ) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;
Proofs::<T>::insert(&id, &claim);
Self::deposit_event(Event::ClaimCreated(id, claim));
Ok(().into())
}
}

impl<T: Config> Pallet<T> {
//重点:供rpc调用,功能函数
pub fn rpc_method(v: u32) -> bool {
if v > 100 {
true
} else {
false
}
}
}
}

2. 在./rpc/runtime-api/目录定义runtime中的rpc接口

Cargo.toml内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[package]
name = "use-rpc-runtime-api"
version = "4.0.0-dev"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
sp-api = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" }

[features]
default = ["std"]
std = [
"sp-api/std",
]

src/lib.rs中定义:

1
2
3
4
5
6
7
#![cfg_attr(not(feature = "std"), no_std)]
sp_api::decl_runtime_apis! {
//定义接口
pub trait MyRpcRuntimeApi {
fn rpc_method(v: u32) -> bool;
}
}

3. 在./rpc/目录定义rpc接口

在Cargo.toml中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[package]
name = "pallet-rpc"
version = "4.0.0-dev"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
jsonrpc-core = "18.0.0"
jsonrpc-core-client = "18.0.0"
jsonrpc-derive = "18.0.0"

sp-runtime = { default-features = false, version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" }
sp-api = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" }
sp-blockchain = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" }
use-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "./runtime-api" }

[dev-dependencies]
serde_json = "1.0.74"

在src/lib.rs中实现rpc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use std::sync::Arc;

pub use self::gen_client::Client as UseRpcClient;
use jsonrpc_core::{Error as RpcError, ErrorCode, Result};
use jsonrpc_derive::rpc;

use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use use_rpc_runtime_api::MyRpcRuntimeApi;

pub struct UseRpc<C, B> {
client: Arc<C>,
_marker: std::marker::PhantomData<B>,
}

impl<C, B> UseRpc<C, B> {
pub fn new(client: Arc<C>) -> Self {
Self { client, _marker: Default::default() }
}
}

#[rpc]
pub trait MyRpcApi<BlockHash> {
#[rpc(name = "my_rpc_method")]
fn rpc_method(&self, v: u32, at: Option<BlockHash>) -> Result<bool>;
}

impl<C, Block> MyRpcApi<<Block as BlockT>::Hash> for UseRpc<C, Block>
where
Block: BlockT,
C: Send + Sync + 'static,
C: ProvideRuntimeApi<Block>,
C: HeaderBackend<Block>,
C::Api: MyRpcRuntimeApi<Block>, {
fn rpc_method(&self, v: u32, at: Option<<Block as BlockT>::Hash>) -> Result<bool> {
let api = self.client.runtime_api();
let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));

let runtime_api_result = api.rpc_method(&at, v);
runtime_api_result.map_err(|e| RpcError {
code: ErrorCode::ServerError(9876),
message: "Something wrong".into(),
data: Some(format!("{:?}", e).into()),
})
}
}

4. 在项目的runtime中引入rpc

在runtime/Cargo.toml中添加依赖:

1
2
3
4
5
6
7
8
9
10
11
12

[dependencies]
#...
use-rpc-runtime-api = { version = "1.0.0", path = "../pallets/use-rpc/runtime-api" }
#...

[features]
default = ["std"]
std = [
#...
"use-rpc-runtime-api/std",
]

在runtime/src/lib.rs中添加:

1
2
3
4
5
6
7
8
impl_runtime_apis! {
//...
impl use_rpc_runtime_api::MyRpcRuntimeApi<Block> for Runtime {
fn rpc_method(v: u32) -> bool {
UseRpc::rpc_method(v)
}
}
}

5. node中添加对应rpc

在node/Cargo.toml中添加如下依赖

1
2
pallet-rpc = { version = "1.0.0", path = "../pallets/use-rpc/rpc"}
use-rpc-runtime-api = { version = "1.0.0", path = "../pallets/use-rpc/runtime-api" }

node/src/rpc.rs中添加如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
pub fn create_full<C, P>(deps: FullDeps<C, P>) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
where
C: ProvideRuntimeApi<Block>,
C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
C: Send + Sync + 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
// 添加此行
C::Api: use_rpc_runtime_api::MyRpcRuntimeApi<Block>,
C::Api: BlockBuilder<Block>,
P: TransactionPool + 'static,
{
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
use substrate_frame_rpc_system::{FullSystem, SystemApi};
// 添加这一行
use pallet_rpc::{MyRpcApi, UseRpc};

let mut io = jsonrpc_core::IoHandler::default();
let FullDeps { client, pool, deny_unsafe } = deps;

io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)));
...

//添加这一行
io.extend_with(MyRpcApi::to_delegate(UseRpc::new(client.clone())));

io
}

6. 运行

运行:

1
./target/debug/node-template --dev

调用rpc接口:

1
2
3
4
5
6
curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d   '{
"jsonrpc":"2.0",
"id":1,
"method":"my_rpc_method",
"params": [1]
}'

7. 总结

本文编辑完毕

  • Copyrights © 2017-2023 Jason
  • Visitors: | Views:

谢谢打赏~

微信