Allow pallet error enum variants to contain fields (#10242)

* Allow pallet errors to contain at most one field

* Update docs on pallet::error

* Reword documentation

* cargo fmt

* Introduce CompactPalletError trait and require #[pallet::error] fields to implement them

* cargo fmt

* Do not assume tuple variants

* Add CompactPalletError derive macro

* Check for error type compactness in construct_runtime

* cargo fmt

* Derive CompactPalletError instead of implementing it directly during macro expansion

* Implement CompactPalletError on OptionBool instead of Option<bool>

* Check for type idents instead of variant ident

* Add doc comments for ErrorCompactnessTest

* Add an trait implementation of ErrorCompactnessTest for ()

* Convert the error field of DispatchError to a 4-element byte array

* Add static check for pallet error size

* Rename to MAX_PALLET_ERROR_ENCODED_SIZE

* Remove ErrorCompactnessTest trait

* Remove check_compactness

* Return only the most significant byte when constructing a custom InvalidTransaction

* Rename CompactPalletError to PalletError

* Use counter to generate unique idents for assert macros

* Make declarative pallet macros compile with pallet error size checks

* Remove unused doc comment

* Try and fix build errors

* Fix build errors

* Add macro_use for some test modules

* Test fix

* Fix compilation errors

* Remove unneeded #[macro_use]

* Resolve import ambiguity

* Make path to pallet Error enum more specific

* Fix test expectation

* Disambiguate imports

* Fix test expectations

* Revert appending pallet module name to path

* Rename bags_list::list::Error to BagError

* Fixes

* Fixes

* Fixes

* Fix test expectations

* Fix test expectation

* Add more implementations for PalletError

* Lift the 1-field requirement for nested pallet errors

* Fix UI test expectation

* Remove PalletError impl for OptionBool

* Use saturating operations

* cargo fmt

* Delete obsolete test

* Fix test expectation

* Try and use assert macro in const context

* Pull out the pallet error size check macro

* Fix UI test for const assertion

* cargo fmt

* Apply clippy suggestion

* Fix doc comment

* Docs for create_tt_return_macro

* Ensure TryInto is imported in earlier Rust editions

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Fix up comments and names

* Implement PalletError for Never

* cargo fmt

* Don't compile example code

* Bump API version for block builder

* Factor in codec attributes while derving PalletError

* Rename module and fix unit test

* Add missing attribute

* Check API version and convert ApplyExtrinsicResult accordingly

* Rename BagError to ListError

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Use codec crate re-exported from frame support

* Add links to types mentioned in doc comments

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* cargo fmt

* cargo fmt

* Re-add attribute for hidden docs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
Keith Yeung
2022-03-24 09:11:14 +01:00
committed by GitHub
parent 5c9f23af13
commit 208be86934
38 changed files with 1263 additions and 241 deletions
@@ -271,139 +271,95 @@ pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
mod origin_test {
use super::{module3, nested, system, Block, UncheckedExtrinsic};
use frame_support::traits::{Contains, OriginTrait};
impl nested::module3::Config for RuntimeOriginTest {}
impl module3::Config for RuntimeOriginTest {}
pub struct BaseCallFilter;
impl Contains<Call> for BaseCallFilter {
fn contains(c: &Call) -> bool {
match c {
Call::NestedModule3(_) => true,
_ => false,
}
}
}
impl system::Config for RuntimeOriginTest {
type BaseCallFilter = BaseCallFilter;
type Hash = super::H256;
type Origin = Origin;
type BlockNumber = super::BlockNumber;
type AccountId = u32;
type Event = Event;
type PalletInfo = PalletInfo;
type Call = Call;
type DbWeight = ();
}
frame_support::construct_runtime!(
pub enum RuntimeOriginTest where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system::{Pallet, Event<T>, Origin<T>},
NestedModule3: nested::module3::{Pallet, Origin, Call},
Module3: module3::{Pallet, Origin<T>, Call},
}
);
#[test]
fn origin_default_filter() {
let accepted_call = nested::module3::Call::fail {}.into();
let rejected_call = module3::Call::fail {}.into();
assert_eq!(Origin::root().filter_call(&accepted_call), true);
assert_eq!(Origin::root().filter_call(&rejected_call), true);
assert_eq!(Origin::none().filter_call(&accepted_call), true);
assert_eq!(Origin::none().filter_call(&rejected_call), false);
assert_eq!(Origin::signed(0).filter_call(&accepted_call), true);
assert_eq!(Origin::signed(0).filter_call(&rejected_call), false);
assert_eq!(Origin::from(Some(0)).filter_call(&accepted_call), true);
assert_eq!(Origin::from(Some(0)).filter_call(&rejected_call), false);
assert_eq!(Origin::from(None).filter_call(&accepted_call), true);
assert_eq!(Origin::from(None).filter_call(&rejected_call), false);
assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&accepted_call), true);
assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&rejected_call), false);
let mut origin = Origin::from(Some(0));
origin.add_filter(|c| matches!(c, Call::Module3(_)));
assert_eq!(origin.filter_call(&accepted_call), false);
assert_eq!(origin.filter_call(&rejected_call), false);
// Now test for root origin and filters:
let mut origin = Origin::from(Some(0));
origin.set_caller_from(Origin::root());
assert!(matches!(origin.caller, OriginCaller::system(super::system::RawOrigin::Root)));
// Root origin bypass all filter.
assert_eq!(origin.filter_call(&accepted_call), true);
assert_eq!(origin.filter_call(&rejected_call), true);
origin.set_caller_from(Origin::from(Some(0)));
// Back to another signed origin, the filtered are now effective again
assert_eq!(origin.filter_call(&accepted_call), true);
assert_eq!(origin.filter_call(&rejected_call), false);
origin.set_caller_from(Origin::root());
origin.reset_filter();
// Root origin bypass all filter, even when they are reset.
assert_eq!(origin.filter_call(&accepted_call), true);
assert_eq!(origin.filter_call(&rejected_call), true);
}
}
#[test]
fn check_modules_error_type() {
assert_eq!(
Module1_1::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 31, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 31,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module2::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 32, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 32,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_2::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 33, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 33,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
NestedModule3::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 34, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 34,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_3::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 6, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 6,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_4::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 3, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 3,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_5::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 4, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 4,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_6::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 1, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 1,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_7::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 2, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 2,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_8::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 12, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 12,
error: [0; 4],
message: Some("Something")
})),
);
assert_eq!(
Module1_9::fail(system::Origin::<Runtime>::Root.into()),
Err(DispatchError::Module(ModuleError { index: 13, error: 0, message: Some("Something") })),
Err(DispatchError::Module(ModuleError {
index: 13,
error: [0; 4],
message: Some("Something")
})),
);
}