[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들이 제공되고 쉽게 사용할 수 있을 지 조금 더 살펴봐야겠습니다. 개개인이 새로 만들어서 배포할 수도 있을 것 같고 말입니다.
[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]