2. Add the Nicks Pallet to your Runtime

코와->코어·2022년 4월 24일
0

Substrate 공부하기

목록 보기
4/8
post-thumbnail

원문

Add the Nicks Pallet to your Runtime: 런타임에 닉스 팔레트를 추가하기

'당신의 첫 번째 substrate 블록체인을 만들어 보세요' 튜토리얼에서 봤듯이, Substrate의 노드 템플릿은 당신만의 블록체인을 구성하기 위해 사용할 수 있는 동작하는 런타임을 제공합니다. 노드 템플릿은 당신이 시작하게 하기 위해서 FRAME이라는 개발 프레임워크를 사용하여 구성된 런타임과 '팔레트'라고 불리는 몇 개의 모듈들을 제공합니다. 이 튜토리얼에서, 당신은 어덯게 노드 템플릿에 '닉스 팔레트'를 추가하는지 배울 것입니다. 당신의 런타임에 다른 FRAME 팔레트들을 추가할 때에도 비슷한 패턴을 사용할 수 있습니다. 그러나, 각 팔레트에 그것을 사용할 때 필요한 특정한 설정들을 해줘야 합니다. 이 튜토리얼은 어떻게 각 팔레트가 요구하는 설정들을 세팅하는지를 설명하지만 당신이 런타임에 추가하리고 결정한 각 팔레트들에 적용될 구체적인 설정을 설명하지는 않습니다.

시작하기 전에

시작하기 전에 우리의 목표를 그려보겠습니다:

  • 노드 템플릿에 닉스 팔레트 추가하기
  • 닉스 팔레트의 설정 특성 구현하기
  • 닉스 팔레트와 상호작용하기 위해 프론트엔드 템플릿 사용하기

학습 결과

  • 어떻게 노드와 런타임에 FRAME 팔레트를 통할하는지를 배운다.
  • 팔레트의 설정 특성을 커스터마이징하는 것에 익숙해진다.
  • crates.io에 커스텀 팔레트 배포하는 법을 배운다.

노드 템플릿에 닉스 팔레트 추가하기

닉스 팔레트는 블록체인 사용자들이 별명을 예약하고 그 별명을 자신이 컨트롤하는 계좌와 연결짓기 위해 돈을 내는 것을 허용해줍니다.
섭스트레이트 노드 템플릿에 닉스 팔레스틑 추가하려면:
1. 터미널을 열고 노드 템플릿의 루트 디렉토리로 갑니다.
2. runtime/Cargo.toml을 열고 텍스트 에디터에서 설정 파일을 엽니다.
3. 닉스 팔레트 크레이트를 불러와서 의존성 리스트에 추가함으로써 노드 템플릿 런타임에서 사용가능하게 합니다.
'''
pallet-nicks = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.18" }
'''

여기의 의존성 부분에서, default-features = false 부분은 런타임을 컴파일할 때 이 팔레트의 기능들이 기본적으로 사용되지 않는다는 것을 의미합니다. 대신에, 런타임을 위해 컴파일되는 기능들은 features 부분에 있는 네이티브 러스트 바이너리를 컴파일할 때 어떤 기능들을 포함시킬지에 따라 컨트롤됩니다.

섭스트레이트 런타임이 표준 라이브러리 함수 std와 네이티브 러스트 바이너리, 표준 라이브러리를 포함하지 않는 웹어셈블리 바이너리를 모두 컴파일하기 때문에, 컴파일되는 팔레트 기능들은 std가 있는 러스트 바이너리를 컴파일할지, 또는 std가 없는 웹어셈블리 바이너리를 컴파일할지에 의존합니다. std와 no_std 기능들을 컴파일하는 것에 대한 더 많은 정보는 Rust Embedded book을 보세요

나머지 부분들은 카고가 paritytech/substrate 저장소에서 올바른 버전의 섭스트레이트와 모든 다른 사용되는 크레이트들에서 가져온 닉스 팔레트를 사용해야 한다는 것을 의미힙니다.

Cargo.toml 파일을 편집하는 것에 대해서는 카고 참조 문서를 보세요
1. features 부분에 다음 코드를 추가해 닉스 팔레트 크레이트에 std 기능에 포함될 기능들의 리스트를 추가하세요.
만약 이 과정을 빠트렸다면, 네이티브 바이너리를 빌드할 때 다음과 비슷한 에러를 볼 것입니다.

  1. 다음 커맨드를 실행해 새 의존성을 올바르게 받아왔는지 확인하세요

닉스 팔레트에서 특성 설정 리뷰

모든 팔레트는 팔레트가 런타임에서 필요로 하는 인자들과 타입들을 설정하는 데 사용하는 Config라 불리는 러스트 특성을 가집니다.

만약 노트 템플릿 안의 런타임 주석을 리뷰해 본다면, 각 팔레트의 인자들을 정의하고 조율하기 위해 Config 설정 특성을 사용한 예시들을 볼 수 있을 것입니다.

팔레트에 추가되어야 하는데 대부분의 팔레트 특정 코드는 Config 특성을 사용해 구현되어있습니다. 닉스 템플릿을 구현하기 위해서 pallet_nicks::Config documentation 문서를 보거나 닉스 팔레트의 소스코드 안에 있는 특성의 정의를 보세요.

닉스 팔레스의 소스 코드에, Config 특성은 다음과 같은 타입들을 정의하고 있습니다

pub trait Config: frame_system::Config {
    /// The overarching event type.
    type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;

    /// The currency trait.
    type Currency: ReservableCurrency<Self::AccountId>;

    /// Reservation fee.
    #[pallet::constant]
    type ReservationFee: Get<BalanceOf<Self>>;

    /// What to do with slashed funds.
    type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;

    /// The origin which may forcibly set or remove a name. Root can always do this.
    type ForceOrigin: EnsureOrigin<Self::Origin>;

    /// The minimum length a name may be.
    #[pallet::constant]
    type MinLength: Get<u32>;

    /// The maximum length a name may be.
    #[pallet::constant]
    type MaxLength: Get<u32>;
}

잔고 팔레트 구현 리뷰

닉스 팔레트를 불로올 때 잔고 팔레트를 템플릿으로 사용했던 것처럼, 닉스 팔레트의 Config 인터페이스를 어덯게 구현하는지 보기 위한 예시로 잔고 팔레트를 사용할 수 있습니다.

  1. 텍스트 에디터에서 runtime/src/lib.rs파일을 여세요
  2. 잔고 팔레트가 있는 곳으로 가서 두 가지 부분으로 구현되어 있다는 것에 주목하세요:
  • parameter_types! : 상수 값들이 정의된 블록입니다.
parameter_types! {
    // The u128 constant value 500 is aliased to a type named ExistentialDeposit.
    pub const ExistentialDeposit: u128 = 500;
    // A heuristic that is used for weight estimation.
    pub const MaxLocks: u32 = 50;
}
  • impl : Config 인터페이스에 정의된 타입들과 값들이 설정되어 있는 곳입니다.
impl pallet_balances::Config for Runtime {
    // The previously defined parameter_type is used as a configuration parameter.
    type MaxLocks = MaxLocks;

    // The "Balance" that appears after the equal sign is an alias for the u128 type.
    type Balance = Balance;

    // The empty value, (), is used to specify a no-op callback function.
    type DustRemoval = ();

    // The previously defined parameter_type is used as a configuration parameter.
    type ExistentialDeposit = ExistentialDeposit;

    // The FRAME runtime system is used to track the accounts that hold balances.
    type AccountStore = System;

    // Weight information is supplied to the Balances pallet by the node template runtime.
    // type WeightInfo = (); // old way
    type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;

    // The ubiquitous event type.
    type Event = Event;
}

impl pallet_balances::Config 블록은 잔고 팔레트의 Config 특성에 의해 지정된 타입들과 인자들을 설정할 수 있게 해 줍니다. 예를 들어, 위의 impl 블록은 잔고 팔레트가 잔고를 추적할 때 u128 타입을 사용하도록 설정했습니다. 만약 저장소를 최적화하는 것이 중요한 체인을 개발한다면, 잔고 팔레트의 Config 특성에 있는 Balance 타입이 AtLeast32BitUnsigned 특성에 묶여 있기 때문에 최소한 32비트를 갖는 어떠한 부호 없는 정수 타입을 사용할 수 있을 것입니다.

닉스 팔레트의 Config 특성 구현하기

잔고 팔레트의 Config 특성이 어떻게 구현되어있는지 예시를 봤으니, 이제 닉스 팔레트의 Config 특성을 구현할 준비가 되었습니다.

런타임에서 닉스 팔레트를 구현하기 위해서는:
1. 텍스트 에디터로 runtime/src/lib.rs 파일을 여세요
2. 잔고 코드의 마지막 줄을 주석처리한 다음, 닉스 팔레트에 다음 코드를 추가하세요:

/// Add this code block to your template for Nicks:
parameter_types! {
    // Choose a fee that incentivizes desireable behavior.
    pub const NickReservationFee: u128 = 100;
    pub const MinNickLength: u32 = 8;
    // Maximum bounds on storage are important to secure your chain.
    pub const MaxNickLength: u32 = 32;
}

impl pallet_nicks::Config for Runtime {
    // The Balances pallet implements the ReservableCurrency trait.
    // `Balances` is defined in `construct_runtime!` macro. See below.
    // https://docs.substrate.io/rustdocs/latest/pallet_balances/index.html#implementations-2
    type Currency = Balances;

    // Use the NickReservationFee from the parameter_types block.
    type ReservationFee = NickReservationFee;

    // No action is taken when deposits are forfeited.
    type Slashed = ();

    // Configure the FRAME System Root origin as the Nick pallet admin.
    // https://docs.substrate.io/rustdocs/latest/frame_system/enum.RawOrigin.html#variant.Root
    type ForceOrigin = frame_system::EnsureRoot<AccountId>;

    // Use the MinNickLength from the parameter_types block.
    type MinLength = MinNickLength;

    // Use the MaxNickLength from the parameter_types block.
    type MaxLength = MaxNickLength;

    // The ubiquitous event type.
    type Event = Event;
}
  1. 닉스 팔레트가 노출하는 타입들을 식별하세요
    construct_runtime! macro 문서에서 전체 타입을 찾아볼 수 있습니다.

    닉스 팔레트는 다음과 같은 타입들을 사용합니다:

  • 팔레트 Storage: #[pallet::storage] 매크로를 사용합니다.
  • 팔레트 Events: #[pallet::events] 매크로를 사용합니다. 닉스 팔레트의 경우, Event 키워드는 T라는 타입에 따라 매개변수화되어 있습니다; 왜냐하면 닉스 팔레트에 정의된 이벤트들 중 최소한 하나는 Config 설정 특성에 지정된 타입에 의존하기 때문입니다.
  • 호출가능한 함수들: #[pallet::call] 매크로 안에 dispatchable function(앱의 현재 상태에 접근할 수 있는 함수)들이 있기 때문입니다.
  • #[pallet::pallet] 매크로에 있는 Pallet 타입
  1. 닉스를 construct_runtime! 매크로에 추가합니다.
    예시:

    construct_runtime!(
       pub enum Runtime where
           Block = Block,
           NodeBlock = opaque::Block,
           UncheckedExtrinsic = UncheckedExtrinsic
       {
           /* --snip-- */
           Balances: pallet_balances,
    
           /*** Add This Line ***/
           Nicks: pallet_nicks,
       }
    );
  2. 다음 커맨드로 새로운 의존성을 올바르게 받아왔는지 확인하세요:

    cargo check -p node-template-runtime

    에러가 없다면, 컴파일할 준비가 됐습니다.

  3. 다음 커맨드로 필리즈 모드로 노드를 컴파일하세요:

    cargo build --release 

    블록체인 노드 시작하고 닉스 팔레트 사용하기

    노드를 컴파일했다면, 닉스 팔레트에서 별명 기능을 추가한 노드를 시작하고 프론트엔드 템플릿을 사용해 상호작용할 준비가 됐습니다.

    Substrate 노드 시작하기

    로컬 Substarte 노드를 시작하기 위해서:

  4. 필요하다면 터미널 쉘 창을 여세요

  5. Substrate 노드 템플릿 디렉토리로 가세요

  6. 다음 커맨드로 개발 모드로 노드를 시작하세요:

    ./target/release/node-template --dev

    노드 템플릿의 커맨드라인 옵션은 어떻게 노드를 작동할 것인지를 지정합니다. 이 경우, --dev 옵션은 노드가 미리 정의된 development 체인 스펙에서 개발자 모드로 실행하는 것입니다. 기본 설정으로, 이 옵션은 또한 모든 활성화된 데이터- 키, 블록체인 데이터베이스, 네트워킹 정보-를 Contro-c를 눌러 노드를 중단시킬 때 삭제합니다. --dev 옵션을 사용하면 언제 노드를 중단하고 재시작하더라도 깨끗한 작업 상태가 보장됩니다.

  7. 터미널에 찍히는 출력을 보고 노드가 성공적으로 동작하는지 확인하세요.

콘솔 출력에서 finalized 뒤의 숫자가 증가하는 중이라면, 당신의 블록체인은 새 블록들을 생성하고 그들이 설명하는 상태에 대해서 합의하는 중인 것입니다.

  1. 계속해서 노드의 출력을 보여주도록 터미널을 열어두세요.

프론트엔드 템플릿 시작하기

이제 런타임에 새로운 팔레트를 추가했으니, 노드 템플릿과 상호작용하고 닉스 팔레트에 접근하기 위해 Substrate 프론트엔드 템플릿을 사용할 수 있습니다.

프론트엔드 템플릿을 사용하기 위해서:
1. 컴퓨터에서 새 터미널 쉘을 여세요
2. 새로운 터미널에서, 프론트엔드 템플릿을 설치한 디렉토리로 이동하세요.
3. 다음 커맨드를 실행하여 프론트엔드 템플릿의 웹서버를 시작하세요

yarn start
  1. 프론트엔드 템플릿을 보기 위해 브라우저에서 http://localhost:8000/에 접속하세요.

닉스 팔레트를 사용해 별명 설정하기

프론트엔드 템플릿을 시작하면, 방금 런타임에 추가한 닉스 팔레트와 상호작용할 수 있습니다.

계정에 별명을 설정하기 위해서:
1. Alice 계정이 현재 선택되었는지 확인하기 위해 계정 선택 리스트를 확인하세요.
2. Pallet Interactor 컴포넌트에서, Extrinsic이 선택되었는지 확인하세요.
3. 호출 가능한 팔레트들의 리스트에서 nicks를 선택하세요.
4. 닉스 팔레트에서 setName dispatchable을 호출할 함수로 선택하세요.
5. 최소별명길이(8글자)보다 길고 최대별명길이(32글자)보다 짧은 이름을 타이핑하세요.
6. 함수를 실행하기 위해 Signed를 클릭하세요.
7.호출 상태와 닉스 팔레트에 의해 실행된 이벤트들을 살펴보세요.

닉스 팔레트를 사용해 계정 정보 요청하기

다음으로, 닉스 팔레트의 런타임 저장소에서 Alice의 별명을 읽기 위해 요청 기능을 사용할 수 있습니다.

Alice에 저장된 정보를 받기 위해서:
1. Pallet Interactor 컴포넌트에서 Query를 선택하세요.
2. 요청가능한 팔레스 리스트에서 nicks를 선택하세요.
3. nameOf를 선택하세요.
4. AccountId에 Alice의 계정 주소를 복사해서 붙여넣고, Query를 클릭하세요.

리턴 타입은 두 개의 값을 갖는 튜플입니다:

  • Alice 계정의 별명을 16진수로 인코딩한 값
  • 별명을 보호하기 위해 Alice의 계정에 예약된 양(?)

만약 닉스 팔레트에 Bob 계정의 nameOf를 요청했다면, None이 리턴된 것을 볼 수 있을텐데, 왜냐하면 Bob은 setName dispatchable을 호출하지 않고 별명을 저장하기 위해 돈을 넣지 않았기 때문입니다.

더 심화된 주제 알아보기

이 튜토리얼은 killName dispatchable 함수를 실행시키고 Bob의 계정 id를 함수의 인자로 사용하기 위해서 Signed 버튼을 사용했습니다. killName함수는 이전 파트의 닉스 팔레트의 Config 인터페이스에 설정된 ForceOrigin에 의해 호출되어야만 합니다. 우리는 이것을 FRAME 시스템의 Root origin으로 설정했습니다. Alice에게 origin에 대한 접근 권한을 주기 위해 Sudo pallet를 설정하는 데 노드 템플릿의 chain specification 파일이 사용됩니다.

프론트엔드 템플릿은 Root origin으로부터 함수를 호출하기 위해 Sudo 팔레트를 사용하는 것을 쉽게 해줍니다- 그냥 SUDO 버튼을 사용합니다. 우리가 방금 SUDO 버튼과 반대되게 Signed버튼을 사용했기 때문에 Signed origin에 의해 실행된 함수는 Root origin과 반대로 Alice의 계정과 관련되어 있습니다.

비록 함수 호출이 성공적으로 처리되었더라도, BadOrigin 에러가 일어난 것을 Events 패널에서 볼 수 있습니다. 이것은 앨리스의 계좌에 여전히 처리에 대한 수수료가 부과되어 있지만 닉스 팔레트는 중요한 "선검증 후작성" 패턴을 따르기 때문에 상태 변화가 없었기 때문입니다. 이제 같은 인자로 같은 호출을 처리하기 위해 SUDO 버튼을 사용해보겠습니다.

수도 팔레트는 네트워크 참여자들에게 루트 오리진이 호출을 처리했다고 알리기 위해 수디드 이벤트를 발생시키지만, 내부 처리가 디스패치 에러(수도 팔레트의 수도 함수는 외부 처리임)로 실패한 것을 알게 될 겁니다. 특히, 이것은 디스패치에러:모듈의 변이 인스턴스입니다. 인덱스 숫자는 그 에러가 발생간 팔레트와 연결되어 있습니다;constant_runtime!매크로 안에서 팔레스틔 인덱스(위치)에 대응합니다. 에러 숫자는 팔레트의 Error enum관련 변이의 인덱스에 대응합니다. 팔레트 에러를 찾기 위해 이 숫자들을 사용하는 경우, 첫 번째 인덱스는 0이라는 것을 기억하세요. 위의 스크린샷에서, 10번째 팔레트는 9번 인덱스이고 에러는 2번 인덱스입니다. 여러분의 construct_runtime!매크로의 닉스 팔레트의 위치에 따라, 다른 인덱스 숫자를 볼수도 있습니다. 인덱스 값에 관계없이, 에러 인덱스 값은 2여야 하는데, 이것은 닉스 팔레트의 에러ㄷ enum인 Unnamed 변이에 대응됩니다. 밥이 아직 별명을 예약하지 않았기 때문에 그것 놀랍지 않은 일이고, 그래서 초기화될 수 없습니다!

앨리스가 killName 처리가능을 실행하고 별명이 있는 자기 자신을 포함한 어떠한 계좌와 관련된 별명을 강제로 초기화하기 위해 수도 버튼을 사용할 수 있다는 것을 확인해야 합니다. 여기 시도해보고 싶을지도 모르는 몇몇 다른 것들이 있습니다:

  • 닉스 팔레트의 컨피그 설정 특성에 명시한 최소별명길이보다 짧거나 최대별명길이보다 긴 별명을 추가해 보세요
  • 밥의 별명을 추가하고 앨리스 계정을 사용해서 수도 버튼으로 밥의 별명을 지워보세요. 밥의 계정으로 돌아와서 clearName 함수를 실행해보세요.

다른 FRAME 팔레트 추가하기

이 튜토리얼은 예시로 닉스 팔레트를 사용해 런타임에 팔레트를 추가하는 방법을 설명했습니다. 그러나, 각 팔레트가 조금씩 다르다는 것을 알아야 합니다. 만약 특정한 팔레트를 어떻게 추가하는지 확신하지 못한다면, 찾아볼 최고의 장소는 메인 Substrate repository입니다. 튜토리얼에 사용된 노드 템플릿과는 다르게, 메인 섭스트레이트 저장소의 런타임은 코어 FRAME 팔라트들의 라이브러리에서 사용가능한 대부분의 팔레트들을 포함하고 있습니다.

메인 섭스트레이트 노드 런타임의 Cargo.toml파일에 따라 다른 팔레트 의존성들을 어떻게 불러오는지 예시를 참조하세요. 각 팔레트를 포함한 런타임을 어떻게 설정하는지 예시를 보기 위해서 메인 섭스트레이트 노드 런타임의 lib.rs 파일을 참조하세요. 일반적으로, 런타임에 팔레트를 추가하는 시작점으로 메인 섭스트레이느 노드 런타임으로부터 코드를 복사할 수 있습니다.

나만의 팔레트 배포하기

이제 닉스 팔레트를 성공적으로 임포트했어야 합니다. 앞으로, 당신의 앱-한정 로직을 실행하기 위해 당신만의 팔레트를 작성할 겁니다. 그런 경우에, 팔레트들을 다른 사람들과 공유하고 싶을 수도 있습니다.

이 부분에서는, 어떻게 나만의 팔레트를 오픈 소스 사용을 위해 배포하는지 다루겠습니다.

1. Github에 배포하기

나만의 팔레트를 깃허브에 배포하기 위해서, 깃허브 레포지토리를 만들고 거기에 팔레트 코드를 푸시해야 합니다.

일단 배포하면, 다른 개발자들이 다음의 스니펫으로 그들의 Cargo.toml 파일에 당신의 팔레트를 참조할 수 있습니다.

your-pallet-name = { default_features = false, git = "https://github.com/your-username/your-pallet", version = "1.0.0" }

# You may choose to refer to a specific commit, tag, or branch instead of (or in addition to, over-specifying) a version
# rev = "<git-commit>""
# tag = "<some tag>"
# branch = "<some branch>"

2. crates.io에 배포하기

crates.io는 어떤 러스트 모듈이라도 허락없이 배포할 수 있도록 해줍니다. 크레이츠에 배포하기 문서를 따라 절차를 배울 수 있습니다.

일단 배포하면, 다른 개발자들은 다음의 스니펫으로 당신의 팔레트를 참조할 수 있습니다.

[dependencies]
your-pallet-name = { default_features = false, version = "some-compatible-version"}

위에서 어떤 타겟을 설정하지 않았으므로, 디폴트로 크레이츠 레포지토리 안에 있는 패키지를 참조할 것입니다.

profile
풀스택 웹개발자👩‍💻✨️

0개의 댓글