I cannot seem to setup a RPC call that accepts a u128
param.
I can input the following
let u128Input = new BN("10")
let output = await api.rpc.template.testRpc(u128Input);
but get an error when the number is large
let u128Input = new BN("10000000000000000")
let output = await api.rpc.template.testRpc(u128Input);
I get the following error
RPC-CORE: testRpc(amount: Balance): Balance:: -32602: Invalid params: invalid type: string "0x0000000000000000002386f26fc10000", expected u128.
RpcError: -32602: Invalid params: invalid type: string "0x0000000000000000002386f26fc10000", expected u128.
My runtime-api/src/lib.rs
file looks like
sp_api::decl_runtime_apis! {
pub trait TemplateApi<Balance> where
Balance: Codec + MaybeDisplay,
{
fn test_rpc(amount: Balance) -> Result<u64, DispatchError>;
}
}
What should I change to allow u128
inputs?
Update
NumberOrHex
was exactly what I needed 🙌
I updated the rpc/runtime-api/src/lib.rs
to look like
sp_api::decl_runtime_apis! {
pub trait TemplateApi<Balance> where
Balance: Codec,
{
fn test_rpc(amount: Balance) -> Result<Balance, DispatchError>;
}
}
I updated the rpc/src/lib.rs
to look like
#[rpc]
pub trait TemplateApi<BlockHash, Balance>
where
Balance: Codec + Copy + TryFrom<NumberOrHex>,
{
#[rpc(name = "template_testRpc")]
fn test_rpc(&self, amount: NumberOrHex, at: Option<BlockHash>) -> Result<NumberOrHex>;
}
Also the impl
had to be updated and added a custom serialization and deserialization
impl<C, Block, Balance> TemplateApi<<Block as BlockT>::Hash, Balance> for Api<C, Block>
where
Block: BlockT,
C: Send + Sync + 'static,
C: ProvideRuntimeApi<Block>,
C: HeaderBackend<Block>,
C::Api: TemplateRuntimeApi<Block, Balance>,
Balance: Codec + Copy + TryFrom<NumberOrHex> + Into<NumberOrHex> + std::fmt::Display,
{
fn test_rpc(
&self,
amount: NumberOrHex,
at: Option<<Block as BlockT>::Hash>,
) -> Result<NumberOrHex> {
let api = self.client.runtime_api();
let at: BlockId<Block> = BlockId::hash(at.unwrap_or(self.client.info().best_hash));
let try_into_rpc_balance = |value: Balance| {
value.try_into().map_err(|_| RpcError {
code: ErrorCode::InvalidParams,
message: format!("{} doesn't fit in NumberOrHex representation", value),
data: None,
})
};
let res = api
.test_rpc(&at, decode_hex(amount, "balance")?)
.map_err(runtime_error_into_rpc_error)?
.map_err(test_rpc_error)?;
try_into_rpc_balance(res)
}
}
...
fn decode_hex<H: std::fmt::Debug + Copy, T: TryFrom<H>>(from: H, name: &str) -> Result<T> {
from.try_into().map_err(|_| RpcError {
code: ErrorCode::InvalidParams,
message: format!("{:?} does not fit into the {} type", from, name),
data: None,
})
}
u8a
) before you send it into the RPC?