Unverified Commit eb44ace4 authored by Michael Müller's avatar Michael Müller Committed by GitHub
Browse files

Add example for mocking chain extensions in off-chain tests (#882)

* Improve language

* Add test with mocked chain extension

* Export off-chain trait `ChainExtension`

* Add missing space

* Remove unequal assert
parent 27b8d778
Pipeline #150440 passed with stages
in 33 minutes and 44 seconds
......@@ -228,7 +228,7 @@ See [here](https://paritytech.github.io/ink/ink_lang/attr.contract.html) for a m
### Trait Definitions
Use`#[ink::trait_definition]` to define your very own trait definitions that are then implementable by ink! smart contracts.
Use `#[ink::trait_definition]` to define your very own trait definitions that are then implementable by ink! smart contracts.
See e.g. the [`examples/trait-erc20`](https://github.com/paritytech/ink/blob/master/examples/trait-erc20/lib.rs#L49-L51) contract on how to utilize it or [the documentation](https://paritytech.github.io/ink/ink_lang/attr.trait_definition.html) for details.
### Off-chain Testing
......
......@@ -14,18 +14,18 @@
//! Operations on the off-chain testing environment.
use super::{
pub use super::{
chain_extension::ChainExtension,
db::ChainSpec,
CallData,
EmittedEvent,
};
use super::{
db::ExecContext,
AccountError,
EnvInstance,
OnInstance,
};
pub use super::{
db::ChainSpec,
CallData,
EmittedEvent,
};
use crate::{
Environment,
Result,
......
......@@ -17,10 +17,11 @@
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
/// This is an example of how an ink! contract may call the Substrate
/// runtime function `RandomnessCollectiveFlip::random_seed`. See the
/// file `runtime/chain-extension-example.rs` for that implementation.
///
/// Here we define the operations to interact with the Substrate runtime.
#[ink::chain_extension]
pub trait FetchRandom {
type ErrorCode = RandomReadErr;
......@@ -69,8 +70,9 @@ impl Environment for CustomEnvironment {
mod rand_extension {
use super::RandomReadErr;
/// Defines the storage of your contract.
/// Here we store the random seed fetched from the chain
/// Defines the storage of our contract.
///
/// Here we store the random seed fetched from the chain.
#[ink(storage)]
pub struct RandExtension {
/// Stores a single `bool` value on the storage.
......@@ -92,19 +94,19 @@ mod rand_extension {
/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
/// Constructors may delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
/// update the value from runtime random source
/// Update the value from the runtimes 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
// Emit the `RandomUpdated` event when the random seed
// is successfully fetched.
self.env().emit_event(RandomUpdated { new: new_random });
Ok(())
......@@ -130,5 +132,38 @@ mod rand_extension {
let rand_extension = RandExtension::default();
assert_eq!(rand_extension.get(), [0; 32]);
}
#[ink::test]
fn chain_extension_works() {
// given
struct MockedExtension;
impl ink_env::test::ChainExtension for MockedExtension {
/// The static function id of the chain extension.
fn func_id(&self) -> u32 {
1101
}
/// The chain extension is called with the given input.
///
/// Returns an error code and may fill the `output` buffer with a
/// SCALE encoded result. The error code is taken from the
/// `ink_env::chain_extension::FromStatusCode` implementation for
/// `RandomReadErr`.
fn call(&mut self, _input: &[u8], output: &mut Vec<u8>) -> u32 {
let ret: [u8; 32] = [1; 32];
scale::Encode::encode_to(&ret, output);
0
}
}
ink_env::test::register_chain_extension(MockedExtension);
let mut rand_extension = RandExtension::default();
assert_eq!(rand_extension.get(), [0; 32]);
// when
rand_extension.update().expect("update must work");
// then
assert_eq!(rand_extension.get(), [1; 32]);
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment