Substrate에서 파일의 존재 증명

개요



Substrate에서 파일의 존재 증명 및 개조되지 않았는지 확인할 수 있는 것을 만듭니다.
NEM의 아포스티유와 같습니다.
아포스티유에 대한 자세한 내용은 여기

Substrate란?



블록체인 프레임워크입니다. 자세한 내용은 아래를 참조하십시오.
What is Substrate | Parity Technologies |

설정



실행 환경은 mac입니다.
먼저 npm과 node가 설치되어 있어야 합니다.
다음 명령으로 Substrate가 실행할 수 있는 환경을 만듭니다.
Rust 등이 설치됩니다.
$ curl https://getsubstrate.io -sSf | bash

커피를 마시면서 기다립니다.

완료되면 Substrate 노드 템플릿을 만듭니다.
$ substrate-node-new receiptchain junki
$ cd receiptchain

receiptchain은 프로젝트 이름이고 junki는 자신의 이름을 넣을 수 있습니다.
다시 커피를 마시자.

파일 편집



runtime/src 이하에 receiptchain.rs를 작성합니다.
receiptchain.rs를 다음과 같이 편집합니다.

receiptchain.rs
use support::{decl_storage, decl_module, StorageValue, StorageMap, dispatch::Result, ensure, decl_event};
use system::ensure_signed;
use parity_codec::{Encode, Decode};
use rstd::vec::Vec;

const BYTEARRAY_LIMIT: usize = 3000000;

#[derive(Encode, Decode, Default, Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Receipt<AccountId, Moment> {
    id: u64,
    owner: AccountId,
    timestamp: Moment
}

pub trait Trait: timestamp::Trait + balances::Trait {
    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}

decl_event!(
    pub enum Event<T> where
        <T as system::Trait>::AccountId,
        <T as timestamp::Trait>::Moment,
    {
        ReceiptCreated(AccountId, Moment),
    }
);

decl_storage! {
    trait Store for Module<T: Trait> as ReceiptStorage {
        Receipts get(receipt): map Vec<u8> => Receipt<T::AccountId, T::Moment>;
        Nonce: u64;
    }
}

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin  {
        fn deposit_event<T>() = default;

        fn create_receipt(origin, hash: Vec<u8>) -> Result {
            ensure!(hash.len() <= BYTEARRAY_LIMIT, "Bytearray is too large");

            let sender = ensure_signed(origin)?;
            let nonce = <Nonce<T>>::get();
            ensure!(!<Receipts<T>>::exists(&hash), "This receipt has already been registered");

            let time = <timestamp::Module<T>>::now();

            let new_receipt = Receipt {
                id: nonce,
                owner: sender.clone(),
                timestamp: time.clone()
            };

            <Receipts<T>>::insert(hash, new_receipt);

            <Nonce<T>>::mutate(|n| *n += 1);
            Self::deposit_event(RawEvent::ReceiptCreated(sender, time));

            Ok(())
        }
    }
}


Substrate는 String를 지원하지 않습니다.
체인에 데이터를 얹을 때는 바이트열로 해 둡시다.
덧붙여서 여기서 사용하고 있는 형태 Vec<u8> 는 바이트열입니다.

런타임 업데이트


  • mod receiptchain; 넣기

  • lib.rs
    ...
    pub type Hash = primitives::H256;
    
    /// Index of a block number in the chain.
    pub type BlockNumber = u64;
    
    /// Index of an account's extrinsic in the chain.
    pub type Nonce = u64;
    
    mod receiptchain;
    ...
    
  • impl receiptchain::Trait for Runtime { type Event = Event; } 넣기

  • lib.rs
    ...
    impl sudo::Trait for Runtime {
        /// The uniquitous event type.
        type Event = Event;
        type Proposal = Call;
    }
    
    impl receiptchain::Trait for Runtime {
        type Event = Event;
    }
    ...
    
  • construct_runtime! 안에 module을 선언한다.

  • lib.rs
    construct_runtime!(
        pub enum Runtime with Log(InternalLog: DigestItem<Hash, AuthorityId, AuthoritySignature>) where
            Block = Block,
            NodeBlock = opaque::Block,
            UncheckedExtrinsic = UncheckedExtrinsic
        {
            System: system::{default, Log(ChangesTrieRoot)},
            Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent},
            Consensus: consensus::{Module, Call, Storage, Config<T>, Log(AuthoritiesChange), Inherent},
            Aura: aura::{Module},
            Indices: indices,
            Balances: balances,
            Sudo: sudo,
    
            Receiptchain: receiptchain::{Module, Call, Storage, Event<T>},
        }
    );
    
    
    

    움직이다


    $ ./scripts/build.sh        //build wasm
    $ cargo build --release       //build binary
    $ ./target/release/receiptchain --dev       //start node
    

    체인의 모든 데이터를 삭제하고 블록 생성을 시작하려면 다음 명령을 실행합니다.
    ./target/release/receiptchain purge-chain --dev
    

    이런 식으로 블록 생성이 시작됩니다.



    PolkadotJS-UI로 동작 확인



    PolkadotJS-UI 를 엽니다.
    Setting 의 remote node 를 Local Node (127.0.0.1:9944) 로 하여 Save&reload 합니다.



    그런 다음 SettingDeveloper 섹션에서 페이지가 올바르게 디코딩되도록 구조체를 설정합니다.


    {
      "Receipt": {
        "id": "u64",
        "owner": "H256",
        "timestamp": "u64"
      }
    }
    

    그런 다음 Extrinsics 로 이동하여 함수를 실행합니다.



    Alice가 토큰을 가지고 있어야하므로 Alice에서 실행합니다.
    hash: Bytes 옆의 문서 표시를 클릭하고 원하는 파일을 선택합니다.
    그리고 Sign&Submit합니다.



    그런 다음 Chain State로 이동하여 receitStorage/receipt(Bytes):Receipt를 선택합니다.
    그리고 방금 선택한 파일을 다시 선택하고 + 마크를 클릭합니다.



    그러면 등록한 정보가 표시됩니다.
    이때 등록시에 선택한 파일과는 다른 파일을 선택했을 경우, 또는 파일의 내용이 변경되어 있던 경우는 이렇게 되돌아옵니다.



    마지막으로



    Substrate는 버전의 변경이 많기 때문에 위의 코드가 움직이지 않는 경우가 있으므로 주의해 주십시오.

    좋은 웹페이지 즐겨찾기