トランザクション

パンダでもわかる miyabi(2)トランザクション詳細

 前回・・・といってももう3か月前になる。この記事自体は3か月前に書いてあったのだが、諸事情があり公開が遅れた。もはや本気でmiyabiを売る気があるのかと疑われてもしょうがない、と反省しよう。
 今年はmiyabiをどんどん表に出していきたい。なんといっても我々のブロックチェーンに対する想いが詰まった製品だ。今後の展開に期待してほしい!(自分を追い込んでみる)
 早速だが2月4日に miyabi のセミナーを行うので興味のある方はぜひ参加していただけると嬉しいです。申し込みは以下のリンクから。
https://hashhub.connpass.com/event/164253/

 さて前回、ブロックチェーンは分散ステートマシンであると書いた。そしてトランザクションとは、状態を変更するためのコマンドであるとも書いた。実のところ miyabi のトランザクションにはいろいろな秘密が詰まっている。今回はそのトランザクションについて説明しよう。

 まずは位置づけだ。miyabi におけるトランザクションは実行の最小単位であり、状態を変更するための唯一の手段でもある。実行の最小単位なので失敗したら状態は書き換わらずにロールバックされる。
 また当然だがトランザクションはブロックに記録されるのでいわゆるログとしても機能する。このログは改ざん不可能であり、なかったことにもできない。これはブロックチェーンだから当たり前だろう。

トランザクションの中を見てみる

 次に詳細を見てみよう。トランザクションは次の4つのパートから構成される。
1、ヘッダー
2、トランザクションエントリーのリスト
3、Required Signatures
4、実際の署名

トランザクション

 まず注目してほしいのは Required Signatures だ。
 このエリアにはトランザクションに署名するべき公開鍵(のリスト)を記載する。実際の署名は4のエリアに置かれる。つまり3と4のエリアを見比べて、指定されたとおりの署名がなければ形式的にエラーとなるというわけだ。

 前回、テーブルへの書き込み権限チェックではトランザクションの署名を使うと書いた。今説明した形式チェックはこの実行時のチェックとは別物である。このチェックは形式チェックなので実行時まで待たなくても、トランザクションの受信時に行うことができる。
 実行時には本当にそのデータを変更する権限があるか?というチェックが別途行われる。

 そもそも形式的なチェックが通っているのなら、わざわざ実行時にチェックせずとも必ず成功しそうなものだが、トランザクションの作成者が正直者とは限らないので必要な権限を Required に指定しないこともあり得る。
 あるいはスマートコントラクト呼び出しトランザクションの場合、どのテーブルにアクセスするのか予測することは困難だ。単純にスマートコントラクトを解析するのが大変という側面もあるが、そもそも条件分岐があるような場合、条件次第でどのデータを書き換えるかは実行時までわからない、というパターンもあることを指摘しておこう。

複合トランザクション

 2のエリアにはトランザクションエントリーのリストが入る。トランザクションエントリーというのはいささか不格好な命名なのだが、非常に重要な概念だ。これは命令(実行ではない)の最小単位なのだ。具体的には
 「コインを移動させろ」とか
 「XXXX テーブルの YYYY という行に ZZZZ と書き込め」とか
 「スマートコントラクト ABC をパラメータ(a,b,c)で呼び出せ」
のようなものが入る。
 少しややこしく見えるが「コインを動かせ」とか「書き込め」とかも、組み込みのスマートコントラクトを呼び出していると捉えれば、結局はスマートコントラクトの呼び出しのことだと考えてもいいだろう。

 トランザクションエントリーは任意の個数持つことができる。ふーん、と思うかもしれないがこれは大きな設計上のポイントなのである。実際「複合トランザクション」ということで 特許 も取得しているくらいだ。

 まず複合トランザクションによりエスクローが簡単に実現される。
 実行(命令ではない)の最小単位はトランザクションなので、複数のトランザクションエントリーは全部実行されるか、全部実行されないかのどっちかにしからならない。例えば2つのコインの移動があった場合にどちらか片方が(残高不足などで)失敗した場合に、中途半端な状態になることなく両方とも元の状態に戻る。
 なので「A->Bに 1 BTC」「B->Aに100万円」という複合トランザクションを作成すれば、両方とも成功するか両方とも失敗するかになる。つまりエスクローが実現されるというわけだ。

 次に複合トランザクションは契約者間の合意という意味あいもある。契約内容(トランザクションエントリー)に対して契約者(AとB)が両者とも署名する、というのは現実世界の契約書にハンコを押すというのと同じことであり、両者の合意を示しているといえるだろう。

 また複合トランザクションにすることで、実行の順序を指定することも可能だ。入金してから支払うような場合、入金の方を先に処理しなくてはならないケースのあるだろう。

問題点

 もちろんこれらの利点は只では手に入らない。最大の障害は Replay Attack 対策の難しさである。
 ここでは一度実行したトランザクションをもう一度実行することを Replay Attack と呼ぼう。これを防がないと、一度支払いトランザクションを作ったら残高がなくなるまで何度でも実行されて、すっからかんになってしまう。

 まず miyabi でどう対応してるかを説明する前に、他のコインではどうやっているかを調べてみることにしよう。
 ビットコインの場合:支払いトランザクションは UTXO と呼ばれる未使用コインを新たな所有者に送ることで実現される。だから同じトランザクションをリプレイしてもすでにその UTXO は使用済みである、と判断されエラーになる。これがビットコインにおける Replay Attack を防ぐメカニズムである。

 イーサリウムの場合:イーサリウムには UTXO というものがない。UTXO の代わりにもっと柔軟なステータスを扱えるようにしたからだ。だから Replay Attack を防ぐためにある機能が発明された。それが「ナンス」である。
 ナンスとはアカウント(アドレスのようなもの)が過去に実行したトランザクションに付与される連番であり、イーサリウムのノードはアカウントごとに何番まで実行したかを記憶している。なので同じ番号を2度と実行することがないのだ。
 これを機能させるためにはトランザクション作成者もアカウントごとに何番まで実行したかを覚えていなくてはならない。これはトランザクションはアカウントという単位に縛られるということでもある。だから複合トランザクションのようにアカウントと1対1に結び付けることができないような場合には、そもそも連番そのものを設定できず困ってしまう。

 では miyabi ではどうやって解決しているのだろうか?実は非常に原始的な方法でこの問題を解決している。それは
「過去に実行したトランザクションIDは2度と実行できない」
 という制約をかけることである。
 しかしこの制約をそのまま実装してしまうと、過去に実行したすべてのトランザクションIDに対して重複チェックをしなくてはならず、運用を続けるらうちにメモリを食いつぶしてしまう。
 そこで miyabi ではさらにもう一つのルールを設けた。
「トランザクションには有効期限がある」
 である。

 この有効期限はトランザクションヘッダに記載されている。要はトランザクションには賞味期限があるのだと思ってもらいたい。
 だからある程度古いトランザクションは絶対に実行されない。賞味期限が切れているからだ。ゆえに古いトランザクションについてはわざわざ重複チェックをする必要がない(どうせ実行されないので)。
 この単純なルールにより miyabi が重複チェックをしなくてはならないトランザクションはある限られた範囲に収まることになる。これならばどんなに長期間運用したとしても限られたメモリで重複チェックが可能だ。ちなみにあまりに未来の有効期限を設定した場合この機構が働かなくなってしまうため、有効期限の上限チェックも行われる。

 なお有効期限チェックをするためには「現在時刻」が必要だ。しかしノードによってタイマーは異なっているので内蔵のシステムタイマーは利用できない。そこで miyabi ではブロックの生成時刻を「現在時刻」として利用している。このへんは決定性ステートマシーンらしい特徴といえよう。

次回

 複合トランザクションは miyabi の大きな特徴である。これによってエスクロー取引を自然に表現でき、リレーショナルデータベースのようにコミット・ロールバックが表現できる。

 次回はいよいよスマートコントラクトについて書こうと思う。miyabi のスマートコントラクトはアセットのオーナーになれる。これは miyabi の特徴の中でも私が最も気に入っているものなのでちょっと気合が入る。

(お知らせ)bitFlyer Blockchainでは仲間を募集しています!




この記事が気に入ったらサポートをしてみませんか?