Error in substrates' "use macros in a custom pallet" tutorial - substrate

I'm currently trying substrate tutorial, but it got stack. Please give me an advice.
Following the "use macros in a custom pallet" tutorial, I coded lib.rs file like this.
#![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::*;
use sp_std::vec::Vec; // Step 3.1 will include this in `Cargo.toml`
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
ClaimCreated(T::AccountId, Vec<u8>),
ClaimRevoked(T::AccountId, Vec<u8>),
}
#[pallet::error]
pub enum Error<T> {
ProofAlreadyClaimed,
NoSuchProof,
NotProofOwner,
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::storage]
pub(super) type Proofs<T: Config> = StorageMap<_, Blake2_128Concat, Vec<u8>, (T::AccountId, T::BlockNumber), ValueQuery>;
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(1_000)]
pub fn create_claim(
origin: OriginFor<T>,
proof: Vec<u8>,
) -> DispatchResult {
let sender = ensure_signed(origin)?;
ensure!(!Proofs::<T>::contains_key(&proof), Error::<T>::ProofAlreadyClaimed);
let current_block = <frame_system::Pallet<T>>::block_number();
Proofs::<T>::insert(&proof, (&sender, current_block));
Self::deposit_event(Event::ClaimCreated(sender, proof));
Ok(())
}
#[pallet::weight(10_000)]
pub fn revoke_claim(
origin: OriginFor<T>,
proof: Vec<u8>,
) -> DispatchResult {
let sender = ensure_signed(origin)?;
ensure!(Proofs::<T>::contains_key(&proof),Error::<T>::NoSuchProof);
let (owner, _) = Proofs::<T>::get(&proof);
ensure!(sender == owner, Error::<T>::NotProofOwner);
Proofs::<T>::remove(&proof);
Self::deposit_event(Event::ClaimRevoked(sender, proof));
Ok(())
}
}
}
Cargo.toml file is like this.
[package]
name = "pallet-template"
version = "4.0.0-dev"
description = "FRAME pallet template for defining custom runtime logic."
authors = ["Substrate DevHub <https://github.com/substrate-developer-hub>"]
homepage = "https://substrate.io/"
edition = "2021"
license = "Unlicense"
publish = false
repository = "https://github.com/substrate-developer-hub/substrate-node-template/"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [
"derive",
] }
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
frame-support = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26"}
frame-system = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
frame-benchmarking = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26", optional = true }
[dev-dependencies]
sp-core = { default-features = false, version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
sp-io = { default-features = false, version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
sp-runtime = { default-features = false, version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
[dependencies.sp-std]
default-features = false
git = 'https://github.com/paritytech/substrate.git'
branch = 'polkadot-v0.9.26'
[features]
default = ["std"]
std = [
"sp-std/std",
"codec/std",
"scale-info/std",
"frame-support/std",
"frame-system/std",
"frame-benchmarking/std",
]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
try-runtime = ["frame-support/try-runtime"]
And I used command "cargo check -p node-template-runtime". But I got an Error like this.
ensure!(!Proofs::<T>::contains_key(&proof), Error::<T>::ProofAlreadyClaimed);
^^^^^^^^^^^^ function or associated item cannot be called on
`frame_support::pallet_prelude::StorageMap<_GeneratedPrefixForStorageProofs<T>, frame_support::Blake2_128Concat, Vec<u8>, (<T as frame_system::Config>::AccountId, <T as frame_system::Config>::BlockNumber), frame_support::pallet_prelude::ValueQuery>` due to unsatisfied trait bounds
Proofs::<T>::insert(&proof, (&sender, current_block));
^^^^^^ function or associated item cannot be called on `frame_support::pallet_prelude::StorageMap<_GeneratedPrefixForStorageProofs<T>, frame_support::Blake2_128Concat, Vec<u8>, (<T as frame_system::Config>::AccountId, <T as frame_system::Config>::BlockNumber), frame_support::pallet_prelude::ValueQuery>` due to unsatisfied trait bounds
ensure!(Proofs::<T>::contains_key(&proof),Error::<T>::NoSuchProof);
^^^^^^^^^^^^ function or associated item cannot be called on `frame_support::pallet_prelude::StorageMap<_GeneratedPrefixForStorageProofs<T>, frame_support::Blake2_128Concat, Vec<u8>, (<T as frame_system::Config>::AccountId, <T as frame_system::Config>::BlockNumber), frame_support::pallet_prelude::ValueQuery>` due to unsatisfied trait bounds
let (owner, _) = Proofs::<T>::get(&proof);
^^^ function or associated item cannot be called on `frame_support::pallet_prelude::StorageMap<_GeneratedPrefixForStorageProofs<T>, frame_support::Blake2_128Concat, Vec<u8>, (<T as frame_system::Config>::AccountId, <T as frame_system::Config>::BlockNumber), frame_support::pallet_prelude::ValueQuery>` due to unsatisfied trait bounds
Proofs::<T>::remove(&proof);
^^^^^^ function or associated item cannot be called on `frame_support::pallet_prelude::StorageMap<_GeneratedPrefixForStorageProofs<T>, frame_support::Blake2_128Concat, Vec<u8>, (<T as frame_system::Config>::AccountId, <T as frame_system::Config>::BlockNumber), frame_support::pallet_prelude::ValueQuery>` due to unsatisfied trait bounds
#[pallet::pallet]
^^^^^^ the trait `MaxEncodedLen` is not implemented for `Vec<u8>`
#[pallet::pallet]
^^^^^^ the trait `core::default::Default` is not implemented for `<T as frame_system::Config>::AccountId`
#[pallet::storage]
^^^^^^^ the trait `core::default::Default` is not implemented for `<T as frame_system::Config>::AccountId`
Somebody, Please help me. I beg you. What should I do next??

Related

How could I configure the reward for a substrate Aura validator?

Now that the PoA is running with multiple Aura validators in my substrate-node-template. How could I configure that reward amount or value for my Aura validators?
I got it working, PoA will reward the validator who created the block using the tip as the sample value for the fees, here are the steps:
Install the pallet_authorship
pallet-authorship = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.23" }
Configure the pallet to get the current author of the block
pub struct AuraAccountAdapter;
impl frame_support::traits::FindAuthor<AccountId> for AuraAccountAdapter {
fn find_author<'a, I>(digests: I) -> Option<AccountId>
where I: 'a + IntoIterator<Item=(frame_support::ConsensusEngineId, &'a [u8])>
{
pallet_aura::AuraAuthorId::<Runtime>::find_author(digests).and_then(|k| {
AccountId::try_from(k.as_ref()).ok()
})
}
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = AuraAccountAdapter;
type UncleGenerations = ();
type FilterUncle = ();
type EventHandler = ();
}
Create OnUnbalanced implementation of Author and DealWithFees
use crate::{Authorship, Balances};
use frame_support::traits::{Imbalance, OnUnbalanced};
use crate::sp_api_hidden_includes_construct_runtime::hidden_include::traits::Currency;
use crate::AccountId;
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author {
fn on_nonzero_unbalanced(amount: NegativeImbalance) {
if let Some(author) = Authorship::author() {
Balances::resolve_creating(&author, amount);
}
}
}
pub struct DealWithFees;
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
if let Some(fees) = fees_then_tips.next() {
let mut split = fees.ration(80, 20);
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 80% to treasury, 20% to block author (though this can be anything)
tips.ration_merge_into(80, 20, &mut split);
}
//Treasury::on_unbalanced(split.0);
Author::on_unbalanced(split.1);
}
}
}
Call the implementation in the pallet_transaction_payment tuple OnChargeTransaction
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = CurrencyAdapter<Balances, crate::impls::DealWithFees>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
}
Also added in my blog: https://hgminerva.wordpress.com/2022/06/21/how-to-pay-the-block-author-validator-on-a-proof-of-authority-poa-consensus-in-substrate/

Substrate pallet loosely coupling example between 2 custom pallets

This official docs is about custom pallet using an substrate's pallets.
https://docs.substrate.io/how-to-guides/v3/pallet-design/loose-coupling/#2-import-the-trait
I don't know exactly how to do this with 2 custom pallets?
Here how I dit it:
For example: pallet BoTrading need to call get_suitable_lp on pallet BoLiquidity
pallets/BoLiquidity/src/lib.rs
/// Internal helpers fn
impl<T: Config> Pallet<T> {
fn pick_a_suitable_lp() -> Option<u32> {
Some(99999)
}
}
pub trait BoLiquidityInterface{
fn get_suitable_lp()->Option<u32>;
}
impl<T: Config> BoLiquidityInterface for Pallet<T> {
fn get_suitable_lp()->Option<u32>{
Self::pick_a_suitable_lp()
}
}
pallets/BoTrading/src/lib.rs
pub mod pallet {
...
use pallet_bo_liquidity::BoLiquidityInterface;
#[pallet::config]
pub trait Config: frame_system::Config {
...
type BoLiquidity: BoLiquidityInterface;
}
...
// call other pallet some where inside this pallet:
let lp = T::BoLiquidity::get_suitable_lp();
...
}
pallets/BoTrading/Cargo.toml
[dependencies.pallet-bo-liquidity]
default-features = false
path = '../BoLiquidity'
version = '0.0.1-dev'
Remember to include pallets in cargo toml of the node runtime, this code bellow focus on important thing only:
runtime/src/lib.rs
impl pallet_bo_trading::Config for Runtime {
...
type BoLiquidity = BoLiquidityModule;
}
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
...
BoLiquidityModule: pallet_bo_liquidity,
}
);

How do you pass and handle arguments to a `ChainExtension`?

I have an ink! contract which calls a extension method 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()?;
How can can I write the extension handler to receive arguments such as let new_random = self.env().extension().fetch_random(1, "hello", true)?;?
You can have a complete example on GitHub here.
Here's the working code:
#![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, Clone, PartialEq, 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]);
}
}
}
You should be able to access the arguments through one of the functions on the <'a, 'b, E: Ext, S: state::BufIn> Environment<'a, 'b, E, S> implementation of Environment, e.g. read, read_as, read_as_unbounded. Please see the Environment struct for more information on this.
The rand-extension example you've cited here has also been updated to demonstrate passing an argument to the chain extension in the runtime. See that example here. You should be able to follow that example and implement the changes.

How to export Substrate native interface to runtime?

I'm trying link the substrate tutorial (https://github.com/substrate-developer-hub/substrate-node-template) to some C library. I wrapped the C library to a crate called cfun, which can called by the node layer.
I figured out I can use the marco runtime_interface to export the native interface for my pallets to call. However, although I can compile successfully, the wasm runtime cannot instantiate.
Any idea what is happening?
// node/cfun/src/lib.rs
#![cfg_attr(not(feature = "std"), no_std)]
#[link(name = "test", kind = "static")]
extern "C" {
pub fn double_int(input: i32) -> i32;
pub fn double_uint(input: u32) -> u32;
}
# node/cint/Cargo.toml
[package]
edition = '2018'
name = 'cint'
version = '2.0.1'
[dependencies]
# local dependencies
sp-runtime-interface = { version = "2.0.1", default-features = false}
cfun = { path = '../cfun', default-features = false, version = '2.0.1', optional = true }
[features]
default = ['std']
std = [
'sp-runtime-interface/std',
'cfun',
]
// node/cint/src/lib.rs
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate cfun;
use sp_runtime_interface::runtime_interface;
#[runtime_interface]
pub trait CFunctions {
fn c_double_uint(input: u32) -> u32 {
unsafe {
cfun::double_uint(input)
}
}
}
// pallets/template/src/lib.rs
// import module at the beginning
extern crate cint;
// ...
// modify the original `do_something` function
// from:
// Something::put(something);
// to:
let smt = cint::c_functions::c_double_uint(something);
Something::put(smt);
Edited 1
# pallets/template.Cargo.toml and runtime/Cargo.toml
# path is a bit different, but both included all interfaces
[dependencies]
# ...
sp-runtime-interface = { version = "2.0.1", default-features = false}
cfun = { path = '../../node/cfun', default-features = false, version = '2.0.1', optional = true }
cint = { path = '../../node/cint', default-features = false, version = '2.0.1'}
[features]
default = ['std']
std = [
# ...
'sp-runtime/std',
'cfun',
'cint/std',
]
Repo:
https://github.com/killalau/substrate-node-template/tree/franky

How do I access storage and functions in a pallet from another pallet?

I have one common pallet which is to be used by other pallets. For example, below is the common shared pallet:
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod tests;
pub trait Trait: system::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;
}
type AccountIdOf<T> = <T as system::Trait>::AccountId;
type BalanceOf<T> = <<T as Trait>::Currency as Currency<AccountIdOf<T>>>::Balance;
type StructInfoOf<T> = StructInfo<AccountIdOf<T>, <T as system::Trait>::BlockNumber>;
#[derive(Encode, Decode, Default, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct StructInfo<AccountId, BlockNumber> {
name: Vec<u8>,
owner: AccountId,
created: BlockNumber,
}
decl_storage! {
trait Store for Module<T: Trait> as TokenStore {
pub Data get(fn data): map hasher(blake2_128_concat) u32 => Option<StructInfoOf<T>>;
pub DataCount get(fn data_count): u32;
}
}
decl_event!(
pub enum Event<T>
where
AccountId = <T as system::Trait>::AccountId,
Balance = BalanceOf<T>,
{
/// Test event
TestEvent(u32, Balance, AccountId),
}
);
decl_error! {
pub enum Error for Module<T: Trait> {
TestError
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event() = default;
#[weight = 10_000]
pub fn test_dispatch_call(origin) -> DispatchResult {
let caller = ensure_signed(origin)?;
Ok(())
}
}
}
impl<T: Trait> Module<T> {
pub fn public_function(value: u32) -> BalanceOf<T> {
let value: u32 = 0;
Self::data_count()
}
}
but I am not sure how I can call Data, DataCount, test_dispatch_call, public_function from the common module.
Add your pallet that need in Cargo.toml in [dependencies] like pallet-test = {default-features = false, path ='../test'} and in [features] [std] like 'pallet-test/std'
In current pallet: add pallet-test in pub trait Trait (v2) or pub trait Config(v3) like pub trait Config: frame_system::Config + pallet_test::Config{}
Access Function: <pallet_test::Module<T>>::function_test();

Resources