Open7

ink!に入門する

hhattohhatto

事前準備

$ brew install binaryen
$ cargo install cargo-contract --vers ^0.16 --force --locked
hhattohhatto

コントラクト用のプロジェクトを新規作成する

$ cargo contract new flipper
$ cd flipper

で、ビルド

$ cargo +nightly test
$ cargo +nightly contract build
   :

Original wasm size: 43.0K, Optimized: 19.2K

The contract was built in DEBUG mode.

Your contract artifacts are ready. You can find them in:
/path/to/flipper/target/ink

  - flipper.contract (code + metadata)
  - flipper.wasm (the contract's code)
  - metadata.json (the contract's metadata)

target/ink の下に関連ファイルが生成される、と。

$ tree -L 2 target
target
├── CACHEDIR.TAG
├── debug
│   ├── build
│   ├── deps
│   ├── examples
│   └── incremental
├── ink
│   ├── CACHEDIR.TAG
│   ├── flipper.contract
│   ├── flipper.wasm
│   ├── metadata.json
│   ├── release
│   └── wasm32-unknown-unknown
└── release
    ├── build
    ├── deps
    ├── examples
    ├── incremental
    ├── libflipper.d
    └── libflipper.dylib

13 directories, 7 files
hhattohhatto

Substrateノード起動

$ substrate-contracts-node --dev --tmp
2021-12-25 17:13:21 Running in --dev mode, RPC CORS has been disabled.
2021-12-25 17:13:21 Substrate Contracts Node
2021-12-25 17:13:21 ✌️  version 0.1.0-7d81166-aarch64-macos
2021-12-25 17:13:21 ❤️  by Parity Technologies <admin@parity.io>, 2021-2021
2021-12-25 17:13:21 📋 Chain specification: Development
2021-12-25 17:13:21 🏷 Node name: freezing-pot-1451
2021-12-25 17:13:21 👤 Role: AUTHORITY
2021-12-25 17:13:21 💾 Database: RocksDb at /var/folders/b_/lxz21x891450bdx5s921z9_40000gn/T/substrateRcFhg8/chains/dev/db/full
2021-12-25 17:13:21 ⛓  Native runtime: substrate-contracts-node-100 (substrate-contracts-node-1.tx1.au1)
2021-12-25 17:13:21 🔨 Initializing Genesis block/state (state: 0x0f3a…bf76, header-hash: 0xcdbe…ebc3)
2021-12-25 17:13:21 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2021-12-25 17:13:22 ⏱  Loaded block-time = 6s from block 0xcdbe4e854bd2a3f2b41c7d23ae5024f9e1bf0f1223a99a710c8aebb41cb1ebc3
2021-12-25 17:13:22 🏷 Local node identity is: 12D3KooWJrTxtnkMwuj9spd4daF916eAvPd1FdVduUgqtBusFZFd
2021-12-25 17:13:22 📦 Highest known block at #0
2021-12-25 17:13:22 〽️ Prometheus exporter started at 127.0.0.1:9615
2021-12-25 17:13:22 Listening for new connections on 127.0.0.1:9944.
2021-12-25 17:13:23 Accepted a new tcp connection from 127.0.0.1:61035.
    :
hhattohhatto

コントラクトをデプロイするためにWeb UIにアクセスする

https://paritytech.github.io/canvas-ui

選択ノードをLocal Nodeにする。

そしてビルドしたコントラクト target/ink/flipper.contract をアップロードして登録する。

hhattohhatto

このコントラクトは値をfalse/trueどちらかをストアするだけみたい。
コントラクト実行して、false/trueを切り替える。

実行した時はこんな感じになる。

hhattohhatto

storageの値をインクリメントするコントラクト作ってみる

$ cargo contract new incrementer
$ cd incrementer
$ cargo +nightly test
$ cargo +nightly contract build

コントラクトはテンプレートでflipperが実装されてるので、以下のような変更を入れる。

--- ../flipper/lib.rs	2021-12-25 16:46:36.000000000 +0900
+++ lib.rs	2021-12-25 17:34:17.000000000 +0900
@@ -3,25 +3,24 @@
 use ink_lang as ink;
 
 #[ink::contract]
-mod flipper {
+mod incrementer {
 
     /// Defines the storage of your contract.
     /// Add new fields to the below struct in order
     /// to add new static storage fields to your contract.
     #[ink(storage)]
-    pub struct Flipper {
-        /// Stores a single `bool` value on the storage.
-        value: bool,
+    pub struct Incrementer {
+        my_number: u32,
     }
 
-    impl Flipper {
+    impl Incrementer {
         /// Constructor that initializes the `bool` value to the given `init_value`.
         #[ink(constructor)]
-        pub fn new(init_value: bool) -> Self {
-            Self { value: init_value }
+        pub fn new(init_value: u32) -> Self {
+            Self { my_number: init_value }
         }
 
-        /// Constructor that initializes the `bool` value to `false`.
+        /// Constructor that initializes the `u32` value to `0`.
         ///
         /// Constructors can delegate to other constructors.
         #[ink(constructor)]
@@ -33,14 +32,14 @@
         /// This one flips the value of the stored `bool` from `true`
         /// to `false` and vice versa.
         #[ink(message)]
-        pub fn flip(&mut self) {
-            self.value = !self.value;
+        pub fn increment(&mut self) {
+            self.my_number += 1;
         }
 
         /// Simply returns the current value of our `bool`.
         #[ink(message)]
-        pub fn get(&self) -> bool {
-            self.value
+        pub fn get(&self) -> u32 {
+            self.my_number
         }
     }
 
@@ -58,17 +57,19 @@
         /// We test if the default constructor does its job.
         #[ink::test]
         fn default_works() {
-            let flipper = Flipper::default();
-            assert_eq!(flipper.get(), false);
+            let incrementer = Incrementer::default();
+            assert_eq!(incrementer.get(), 0);
         }
 
         /// We test a simple use case of our contract.
         #[ink::test]
         fn it_works() {
-            let mut flipper = Flipper::new(false);
-            assert_eq!(flipper.get(), false);
-            flipper.flip();
-            assert_eq!(flipper.get(), true);
+            let mut incrementer = Incrementer::new(0);
+            assert_eq!(incrementer.get(), 0);
+            incrementer.increment();
+            assert_eq!(incrementer.get(), 1);
+            incrementer.increment();
+            assert_eq!(incrementer.get(), 2);
         }
     }
 }

テストで確認

$ cargo +nightly test
    Finished test [unoptimized + debuginfo] target(s) in 0.06s
     Running unittests (target/debug/deps/incrementer-d60c12a0e8f0b2ec)

running 2 tests
test incrementer::tests::default_works ... ok
test incrementer::tests::it_works ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
hhattohhatto

コントラクをビルドし直して、コントラクト(target/ink/incrementer.contract)登録して動き見てみる。

$ cargo +nightly contract build

うまく動いてそう。

Rustでコントラクト実装できるのいいですね。