[Polkadot]Substrate 을 이용하여 Parachain 만들기 튜토리얼 - 3

지난 시간에 이어서 계속 합니다.
번역해가면서, rust 언어에 대해서 알아보면서 하려니 진도가 잘 안나가네요 ㅠㅠ


5. Build New Pallet
  • Frame pallet은 6개의 섹션으로 나눌 수 있습니다.
// 1. Imports
use frame_support::{decl_module, decl_storage, decl_event, decl_error, dispatch};
use frame_system::ensure_signed;

// 2. Configuration
pub trait Trait: frame_system::Trait { /* --snip-- */ }

// 3. Storage
decl_storage! { /* --snip-- */ }

// 4. Events
decl_event! { /* --snip-- */ }

// 5. Errors
decl_error! { /* --snip-- */ }

// 6. Callable Functions
decl_module! { /* --snip-- */ }
// lib.rs 파일 상단에 해당 부분은 지우고 아래 내용을 붙여 넣는다.
#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::{
    decl_module, decl_storage, decl_event, decl_error, ensure, StorageMap
};
use frame_system::ensure_signed;
use sp_std::vec::Vec;
/// Cargo.toml 파일의 dependency 아래 쪽에 아래 내용을 붙여넣는다.
[dependencies.sp-std]
git = 'https://github.com/paritytech/substrate.git'
default-features = false
tag = 'v2.0.0-rc6'
version = '2.0.0-rc6'

/// feature 쪽에 붙여넣은 부분을 추가한다.
[features]
default = ['std']
std = [
    'codec/std',
    'frame-support/std',
    'frame-system/std',
    'sp-std/std',          <-- This line is new
]
5. Trait / Configuration
  • 모든 Pallet는 "Trait"라고 불려지는 컴포너트를 가지고 있고, configuration에 사용됩니다.
  • "Trait"는 rust에서 사용되는 명령어인데, 일반적인 프로그램에서 interface와 유사하다고 생각하면 됩니다.
  • 지금은 Pallet에 대해 구성 할 것은 일부 이벤트를 내보내는 것입니다.
/// Configuration
/// Configure the pallet by specifying the parameters and types on which it depends.
pub trait Trait: frame_system::Trait {
    /// Because this pallet emits events, it depends on the runtime's definition of an event.
    type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
}
6. Events
  • 소스에 이벤트를 추가해 봅니다.
// Pallets use events to inform users when important changes are made.
// Event documentation should end with an array that provides descriptive names for parameters.
// https://substrate.dev/docs/en/knowledgebase/runtime/events
decl_event! {
    pub enum Event<T> where AccountId = <T as frame_system::Trait>::AccountId {
        /// Event emitted when a proof has been claimed. [who, claim]
        ClaimCreated(AccountId, Vec<u8>),
        /// Event emitted when a claim is revoked by the owner. [who, claim]
        ClaimRevoked(AccountId, Vec<u8>),
    }
}
  • Pallet는 2가지 환경에서 이벤트가 발생됩니다. 새로운 proof가 블록체인에 추가 되었을 때와 삭제 되었을 때 입니다.
  • 이벤트에는 추가 Parameter을 받을 수 있고, 이벤트에는 Array 형태의 주석으로 이벤트 Parameter을 설명하는 것이 관례입니다.
7. Errors
  • 에러에 대한 인터페이스 정의도 필요합니다. 이는 호출했을 때 에러가 있는 경우 발생됩니다.
// Errors inform users that something went wrong.
decl_error! {
    pub enum Error for Module<T: Trait> {
        /// The proof has already been claimed.
        ProofAlreadyClaimed,
        /// The proof does not exist, so it cannot be revoked.
        NoSuchProof,
        /// The proof is claimed by another account, so caller can't revoke it.
        NotProofOwner,
    }
}
8. Store
  • 새로운 정보를 블록체인에 추가하려면, Pallet의 Storage에 그 정보를 저장을 할 수 있습니다.
  • 값을 저장하기 위해 블럭정보와 파일 고유정보로 hash 형태로 만들어 냅니다.
// The pallet's runtime storage items.
// https://substrate.dev/docs/en/knowledgebase/runtime/storage
decl_storage! {
    trait Store for Module<T: Trait> as TemplateModule {
        /// The storage item for our proofs.
        /// It maps a proof to the user who made the claim and when they made it.
        Proofs: map hasher(blake2_128_concat) Vec<u8> => (T::AccountId, T::BlockNumber);
    }
}
9. 호출 할 함수 정의
  • 위에서 말한 것과 같이 2가지 함수를 정의 합니다.
  • create_claim, revoke_claim
  • 아래 추가된 함수에는 리턴 타입을 명시하지 않았습니다.
  • 이 때 두 함수는 모두 DispatchResults를 반환합니다.
  • 이 반환 유형은 decl_module에 의해 사용자를 대신하여 추가됩니다.
// Dispatchable functions allows users to interact with the pallet and invoke state changes.
// These functions materialize as "extrinsics", which are often compared to transactions.
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        // Errors must be initialized if they are used by the pallet.
        type Error = Error<T>;

        // Events must be initialized if they are used by the pallet.
        fn deposit_event() = default;

        /// Allow a user to claim ownership of an unclaimed proof.
        #[weight = 10_000]
        fn create_claim(origin, proof: Vec<u8>) {
            // Check that the extrinsic was signed and get the signer.
            // This function will return an error if the extrinsic is not signed.
            // https://substrate.dev/docs/en/knowledgebase/runtime/origin
            let sender = ensure_signed(origin)?;

            // Verify that the specified proof has not already been claimed.
            ensure!(!Proofs::<T>::contains_key(&proof), Error::<T>::ProofAlreadyClaimed);

            // Get the block number from the FRAME System module.
            let current_block = <frame_system::Module<T>>::block_number();

            // Store the proof with the sender and block number.
            Proofs::<T>::insert(&proof, (&sender, current_block));

            // Emit an event that the claim was created.
            Self::deposit_event(RawEvent::ClaimCreated(sender, proof));
        }

        /// Allow the owner to revoke their claim.
        #[weight = 10_000]
        fn revoke_claim(origin, proof: Vec<u8>) {
            // Check that the extrinsic was signed and get the signer.
            // This function will return an error if the extrinsic is not signed.
            // https://substrate.dev/docs/en/knowledgebase/runtime/origin
            let sender = ensure_signed(origin)?;

            // Verify that the specified proof has been claimed.
            ensure!(Proofs::<T>::contains_key(&proof), Error::<T>::NoSuchProof);

            // Get owner of the claim.
            let (owner, _) = Proofs::<T>::get(&proof);

            // Verify that sender of the current call is the claim owner.
            ensure!(sender == owner, Error::<T>::NotProofOwner);

            // Remove claim from storage.
            Proofs::<T>::remove(&proof);

            // Emit an event that the claim was erased.
            Self::deposit_event(RawEvent::ClaimRevoked(sender, proof));
        }
    }
}

위와 같이 Substrate는 간단히 모듈들을 넣고, 정의된 부분에 세부 코드를 넣는 정도만으로 블록체인을 구성할 수 있게 되어 있습니다. 다음 시간에는 본인만의 Pallet를 만드는 작업을 해볼 예정입니다.


생소한 프로그래밍 언어인 rust와 substrate로 작업을 하려니 꽤나 막히는 부분이 많았네요. ㅠㅠ 영어 번역도 힘들었고 말입니다. ㅠㅠ 부정확한 내용도 있을 수 있으니 참고바라며... 일단 Polkadot의 Substrate Framework가 편리한 도구들을 많이 제공하고, 기능에 맞게 쉽게 갈아 끼울 수 있도록 구성 해놓았다는 사실은 잘알게 되었네요.

얼마나 많은 Pallet들이 제공되고 쉽게 사용할 수 있을 지 조금 더 살펴봐야겠습니다. 개개인이 새로 만들어서 배포할 수도 있을 것 같고 말입니다.

Sort:  

[US$140.00](▼54%)샤오미 드리미 V10 무선 청소기 / 유럽버전! / 6개월무료A/S / 무료배송/

WWW.QOO10.COM

@happyberrysboy transfered 23 KRWP to @krwp.burn. voting percent : 87.69%, voting power : 82.19%, steem power : 1897409.02, STU KRW : 1200.
@happyberrysboy staking status : 7300 KRWP
@happyberrysboy limit for KRWP voting service : 21.9 KRWP (rate : 0.003)
What you sent : 23 KRWP
Refund balance : 1.1 KRWP [46448894 - 52423804b44d06d1d9a62697a357a408f33a2916]

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.033
BTC 61821.21
ETH 3068.39
USDT 1.00
SBD 3.84