기판 팔레트 코드 분석: Sudo
개요
기판 기반 체인에는 sudo 계정이라는 특권 기능을 호출할 수 있는 신과 같은 계정이 있습니다. sudo 계정이 할 수 있는 기능으로 구성된 sudo 팔레트. 런타임에는 'sudo-key'라고 하는 하나의 sudo 계정만 있어야 합니다. 퍼블릭 블록체인 네트워크를 시작하기 전에 sudo 계정이 있으면 유용할 수 있지만 시작 후 대부분의 Parachain 프로젝트는 안전을 위해 이 Sudo 팔레트를 제거하는 경향이 있습니다.
이 팔레트가 어떻게 구현되는지 살펴보겠습니다.
소스 코드 분석
저장
이 팔레트에는 하나의 스토리지만 있습니다. 저장소 유형은 런타임에 대해 하나의 sudo 키 계정만 저장하는 StorageValue입니다.
#[pallet::storage]
#[pallet::getter(fn key)]
pub(super) type Key<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;
파견 호출
스도
Dispatch a call with Root origin.
Params
- origin: who calls this function
- call: Some Call type like dispatch calls. When building runtime, Compiler collects all the Call type into one single Call Enum type by #[pallet::call] macro. Code below is how Substrate deals with Call data type.
런타임에서
pub enum Call { System( <Pallet<Runtime> as Callable<Runtime>>::Call ), Balances( <Pallet<Runtime> as Callable<Runtime>>::Call ), Staking( <Pallet<Runtime> as Callable<Runtime>>::Call ), ... }
예를 들어 Staking Pallet에서 모든 디스패치 호출은 Call enum 유형으로 정의됩니다.
pub enum Call { ... Staking(pallet_staking::Call::<Runtime>) ... } pub enum Call { bond { controller, value, payee }, nominate { targets } .... }
분석출처가 서명되었는지 확인하십시오. 호출자가 'sudo 키 계정'인지 확인합니다 .dispatch_bypass_filter: 디스패치 호출에서 원본 필터 확인을 건너뜁니다. 'Sudid' 이벤트 발생 Sudo 계정이 수수료를 지불하지 않음
pub fn sudo( origin: OriginFor<T>, call: Box<<T as Config>::Call>, ) -> DispatchResultWithPostInfo { // 1 let sender = ensure_signed(origin)?; // 2 ensure!(Self::key().map_or(false, |k| sender == k), Error::<T>::RequireSudo); // 3 let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); // 4 Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) }); // 5 Ok(Pays::No.into()) }
sudo_unchecked_weight
The logic of this method is same with _sudo but this time, Sudo account can control the Weight of the call. As we can see the parameter we give as _weight is used in the weight calculation in #[pallet::weight((*_weight, call.get_dispatch_info().class))] macro._
Params
- _weight: Amount of weight sudo want to control
#[pallet::weight((*_weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor<T>, call: Box<<T as Config>::Call>, _weight: Weight, ) -> DispatchResultWithPostInfo { // Same logic with sudo }
set_key
Set sudo key with different account
Params
- new: New sudo key account. Type is Source type of StaticLookup trait. This type is for converting any source type into AccountId. Let's take a closer look!
먼저 StaticLookup은 다음과 같이 정의됩니다.유형 소스: 보고자 하는 모든 유형 type Target: 변환하려는 유형 fn 조회: 소스 유형을 대상 유형으로 변환 fn unlookup: 대상 유형을 소스 유형으로 변환
pub trait StaticLookup { // 1 pub type Source; // 2 pub type Target; // 3 fn lookup(s: Self::Source) -> Result<Self::Target, LookupError> // 4 fn unlookup(t: Self::Target) -> Self::Source; }
프레임 시스템 팔레트에서 Target은 AccountId 유형으로 정의되며 조회 메소드를 호출하면 찾고자 하는 모든 Source 유형을 AccountId 유형으로 변환할 수 있습니다.
pub trait Config { ... type lookup: StaticLookup<Target = AccountId> ... }
Runtime에서 frame_system의 config가 Runtime에 어떻게 구현되어 있는지 살펴보면 palette_indices가 lookup으로 정의되어 있습니다. 즉, palette_indices는 StaticLookup 트레이트를 구현해야 합니다.
impl frame_system::Config for Runtime { ... type lookup = Indices(pallet_indices) ... }
내부 palette_indicesPallet용 정적 조회 구현 다중 주소: 주소 형식의 유형 fn lookup_address(): 주소 형식에 따라 존재하는 경우 주소를 반환합니다. 여기서 찾고 있는 주소 형식의 유형은 Account Id 및 AccountIndex입니다.
// 1 impl<T: Config> StaticLookup for Pallet<T> { type Source = MultiAddress<T::AccountId, T::AccountIndex>, type Target = T::AccountId, fn lookup(a: Self::Source) -> Result<Self::Target, LookupError> { Self::lookup_address(a).ok_or(LookupError); } fn unlookup(a: Self::Target) -> Self::Source { Multiaddress::Id(a) } } // 2 pub enum MultiAddress<AccountId, AccountIndex> { Id(AccountId), // public address Index(AccountIndex), // Account index for database ... } // 3 impl<T: Config> Pallet<T> { fn lookup_index(index: T::AccountIndex) -> Option<T::AccountId> { // where Accounts is a storage that maps _AccountIndex_ to (AccountId, Balance) Accounts::<T>::get(index).map(|x| x.0) } fn lookup_address(a: Multiaddress<T::AccountId, T::AccountIndex> -> Option<T::AccountId> { match a { Multiaddress::Id(account) => Some(account) Multiaddress::Index(index) => Self::lookup_index(index) } } } #[pallet::storage] pub type Accounts<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountIndex, (T::AccountId, BalanceOf<T>, bool)>;
분석출처가 서명되었는지 확인하십시오. 호출자가 'sudo 키 계정'인지 확인합니다 .MultiAddress 유형을 AccountId로 변환합니다. 'KeyChanged' 이벤트 발생 키 저장소에 새 sudo 키 넣기 Sudo는 수수료를 지불하지 않습니다.
#[pallet::weight(0)] pub fn set_key( origin: OriginFor<T>, new: <T::Lookup as StaticLookup>::Source, ) -> DispatchResultWithPostInfo { // 1 let sender = ensure_signed(origin)?; // 2 ensure!(Self::key().map_or(false, |k| sender == k), Error::<T>::RequireSudo); // 3 let new = T::Lookup::lookup(new)?; // 4 Self::deposit_event(Event::KeyChanged { old_sudoer: Key::<T>::get() }); // 5 Key::<T>::put(&new); // 6 Ok(Pays::No.into()) }
sudo_as
Sudo account calls and dispatches a call with a signed account.
Make signed account as sudo account which pays no fee
Params
- who: The one who calls the dispatch call
pub fn sudo_as( origin: OriginFor<T>, who: <T::Lookup as StaticLookup>::Source, call: Box<<T as Config>::Call>, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; ensure!(Self::key().map_or(false, |k| sender == k), Error::<T>::RequireSudo); let who = T::Lookup::lookup(who)?; let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Signed(who).into()); Self::deposit_event(Event::SudoAsDone { sudo_result: res.map(|_| ()).map_err(|e| e.error), }); Ok(Pays::No.into()) }
결론
Sudo는 모든 것을 할 수 있는 Substrate 기반 체인에만 존재하는 특별한 기능이며 퍼블릭 블록체인에서는 선호되지 않습니다.
질문이 있으시면 언제든지 의견을 남겨주세요.
참조
Sudo
Frame System
Indices
Reference
이 문제에 관하여(기판 팔레트 코드 분석: Sudo), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/cocoyoon/substrate-pallet-code-analysis-sudo-45kp텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)