Waves - スマートコントラクトの書き方まとめ

内容が古い可能性があります。
参考にする場合は、公式サイト、ドキュメントも合わせて確認してください。
このブログでの最新内容は、ページ末尾の「Waves」タグから辿ってください。

WavesPlatformのTestnetにて無事(?)スマートコントラクトが有効になったので、できることの確認をしていこうと思う。

の二つから大体のことは分かるので、触ってみて気づいた点(あくまでも私の主観)などを補足する方向で。

SmartAccountやSmartAccountの作り方は前回確認済みなので、そちらを参照のこと。(リンク)

スマートコントラクトの流れ

基本的には以下な感じ

  1. 必要なデータを集め
  2. いくつかの条件判定を行い
  3. 成否を判断する

スマートコントラクト最後の行の結果がtrueならコントラクト成功、falseなら失敗になる

使えるもの

  • スマートコントラクト内で定義したデータ
    • 文字列 (例: “wavesplatform”)
    • 整数 (たぶん 64bit)
    • ブール値 (true or false)
    • バイトデータ (例: base58’12345’)
  • DataTransactionで設定したデータ(いわゆるオラクル)
  • あらかじめ用意されているデータおよび関数

用意されているデータについて

ブロックチェーンのつぎのデータにアクセスできる。

  • height
    ブロック長
  • tx
    このスマコンで判定するトランザクション

tx から tx.xxx の形でトランザクションの各データにアクセスできる。
以下がその一覧

  • type
  • id
  • fee
  • feeAssetId
  • timestamp
  • amount
  • bodyBytes
  • senderPk
  • aliasText
  • assetName
  • assetDescription
  • attachment
  • decimals
  • chainId
  • version
  • reissuable
  • proof0
  • proof1
  • proof2
  • proof3
  • proof4
  • proof5
  • proof6
  • proof7
  • transferAssetId
  • assetId
  • recipient
  • minSponsoredAssetFee

普段トランザクションを発行する際のパラメータ名と同じため、役割は分かると思う。
スマコン的に大事そうなのを挙げると

  • type
    トランザクションの種別を示す。例えばTransferTransactionのみ判定したい場合など、この値を用いる。
    txの各データはトランザクションによっては存在しないものがあり、
    存在しないデータにアクセスしようとすると問答無用でスマコンがfalseで終了するのでtype判定は結構大事

  • id
    トランザクション識別子。IDEの例にこれを使ったコントラクトがある。
    トランザクションを一意に特定しスマコンを適用したい場合に使う。

  • timestamp
    トランザクション発行時間。いわゆるタイムロック(指定日時以降にならないとトランザクション発行できない)用途に使える。

  • bodyBytes
    トランザクションバイナリデータ。要は署名対象のデータ。 マルチシグとかはこいつに対する署名を検証する

  • proof0〜7
    従来署名だったもの。スマコン適用にあたり拡張された。
    通常proof0には送信者による署名データが入っているが、別に署名である必要はない。
    マルチシグでは複数の署名がそれぞれ格納されるし、ハッシュ値などを格納することでアトミックスワップができるようになる

用意されている関数について

次の関数が使えるみたい

  • getLong(address, key), getBoolean(address, key), getByteArray(address, key)
    それぞれDataTransactionで設定されたデータを取得する。
    値は存在しない可能性があるので、関数戻り値(取得した値)はisDefinedで判定し、使用前にextractすること
    addressにはaddressFromxxx関数で取得したものを指定する。
    keyにはDataTransactionで設定したキー文字列を指定する。

  • addressFromPublicKey(publickey), addressFromString(address), addressFromRecipient(tx.recipient)
    それぞれpublickeyのバイトデータ、文字列(“3P”で始まるいつものアレ)、tx.recipientからアドレスを取得する。
    tx.recipientだけ特別扱いな理由は不明。

  • getTransactionById(id), transactionHeightById(id)
    それぞれ指定のidを持つトランザクションおよび、そのトランザクションが取り込まれたブロック長を得る。トランザクションは存在しない可能性があるので、isDefinedとextractが必要

  • accountBalance(address??), accountAssetBalance(address??, assetid)
    それぞれ指定のアドレス所有のWAVESおよびトークン量を得る。と思われる。 現状なぜかtx.recipientだけでしか使えない。

  • keccak256(bytes), blake2b256(bytes), sha256(bytes)
    それぞれ該当アルゴリズムのハッシュ関数

  • sigVerify(message, sig, pub)
    署名検証する。 通常アカウント(デフォルト)のスマートコントラクトは sigVerify(tx.bodyBytes, tx.proof0, tx.senderPk) である。と考えることができる。

  • toBase58String(bytes)
    バイトデータをBase58エンコードする

  • size(bytes)
    バイトデータのサイズ(データ長)を得る

  • Some(T), isDefined(Option[T]), extract(Option[T])
    中身空っぽからもしれないよ、を表すOptionというのがある。
    Some()でOptionが作られ、extract()でOptionから値を取り出す。
    extract()できるかをisDefined()で判断する。
    無理やりextract()すると、スマコンはfalseで終了する。たぶん。

その他

スマートコントラクトはトランザクション発行時点で判断される。
従って、例えばマルチシグなどの場合、その時には署名が揃っていなければならないが、
今の所
署名元データをリモートでやり取りすることや
署名すべきデータがあることの通知(リモートで知る手段)
などの仕組みは用意されていない。

その仕組み自体はマッチャーおよびデータフィードと同じようなものなので
クライアント含め、そのうち公式で用意されるかもしれない。

どう運用するかを設計することが大事だからね。

追記

2018-08-07

試してみたこと


See also