Substrateでファイルの存在証明をする

#概要
Substrateでファイルの存在証明および改竄されていないかの確認ができるものを作ります。
NEMのアポスティーユのようなものです。
アポスティーユの詳細は[こちら](https://qiita.com/44uk_i3/items/82a5446e48aea23e054b)

#Substrateとは
ブロックチェーンのフレームワークです。詳しくは以下を参照してください。
[What is Substrate | Parity Technologies |](https://medium.com/paritytech/what-is-substrate-29af4231d7e0)

#セットアップ
実行環境は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>```はバイト列です。

#runtimeをアップデートする

- ```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
```

こんな感じでブロック生成が始まります。

<img width="560" alt="スクリーンショット 2019-05-11 18.16.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/511d7c0a-2e69-64e1-e444-9d9ea5ca5cab.png">


#PolkadotJS-UIで挙動を確認する

[PolkadotJS-UI](https://substrate-ui.parity.io/)を開きます。

では```Setting```のremote nodeを```Local Node (127.0.0.1:9944)```にしてSave&reloadします。

<img width="1437" alt="スクリーンショット 2019-05-11 17.08.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/9f66d19b-c0fc-a7b4-ad1d-09c1c0252adb.png">

次に```Setting```の```Developer```セクションでページが正しくデコードするために構造体を設定します。

<img width="1409" alt="スクリーンショット 2019-05-11 19.41.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/b2b4229f-7d24-9b28-044c-536369183897.png">

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


次に```Extrinsics```に移動して関数を実行します。

<img width="1440" alt="スクリーンショット 2019-05-11 18.32.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/6c563b90-62ab-f5e6-47c6-35b7fc57f7cc.png">

Aliceがトークンを持っているはずなのでAliceで実行します。
hash: Bytesの横のドキュメントマークをクリックしてお好きなファイルを選択してください。
そしてSign&Submitします。

<img width="1437" alt="スクリーンショット 2019-05-11 18.37.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/267185dc-700f-463e-05d4-3581196837b9.png">

次に```Chain State```に移動して```receitStorage/receipt(Bytes):Receipt```を選択します。
そして、先ほど選んだファイルを再び選んで+マークをクリックします。

<img width="1439" alt="スクリーンショット 2019-05-11 19.40.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/15da3a3b-9225-1b16-a64f-3858ec1b46c9.png">

すると登録した情報が表示されます。
この時登録の時に選んだファイルとは違うファイルを選択した場合、またはファイルの内容が変更されていた場合はこのように返ってきます。

<img width="1405" alt="スクリーンショット 2019-05-11 19.47.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/3e192ebf-18a7-d9a8-bfc3-33a2faf65d83.png">

#最後に
Substrateはバージョンの変更が多いので上のコードが動かないことがあるのでご注意ください。