forked from polkadot-evm/frontier
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add initial impl of evm-system * Check account existence * Improve creation account logic * Add new line * Add default implementations * Add mock * Use DispatchResult instead of custom enums * Basic create account tests * Add simple tests with remove account and nonce update * Remove default implementations for OnNewAccount and OnKilledAccount * Add mock objects for OnNewAccount and OnKilledAccount * Use mock logic in tests * Some tests improvements * Add docs to tests * Check events in tests
- Loading branch information
1 parent
5d21c6d
commit 1bb8d88
Showing
6 changed files
with
504 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
[package] | ||
name = "pallet-evm-system" | ||
version = "1.0.0-dev" | ||
license = "Apache-2.0" | ||
description = "FRAME EVM SYSTEM pallet." | ||
authors = { workspace = true } | ||
edition = { workspace = true } | ||
repository = { workspace = true } | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] | ||
|
||
[dependencies] | ||
log = { version = "0.4.17", default-features = false } | ||
scale-codec = { package = "parity-scale-codec", workspace = true } | ||
scale-info = { workspace = true } | ||
# Substrate | ||
frame-support = { workspace = true } | ||
frame-system = { workspace = true } | ||
sp-runtime = { workspace = true } | ||
sp-std = { workspace = true } | ||
|
||
[dev-dependencies] | ||
mockall = "0.11" | ||
sp-core = { workspace = true } | ||
sp-io = { workspace = true } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"log/std", | ||
"scale-codec/std", | ||
"scale-info/std", | ||
# Substrate | ||
"frame-support/std", | ||
"frame-system/std", | ||
"sp-runtime/std", | ||
"sp-std/std", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// This file is part of Frontier. | ||
// | ||
// Copyright (c) 2020-2022 Parity Technologies (UK) Ltd. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//! # EVM System Pallet. | ||
// Ensure we're `no_std` when compiling for Wasm. | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
use sp_runtime::{traits::One, RuntimeDebug, DispatchResult}; | ||
use scale_codec::{Encode, Decode, MaxEncodedLen, FullCodec}; | ||
use scale_info::TypeInfo; | ||
|
||
#[cfg(test)] | ||
mod mock; | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
pub use pallet::*; | ||
|
||
/// Account information. | ||
#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] | ||
pub struct AccountInfo<Index, AccountData> { | ||
/// The number of transactions this account has sent. | ||
pub nonce: Index, | ||
/// The additional data that belongs to this account. Used to store the balance(s) in a lot of | ||
/// chains. | ||
pub data: AccountData, | ||
} | ||
|
||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use super::*; | ||
use frame_support::pallet_prelude::*; | ||
use sp_runtime::traits::{MaybeDisplay, AtLeast32Bit}; | ||
use sp_std::fmt::Debug; | ||
|
||
#[pallet::pallet] | ||
#[pallet::generate_store(pub(super) trait Store)] | ||
#[pallet::without_storage_info] | ||
pub struct Pallet<T>(PhantomData<T>); | ||
|
||
#[pallet::config] | ||
pub trait Config: frame_system::Config { | ||
/// The overarching event type. | ||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; | ||
|
||
/// The user account identifier type. | ||
type AccountId: Parameter | ||
+ Member | ||
+ MaybeSerializeDeserialize | ||
+ Debug | ||
+ MaybeDisplay | ||
+ Ord | ||
+ MaxEncodedLen; | ||
|
||
/// Account index (aka nonce) type. This stores the number of previous transactions | ||
/// associated with a sender account. | ||
type Index: Parameter | ||
+ Member | ||
+ MaybeSerializeDeserialize | ||
+ Debug | ||
+ Default | ||
+ MaybeDisplay | ||
+ AtLeast32Bit | ||
+ Copy | ||
+ MaxEncodedLen; | ||
|
||
/// Data to be associated with an account (other than nonce/transaction counter, which this | ||
/// pallet does regardless). | ||
type AccountData: Member + FullCodec + Clone + Default + TypeInfo + MaxEncodedLen; | ||
|
||
/// Handler for when a new account has just been created. | ||
type OnNewAccount: OnNewAccount<<Self as Config>::AccountId>; | ||
|
||
/// A function that is invoked when an account has been determined to be dead. | ||
/// | ||
/// All resources should be cleaned up associated with the given account. | ||
type OnKilledAccount: OnKilledAccount<<Self as Config>::AccountId>; | ||
} | ||
|
||
/// The full account information for a particular account ID. | ||
#[pallet::storage] | ||
#[pallet::getter(fn full_account)] | ||
pub type FullAccount<T: Config> = StorageMap< | ||
_, | ||
Blake2_128Concat, | ||
<T as Config>::AccountId, | ||
AccountInfo<<T as Config>::Index, <T as Config>::AccountData>, | ||
ValueQuery, | ||
>; | ||
|
||
#[pallet::event] | ||
#[pallet::generate_deposit(pub(super) fn deposit_event)] | ||
pub enum Event<T: Config> { | ||
/// A new account was created. | ||
NewAccount { account: <T as Config>::AccountId }, | ||
/// An account was reaped. | ||
KilledAccount { account: <T as Config>::AccountId }, | ||
} | ||
|
||
#[pallet::error] | ||
pub enum Error<T> { | ||
/// The account already exists in case creating it. | ||
AccountAlreadyExist, | ||
/// The account doesn't exist in case removing it. | ||
AccountNotExist, | ||
} | ||
} | ||
|
||
impl<T: Config> Pallet<T> { | ||
/// Check the account existence. | ||
pub fn account_exists(who: &<T as Config>::AccountId) -> bool { | ||
FullAccount::<T>::contains_key(who) | ||
} | ||
|
||
/// An account is being created. | ||
fn on_created_account(who: <T as Config>::AccountId) { | ||
<T as Config>::OnNewAccount::on_new_account(&who); | ||
Self::deposit_event(Event::NewAccount { account: who }); | ||
} | ||
|
||
/// Do anything that needs to be done after an account has been killed. | ||
fn on_killed_account(who: <T as Config>::AccountId) { | ||
<T as Config>::OnKilledAccount::on_killed_account(&who); | ||
Self::deposit_event(Event::KilledAccount { account: who }); | ||
} | ||
|
||
/// Retrieve the account transaction counter from storage. | ||
pub fn account_nonce(who: &<T as Config>::AccountId) -> <T as Config>::Index { | ||
FullAccount::<T>::get(who).nonce | ||
} | ||
|
||
/// Increment a particular account's nonce by 1. | ||
pub fn inc_account_nonce(who: &<T as Config>::AccountId) { | ||
FullAccount::<T>::mutate(who, |a| a.nonce += <T as pallet::Config>::Index::one()); | ||
} | ||
|
||
/// Create an account. | ||
pub fn create_account(who: &<T as Config>::AccountId) -> DispatchResult { | ||
if Self::account_exists(who) { | ||
return Err(Error::<T>::AccountAlreadyExist.into()); | ||
} | ||
|
||
FullAccount::<T>::insert(who.clone(), AccountInfo::<_, _>::default()); | ||
Self::on_created_account(who.clone()); | ||
Ok(()) | ||
} | ||
|
||
/// Remove an account. | ||
pub fn remove_account(who: &<T as Config>::AccountId) -> DispatchResult { | ||
if !Self::account_exists(who) { | ||
return Err(Error::<T>::AccountNotExist.into()); | ||
} | ||
|
||
FullAccount::<T>::remove(who); | ||
Self::on_killed_account(who.clone()); | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// Interface to handle account creation. | ||
pub trait OnNewAccount<AccountId> { | ||
/// A new account `who` has been registered. | ||
fn on_new_account(who: &AccountId); | ||
} | ||
|
||
/// Interface to handle account killing. | ||
pub trait OnKilledAccount<AccountId> { | ||
/// The account with the given id was reaped. | ||
fn on_killed_account(who: &AccountId); | ||
} |
Oops, something went wrong.