Skip to content

Commit

Permalink
feat: new API for get_module(_abi) RPC calls
Browse files Browse the repository at this point in the history
  • Loading branch information
asmie committed Nov 3, 2023
1 parent b20c9d2 commit 436e666
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 61 deletions.
7 changes: 5 additions & 2 deletions rpc/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

use frame_support::{dispatch::Vec, weights::Weight};
use alloc::string::String;

// Here we declare the runtime API. It is implemented it the `impl` block in
// runtime file (the `runtime/src/lib.rs` of the node)
Expand All @@ -21,10 +24,10 @@ sp_api::decl_runtime_apis! {
fn estimate_gas_execute(account: AccountId, bytecode: Vec<u8>, gas_limit: u64) -> u64;

// Get module binary by its address
fn get_module(module_id: Vec<u8>) -> Result<Option<Vec<u8>>, Vec<u8>>;
fn get_module(address: String, name: String) -> Result<Option<Vec<u8>>, Vec<u8>>;

// Get module ABI by its address
fn get_module_abi(module_id: Vec<u8>) -> Result<Option<Vec<u8>>, Vec<u8>>;
fn get_module_abi(address: String, name: String) -> Result<Option<Vec<u8>>, Vec<u8>>;

// Get resource
fn get_resource(account: AccountId, tag: Vec<u8>) -> Result<Option<Vec<u8>>, Vec<u8>>;
Expand Down
88 changes: 58 additions & 30 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,21 @@ pub trait MoveApi<BlockHash, AccountId> {

/// Get module ABI using address
#[method(name = "mvm_getModuleABI")]
fn get_module_abi(&self, module_id: Vec<u8>, at: Option<BlockHash>) -> RpcResult<Option<Vec<u8>>>;
fn get_module_abi(
&self,
address: &str,
name: &str,
at: Option<BlockHash>,
) -> RpcResult<Option<Vec<u8>>>;

/// Get module binary using address
#[method(name = "mvm_getModule")]
fn get_module(&self, module_id: Vec<u8>, at: Option<BlockHash>) -> RpcResult<Option<Vec<u8>>>;
fn get_module(
&self,
address: &str,
name: &str,
at: Option<BlockHash>,
) -> RpcResult<Option<Vec<u8>>>;
}

/// A struct that implements the `MoveApi`.
Expand Down Expand Up @@ -106,8 +116,12 @@ where
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<u64> {
let api = self.client.runtime_api();
let res =
api.estimate_gas_publish(at.unwrap_or_else(|| self.client.info().best_hash), account, bytecode, gas_limit);
let res = api.estimate_gas_publish(
at.unwrap_or_else(|| self.client.info().best_hash),
account,
bytecode,
gas_limit,
);

res.map_err(runtime_error_into_rpc_err)
}
Expand All @@ -120,8 +134,12 @@ where
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<u64> {
let api = self.client.runtime_api();
let res =
api.estimate_gas_execute(at.unwrap_or_else(|| self.client.info().best_hash), account, bytecode, gas_limit);
let res = api.estimate_gas_execute(
at.unwrap_or_else(|| self.client.info().best_hash),
account,
bytecode,
gas_limit,
);

res.map_err(runtime_error_into_rpc_err)
}
Expand All @@ -133,31 +151,45 @@ where
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Option<Vec<u8>>> {
let api = self.client.runtime_api();
let res = api.get_resource(at.unwrap_or_else(|| self.client.info().best_hash), account, tag);
let res = api.get_resource(
at.unwrap_or_else(|| self.client.info().best_hash),
account,
tag,
);

// Currently, there is always correct value returned so it's safe to unwrap here.
res.unwrap().map_err(runtime_error_into_rpc_err)
}

fn get_module_abi(
&self,
module_id: Vec<u8>,
address: &str,
name: &str,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Option<Vec<u8>>> {
let api = self.client.runtime_api();
let res = api.get_module_abi(at.unwrap_or_else(|| self.client.info().best_hash), module_id);
let res = api.get_module_abi(
at.unwrap_or_else(|| self.client.info().best_hash),
address.to_string(),
name.to_string(),
);

// Currently, there is always correct value returned so it's safe to unwrap here.
res.unwrap().map_err(runtime_error_into_rpc_err)
}

fn get_module(
&self,
module_id: Vec<u8>,
address: &str,
name: &str,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Option<Vec<u8>>> {
let api = self.client.runtime_api();
let res = api.get_module(at.unwrap_or_else(|| self.client.info().best_hash), module_id);
let res = api.get_module(
at.unwrap_or_else(|| self.client.info().best_hash),
address.to_string(),
name.to_string(),
);

// Currently, there is always correct value returned so it's safe to unwrap here.
res.unwrap().map_err(runtime_error_into_rpc_err)
Expand Down Expand Up @@ -186,16 +218,14 @@ mod tests {
let err_str_tst = "\"\\\"test\\\"\"";
let res = runtime_error_into_rpc_err(err_str);
match res {
JsonRpseeError::Call(err) => {
match err {
CallError::Custom(err) => {
assert_eq!(err.code(), RUNTIME_ERROR);
assert_eq!(err.message(), "Runtime error");
assert_eq!(err.data().unwrap().get(), err_str_tst)
}
_ => panic!("Wrong error type"),
JsonRpseeError::Call(err) => match err {
CallError::Custom(err) => {
assert_eq!(err.code(), RUNTIME_ERROR);
assert_eq!(err.message(), "Runtime error");
assert_eq!(err.data().unwrap().get(), err_str_tst)
}
}
_ => panic!("Wrong error type"),
},
_ => panic!("Wrong error type"),
}
}
Expand All @@ -206,17 +236,15 @@ mod tests {
let err_str_tst = "\"\\\"\\\"\"";
let res = runtime_error_into_rpc_err(err_str);
match res {
JsonRpseeError::Call(err) => {
match err {
CallError::Custom(err) => {
assert_eq!(err.code(), RUNTIME_ERROR);
assert_eq!(err.message(), "Runtime error");
assert_eq!(err.data().unwrap().get(), err_str_tst)
}
_ => panic!("Wrong error type"),
JsonRpseeError::Call(err) => match err {
CallError::Custom(err) => {
assert_eq!(err.code(), RUNTIME_ERROR);
assert_eq!(err.message(), "Runtime error");
assert_eq!(err.data().unwrap().get(), err_str_tst)
}
}
_ => panic!("Wrong error type"),
},
_ => panic!("Wrong error type"),
}
}
}
}
15 changes: 11 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,24 @@ pub mod pallet {
})
}

pub fn get_module_abi(module_id: &[u8]) -> Result<Option<Vec<u8>>, Vec<u8>> {
pub fn get_module_abi(
address: &T::AccountId,
name: &str,
) -> Result<Option<Vec<u8>>, Vec<u8>> {
let vm = Self::move_vm()?;

vm.get_module_abi(module_id)
let address = address::to_move_address(&address);

vm.get_module_abi(address, name)
.map_err(|e| format!("error in get_module_abi: {:?}", e).into())
}

pub fn get_module(module_id: &[u8]) -> Result<Option<Vec<u8>>, Vec<u8>> {
pub fn get_module(address: &T::AccountId, name: &str) -> Result<Option<Vec<u8>>, Vec<u8>> {
let vm = Self::move_vm()?;

vm.get_module(module_id)
let address = address::to_move_address(&address);

vm.get_module(address, name)
.map_err(|e| format!("error in get_module: {:?}", e).into())
}

Expand Down
1 change: 1 addition & 0 deletions tests/assets/move/Move.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ MoveStdlib = { git = "https://github.com/move-language/move.git", subdir = "lang
[addresses]
std = "0x1"
TestAccount = "0xCAFE"
Bob = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
Binary file modified tests/assets/move/build/move/bytecode_modules/Empty.mv
Binary file not shown.
4 changes: 4 additions & 0 deletions tests/assets/move/sources/EmptyBob.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Bob::EmptyBob {
struct EmptyStruct {
}
}
28 changes: 3 additions & 25 deletions tests/modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ mod mock;

use frame_support::assert_ok;
use mock::*;
use move_core_types::{
account_address::AccountAddress,
identifier::Identifier,
language_storage::{ModuleId, StructTag},
};
use move_core_types::{identifier::Identifier, language_storage::StructTag};
use pallet_move::address;

const EMPTY_ADDR: u64 = 0x000000000CAFE_u64.to_be();
Expand All @@ -21,10 +17,7 @@ fn get_module_correct() {

assert_ok!(res);

let address = AccountAddress::from_hex_literal("0xCAFE").unwrap(); // Alternative: let address = address::to_move_address(&ACC_ADDR);
let module_id = ModuleId::new(address, Identifier::new("Empty").unwrap());

let res = MoveModule::get_module(&bcs::to_bytes(&module_id).unwrap());
let res = MoveModule::get_module(&EMPTY_ADDR, "Empty");

assert_eq!(res, Ok(Some(module)));
});
Expand All @@ -34,27 +27,12 @@ fn get_module_correct() {
/// Test getting a module that does not exist.
fn get_module_nonexistent() {
new_test_ext().execute_with(|| {
let address = AccountAddress::from_hex_literal("0xCAFE").unwrap();
let module_id = ModuleId::new(address, Identifier::new("Empty").unwrap());

let res = MoveModule::get_module(&bcs::to_bytes(&module_id).unwrap());
let res = MoveModule::get_module(&EMPTY_ADDR, "Empty");

assert_eq!(res, Ok(None));
});
}

#[test]
/// Test getting a module providing incorrect (no module name after the address) module id.
fn get_module_invalid_input() {
new_test_ext().execute_with(|| {
let invalid_module_id = [0u8; 32];
let errmsg = "error in get_module: unexpected end of input".as_bytes();
let res = MoveModule::get_module(&invalid_module_id);

assert_eq!(res, Err(errmsg.to_vec()));
});
}

#[test]
#[ignore = "failing - to be investigated"]
/// Test getting resource from the module.
Expand Down

0 comments on commit 436e666

Please sign in to comment.