How to implement the ethereum virtual machine pallet? - substrate

Im trying to implement the pallet_evm to my substrate runtime
i've seen this handy instruction but the types have changed
How to implement the EVM Trait for a Substrate Runtime?
impl FeeCalculator for FixedGasPrice {
fn min_gas_price() -> U256 {
// Gas price is always one token per gas.
1.into()
}
}
parameter_types! {
pub const ChainId: u64 = 43;
}
impl pallet_evm::Trait for Runtime {
type FeeCalculator = FixedGasPrice;
type CallOrigin = EnsureAddressOrigin<AccountId, Success = AccountId>;
type WithdrawOrigin = EnsureAddressOrigin<AccountId, Success = AccountId>;
type AddressMapping = AddressMapping<AccountId>;
type Currency = balances::Module<Runtime>;
type Event = Event;
type ChainId = ChainId;
}
how do we implement this pallet now with rc-5?

Related

How to get the AccountId of the contract instantiated in the contract in Substrate ink

I want to instantiate another contract inside a contract and get the AccountId of that contract.
Can anyone tell me how to do that?
Instantiate SampleContract2 in the add_contract function of SampleContract1.
I want to get the AccountId of the instantiated SampleContract2, manage it in a list, and use the AccountId later to be able to access SmapleContract2.
In the future, I would like to increase the types of contracts, so I would like to use AccountId, which can be used for general purposes, instead of the SmapleContract2 type for the list.
Why does "sample_contract_2.env().account_id()" return the address of SampleContract1?
-- snip --
#[ink(storage)]
pub struct SampleContract1 {
next_id:u128,
account_id_list:Mapping<u128, AccountId>
}
-- snip --
impl SampleContract1 {
#[ink(constructor)]
pub fn new() -> Self {
Self {
account_id_list: Mapping::default(),
next_id:0,
}
}
#[ink(message)]
pub fn add_contract(&mut self ) -> Result<()> {
let sample_contract_2 = SampleContract2::new();
let contract_address = sample_contract_2.env().account_id(); <- ###### Address of SampleContract1 is obtained.
self.token_list.insert(&self.next_id, &contract_address );
self.next_id = self.next_id + 1;
Ok(())
}
Thank you.

How should I initialize interface types from the windows crate?

I have a struct that uses some types from the windows crate, but I'm not able to initialize them:
use windows::Win32::{
IUIAutomationFocusChangedEventHandler, IUIAutomationFocusChangedEventHandler_Vtbl,
};
// Here's my struct:
pub struct EventHandler {
// A struct member to handle the event:
event: IUIAutomationFocusChangedEventHandler,
event_vtbl: IUIAutomationFocusChangedEventHandler_Vtbl,
}
// Anyone with experience in the windows API
// Will understand the Virtual tables, and this code.
impl EventHandler {
pub fn new() -> EventHandler {
// Here, I should return a new instance of my struct:
EventHandler {
// Now, I should initialize every struct member:
event: IUIAutomationFocusChangedEventHandler {}, // ...
event_vtbl: IUIAutomationFocusChangedEventHandler_Vtbl {
// This struct needs two members:
base__: IUnknown {}, // IUnknown requires a lot of
// methods and member initialization to initialize it.
// Also the IUIAutomationFocusChangedEvent needs too member initialization....
},
}
}
}
These structs shouldn't be initialized in C++ winapi. I don't know what should I do. Every struct needs member initialization, and every member needs other members, and other members need member initialization!
I feel like I'm in a whirlpool! Am I missing something?
Answering the literal question first: You could, but you probably shouldn't have to.
COM support in the windows crate exposes many types, and not all of them are meant for immediate use by client code. The *_Vtbl structures specifically represent the raw function pointer tables used by COM internally to dispatch interface calls. They are declared and populated by the library and not intended to be used by clients directly (the #[doc(hidden)] attribute is a hint, though I'm sure the library structure and documentation experience can be improved).
Attempting to populate the v-tables in client code puts you into a miserable situation. Luckily, none of that is required, as briefly explained in the FAQ:
How do I implement an existing COM interface?
If you need to implement a COM interface for a type, you'll need to add the implement feature which (like any Cargo feature) can be enabled in your project's Cargo.toml file.
windows = { version = "..", features = ["implement"] }
Then you'll need to declare that your type implements a particular interface by adding the #[implement] proc macro to your type and then writing an impl block for the interface. For an interface called IMyInterface you will need to implement the IMyInterface_Impl trait (note the trailing _Impl in the name).
#[windows::core::implement(IMyInterface)]
struct MyStruct;
impl IMyInterface_Impl for MyStruct {
fn MyMethod(&self) -> windows::core::HRESULT {
todo!("Your implementation goes here");
}
}
Version 0.37.0 made significant changes to the implement macro, making this far more approachable than it may appear. Let's start out by declaring a simple structure with a bit of state information:
#[implement(IUIAutomationFocusChangedEventHandler)]
struct EventHandler {
count: Cell<u64>,
}
impl EventHandler {
fn new() -> Self {
Self {
count: Cell::new(0),
}
}
/// Increments the count and returns the new value
fn increment(&self) -> u64 {
let new_val = self.count.get() + 1;
self.count.set(new_val);
new_val
}
}
This keeps a cumulative count of focus change events that happened. Note that the implementation isn't actually correct: Since the event handler can be called from multiple threads we'd actually need a type that's Sync (which Cell isn't). That's something you'd need to change1.
What's missing is the IUIAutomationFocusChangedEventHandler interface implementation. It only has a single member, so that's easy (the IUnknown implementation is conveniently provided for you by the library already):
impl IUIAutomationFocusChangedEventHandler_Impl for EventHandler {
fn HandleFocusChangedEvent(&self, _sender: &Option<IUIAutomationElement>) -> Result<()> {
let count = self.increment();
println!("Focus changed (cumulative count: {})", count);
Ok(())
}
}
For every focus change event it first increments the cumulative count and then prints a message to STDOUT.
That's all that's required to implement a custom IUIAutomationFocusChangedEventHandler interface. Using that from a program isn't much harder, either, even though there are a lot of pitfalls (see comments):
fn main() -> Result<()> {
// Initialize COM for the current thread. Since we are running event handlers on this
// thread, it needs to live in the MTA.
// See [Understanding Threading Issues](https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-threading)
// for more information.
unsafe { CoInitializeEx(ptr::null(), COINIT_APARTMENTTHREADED) }?;
// Instantiate a `CUIAutomation` object
let uia: IUIAutomation =
unsafe { CoCreateInstance(&CUIAutomation, None, CLSCTX_INPROC_SERVER) }?;
// Subscribe to the focus changed event; this transfers ownership of `handler` into
// `uia`, making it the sole owner
let handler = EventHandler::new();
unsafe { uia.AddFocusChangedEventHandler(None, &handler.into()) }?;
// Display a message box so that we have an easy way to quit the program
let _ = unsafe {
MessageBoxW(
None,
w!("Click OK to end the program"),
w!("UIA Focus Monitor"),
MB_OK,
)
};
// Optionally unsubscribe from all events; this is not strictly required since we have
// to assume that the `CUIAutomation` object properly manages the lifetime of our
// `EventHandler` object
unsafe { uia.RemoveAllEventHandlers() }?;
// IMPORTANT: Do NOT call `CoUninitialize()` here. `uia`'s `Drop` implementation will
// get very angry at us when it runs after COM has been uninitialized
Ok(())
}
To compile the code you'll want to use the following imports:
use std::{cell::Cell, ptr};
use windows::{
core::{implement, Result},
w,
Win32::{
System::Com::{
CoCreateInstance, CoInitializeEx, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED,
},
UI::{
Accessibility::{
CUIAutomation, IUIAutomation, IUIAutomationElement,
IUIAutomationFocusChangedEventHandler, IUIAutomationFocusChangedEventHandler_Impl,
},
WindowsAndMessaging::{MessageBoxW, MB_OK},
},
},
};
and this Cargo.toml file:
[package]
name = "uia_focus_change"
version = "0.0.0"
edition = "2021"
[dependencies.windows]
version = "0.39.0"
features = [
"implement",
"Win32_Foundation",
"Win32_System_Com",
"Win32_UI_Accessibility",
"Win32_UI_WindowsAndMessaging",
]
1 Possible alternatives include an AtomicU64 and a Mutex. An atomic is perfectly sufficient here, is easy to use, and will properly work in situations of re-entrancy:
use std::sync::atomic::{AtomicU64, Ordering};
#[implement(IUIAutomationFocusChangedEventHandler)]
struct EventHandler {
count: AtomicU64,
}
impl EventHandler {
fn new() -> Self {
Self {
count: AtomicU64::new(0),
}
}
/// Increments the count and returns the new value
fn increment(&self) -> u64 {
self.count.fetch_add(1, Ordering::SeqCst) + 1
}
}
A mutex, on the other hand, is substantially harder to use, its behavior in part unspecified, and equipped with lots of opportunities to fail. On the upside it is more versatile in protecting arbitrarily large structures:
use std::sync::Mutex;
#[implement(IUIAutomationFocusChangedEventHandler)]
struct EventHandler {
count: Mutex<u64>,
}
impl EventHandler {
fn new() -> Self {
Self {
count: Mutex::new(0),
}
}
/// Increments the count and returns the new value
fn increment(&self) -> u64 {
let mut guard = self.count.lock().expect("Failed to lock mutex");
*guard += 1;
*guard
}
}
Either one works and is compatible with COM objects that live in the MTA.

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/

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.

String attribute set in init method always returns empty string

I have the following struct with impl:
#[near_bindgen]
#[derive(Default, Serialize, Deserialize, BorshDeserialize, BorshSerialize, Debug)]
pub struct MyStruct {
owner: String
}
#[near_bindgen(init => new)]
impl MyStruct {
fn new() -> Self {
Self {
owner: "bob".to_string()
}
}
fn get_owner(&self) -> String {
return self.owner;
}
}
Then I deploy the contract using near deploy my_contract --masterAccount myAccount
If I call get_owner using near-shell: near call my_contract get_owner --accountId=myAccount It always returns "" instead of the expected "bob".
It seems like the new method might not get called on deployment.
Initializer doesn't automatically get called on deploy. deploy just deploys the code and doesn't call anything on the contract. We should probably add a new method to shell, that does deploy_and_call. But for now just call new manually.
The reason why we don't initialize automatically is that initializer might take additional arguments. You can pass an owner to new method. Here is an example how to use initializer with custom arguments and as well as how to make sure a contract can't be called without initialization:
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct FunToken {
/// AccountID -> Account details.
pub accounts: Map<AccountId, Account>,
/// Total supply of the all token.
pub total_supply: Balance,
}
impl Default for FunToken {
fn default() -> Self {
env::panic(b"Not initialized");
unreachable!();
}
}
#[near_bindgen(init => new)]
impl FunToken {
pub fn new(owner_id: AccountId, total_supply: Balance) -> Self {
let mut ft = Self { accounts: Map::new(b"a".to_vec()), total_supply };
let mut account = ft.get_account(&owner_id);
account.balance = total_supply;
ft.accounts.insert(&owner_id, &account);
ft
}
}
From here: https://github.com/nearprotocol/near-bindgen/blob/master/examples/fun-token/src/lib.rs#L52-L77
Basically it panics during Default call, so non initialized contract can't be called.
Initializer functions are usually used when you need to parametrize the initialization of the contract. If there are no parameters then just implement Default trait:
impl Default for MyStruct {
fn default() -> Self {
Self {
owner: "bob".to_string()
}
}}

Resources