如何解决您如何将参数传递和处理到“ChainExtension”?
我有一个调用扩展方法 ink!
的 fetch_random()
合同。
// runtime/src/lib.rs
pub struct FetchRandomExtension;
impl ChainExtension<Runtime> for FetchRandomExtension {
fn call<E: Ext>(
func_id: u32,env: Environment<E,InitState>,) -> Result<RetVal,dispatchError>
where
<E::T as SysConfig>::AccountId:
UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,{
match func_id {
1101 => {
let mut env = env.buf_in_buf_out();
let random_seed = crate::RandomnessCollectiveFlip::random_seed().0;
let random_slice = random_seed.encode();
env.write(&random_slice,false,None).map_err(|_| {
dispatchError::Other("ChainExtension Failed to call random")
})?;
}
_ => {
return Err(dispatchError::Other("Unimplemented func_id"))
}
}
Ok(RetVal::Converging(0))
}
fn enabled() -> bool {
true
}
}
// contract/lib.rs
let new_random = self.env().extension().fetch_random()?;
如何编写扩展处理程序以接收诸如 let new_random = self.env().extension().fetch_random(1,"hello",true)?;
之类的参数?
解决方法
您可以在 GitHub here 上找到完整的示例。
这是工作代码:
#![cfg_attr(not(feature = "std"),no_std)]
use ink_env::Environment;
use ink_lang as ink;
/// This is an example of how ink! contract should
/// call substrate runtime `RandomnessCollectiveFlip::random_seed`.
/// Define the operations to interact with the substrate runtime
#[ink::chain_extension]
pub trait FetchRandom {
type ErrorCode = RandomReadErr;
/// Note: this gives the operation a corresponding `func_id` (1101 in this
case),/// and the chain-side chain extension will get the `func_id` to do further operations.
#[ink(extension = 1101,returns_result = false)]
fn fetch_random() -> [u8; 32];
}
#[derive(Debug,Copy,Clone,PartialEq,Eq,scale::Encode,scale::Decode)]
#[cfg_attr(feature = "std",derive(scale_info::TypeInfo))]
pub enum RandomReadErr {
FailGetRandomSource,}
impl ink_env::chain_extension::FromStatusCode for RandomReadErr {
fn from_status_code(status_code: u32) -> Result<(),Self> {
match status_code {
0 => Ok(()),1 => Err(Self::FailGetRandomSource),_ => panic!("encountered unknown status code"),}
}
}
#[derive(Debug,Eq)]
#[cfg_attr(feature = "std",derive(scale_info::TypeInfo))]
pub enum CustomEnvironment {}
impl Environment for CustomEnvironment {
const MAX_EVENT_TOPICS: usize =
<ink_env::DefaultEnvironment as Environment>::MAX_EVENT_TOPICS;
type AccountId = <ink_env::DefaultEnvironment as Environment>::AccountId;
type Balance = <ink_env::DefaultEnvironment as Environment>::Balance;
type Hash = <ink_env::DefaultEnvironment as Environment>::Hash;
type BlockNumber = <ink_env::DefaultEnvironment as Environment>::BlockNumber;
type Timestamp = <ink_env::DefaultEnvironment as Environment>::Timestamp;
type RentFraction = <ink_env::DefaultEnvironment as Environment>::RentFraction;
type ChainExtension = FetchRandom;
}
#[ink::contract(env = crate::CustomEnvironment)]
mod rand_extension {
use super::RandomReadErr;
/// Defines the storage of your contract.
/// Here we store the random seed fetched from the chain
#[ink(storage)]
pub struct RandExtension {
/// Stores a single `bool` value on the storage.
value: [u8; 32],}
#[ink(event)]
pub struct RandomUpdated {
#[ink(topic)]
new: [u8; 32],}
impl RandExtension {
/// Constructor that initializes the `bool` value to the given `init_value`.
#[ink(constructor)]
pub fn new(init_value: [u8; 32]) -> Self {
Self { value: init_value }
}
/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
/// update the value from runtime random source
#[ink(message)]
pub fn update(&mut self) -> Result<(),RandomReadErr> {
// Get the on-chain random seed
let new_random = self.env().extension().fetch_random()?;
self.value = new_random;
// emit the RandomUpdated event when the random seed
// is successfully fetched.
self.env().emit_event(RandomUpdated { new: new_random });
Ok(())
}
/// Simply returns the current value.
#[ink(message)]
pub fn get(&self) -> [u8; 32] {
self.value
}
}
/// Unit tests in Rust are normally defined within such a `#[cfg(test)]`
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;
use ink_lang as ink;
/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let rand_extension = RandExtension::default();
assert_eq!(rand_extension.get(),[0; 32]);
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。