NEMのマルチシグをAPIレベルで紐解く

NEM にはマルチシグトランザクションという機能があります。

複数人で署名することで始めて成立するトランザクション、というものなのですが API レベルでどうやって使うのかよくわからなかったので、調査して nem-kotlin への実装を行いました。

調べてわかったことなどを書いておきます。

この記事では NanoWallet を使ってマルチシグを行う手順とかではなく、NEM の API としてどのようにしてマルチシグトランザクションを成立させるかと言う部分について記載します。

マルチシグトランザクションって何?

めちゃくちゃざっくり言うと、複数人が署名を行う(賛同する)ことで始めて成立するトランザクションということで理解しています。

こちらの記事の内容が参考になるかと思います。ご参照ください。

上記サイトでも記載されていますが、複数人で一つの口座を管理する、というイメージになるかと思います。

マルチシグトランザクションの構成要素

マルチシグトランザクションが一見して複雑なのは、構成要素が多すぎるからなんじゃないかと思います。

マルチシグトランザクションの流れを説明する前に、構成要素について軽く触れておきます。

  • アカウント
    • マルチシグアカウント
      これはNEM上ではアカウントの一種ですが、実際に署名するアカウント達が共同で管理する口座みたいなものだと考えて良いかと思います。
      マルチシグアカウント自体は送金トランザクションを発行できません(署名できません)。
      人ではない、ただのお金を入れる箱です。
    • 署名アカウント
      マルチシグアカウントアドレスにあるXEM、モザイクの送金は署名アカウントから行います。
      署名アカウント自体は通常のアカウントなので、正確にはマルチシグアカウントからの送金を行うトランザクションに対して、署名する権利を持ったアカウントという感じでしょうか。
  • トランザクション
    • マルチシグ集計変更トランザクション
      マルチシグアカウントに対して、必要署名数の変更、署名アカウントの追加削除を行うためのトランザクション。
    • マルチシグトランザクション
      複数署名が必要なトランザクション。今回の本題。
      構造としては本体のトランザクション(例えば送金トランザクション)をラップするような形のトランザクションになっています。
      本体のトランザクションは送金トランザクションとは限らず、上記マルチシグアカウント集計変更トランザクションも含まれます。
    • マルチシグ署名トランザクション
      特定のマルチシグトランザクションに対して、署名を行うためのトランザクション。

マルチシグトランザクションの流れ

マルチシグアカウントの作成

最初からマルチシグアカウントを作るというAPIとかはありません。

マルチシグ集計変更トランザクションを発行して、通常のアカウントをマルチシグアカウントに変更することになります。

マルチシグアカウントにしたいアカウントで署名したマルチシグ集計変更トランザクションを発行して、自身のアカウントをマルチシグアカウントに変更します。

マルチシグアカウントにしたいアカウントM と署名アカウントにしたい S1、S2、S3 がある場合の流れは下図の通り。

マルチシグ集計変更トランザクションで、

  • 署名アカウントに指定したいアカウントの公開鍵
  • 必要署名数

を指定できます。

マルチシグアカウントにすると、そのアカウントから直接送金トランザクションなどを送ることができなくなります。

マルチシグアカウントから直接送金トランザクションを発行しようとすると、”FAILURE_TRANSACTION_NOT_ALLOWED_FOR_MULTISIG” とエラーが返ってきました。

また、一度マルチシグアカウントにすると、戻す方法がないようなので、試す時は専用のアカウントを作って試すようにしましょう。

マルチシグ集計変更トランザクションで、マルチシグアカウントからすべての署名アカウントの登録を解除するともとの通常のアカウントに戻ります。

マルチシグ集計変更トランザクションが承認されると、アカウントM がマルチシグアカウントになります。

マルチシグアカウントから出金

作成したマルチシグアカウントからの出金する際は、署名アカウントの誰かからマルチシグトランザクションを発行します。

マルチシグトランザクションは他のトランザクションをラップするような構造のトランザクションになっています。

マルチシグトランザクション内のトランザクション(内部トランザクション)に、転送トランザクションを指定することでマルチシグアカウントからの出金を行うことができます。

流れとしては下図のような感じになるかと

  1. 署名アカウント S1 が内部トランザクションを転送トランザクションにしたマルチシグトランザクションを作成し、署名

  2. 署名アカウント S2 は未承認トランザクションとして 1. で作成されたトランザクションを確認。

  3. 署名アカウント S2 は 2. で取得した内部トランザクションハッシュと、マルチシグアカウントアドレスを指定してマルチシグ署名トランザクションを作成し、署名

  4. 必要署名数 (2) が集まったので承認される

内部トランザクションの署名者はマルチシグアカウントとなっていますが、これでどのアカウントを対象にした操作なのかということを表現しているのかなと思います。実際にはマルチシグアカウントで署名はしない(秘密鍵知らないのでできない)ので。

最終的に承認済みのトランザクションとして取得すると、マルチシグトランザクションに、内部トランザクションと署名トランザクションが含まれる形になります。

マルチシグアカウントの設定変更

マルチシグアカウントを作成した後に、必要署名数を変更したい場合を考えます。

必要署名数の変更、署名アカウントの追加削除はマルチシグ集計変更トランザクションですが、マルチシグアカウントから直接このトランザクションを発行できなくなっていますので、これも署名アカウントからマルチシグトランザクションとして発行することになります。

出金時とほぼ同じですが、下図のようになります。

マルチシグ集計変更トランザクションの署名数変更のパラメータは今の設定値からの相対値を指定します。

実践

ここから実践です。

といっても、今回は実装上の難点はあまりないかと思います。一応各トランザクションの作成の仕方を載せておきます。

前記事と同様、トランザクションの内容をバイト配列で表現し、それに対して署名作成するという方法をとります。

各トランザクションのバイト配列がどのようになるかを書いていきます。なお、手数料に関しては v0.6.93 現在のものを記載しています。

トランザクション共通部分

「AndroidでNEMのAPIを使って送金する」の記事でも書きましたが、トランザクション全種に共通部分があります。
今回のマルチシグトランザクションの内部トランザクションにもこれらのパラメータを指定する必要がありますのでご注意を(内部トランザクションのパラメータがどこまで意味があるのかは不明ですが)。

再度共通パラメータを書いておきます。パラメータの詳細については前記事も参照ください。

  • トランザクションの種別(4バイト)
  • バージョン(メインネットワークか、テストネットワークか。4バイト)
  • タイムスタンプ(4バイト)
  • 公開鍵の長さ(32固定、4バイト)
  • 公開鍵(32バイト)
  • 手数料(マイクロNEM単位、8バイト)
  • デッドライン(4バイト)

マルチシグ集計変更トランザクション

共通部分のあとに下記バイト列を続けます。

下記4つを追加・削除する署名アカウント数分繰り返し

  • 下記3つのバイト数の合計(4バイト。常に 40)
  • 追加か削除か(4バイト。 1 = 追加、 2 = 削除)
  • 署名アカウントの公開鍵の長さ(4バイト。常に 32)
  • 署名アカウントの公開鍵(32バイト)

その後に下記が続きます。

  • 下記1つのバイト数(4バイト)
  • 最小署名必要数の変更値(4バイト。今の設定からの変更量を相対値で指定。)

マルチシグ集計変更トランザクションの手数料は 0.5 XEMです。

マルチシグトランザクション

共通部分のあとに下記バイト列を続けます。

  • 内部トランザクションのバイト列の長さ(4バイト)
  • 内部トランザクションのバイト列

内部トランザクション内の公開鍵はマルチシグアカウントの公開鍵という点にだけ注意。

マルチシグトランザクションの手数料は 0.15 XEMです。内部トランザクションの手数料は別です。(後述)

マルチシグ署名トランザクション

共通部分のあとに下記バイト列を続けます。

  • 下記2つのバイト数の合計(4バイト。常に 36)
  • 署名する内部トランザクションハッシュの長さ(4バイト。常に32)
  • 署名する内部トランザクションハッシュ(32バイト)

  • マルチシグアカウントのアドレス長(4バイト。常に40)

  • マルチシグアカウントのアドレス(40バイト)

マルチシグ署名トランザクションの手数料は 0.15 XEMです。

マルチシグトランザクションの手数料について

マルチシグアカウントから出金を行う場合だと、各手数料はこんな感じ。

  • 転送トランザクションの手数料
    送る XEM、モザイクなどに依存。
  • マルチシグトランザクションの手数料
    0.15 XEM。
  • マルチシグ署名トランザクション
    0.15 XEM。

全部マルチシグアカウントから手数料が引かれるみたいです。

合計で、本体のトランザクション(今回は転送トランザクション)の手数料 + 必要署名数 * 0.15 XEM の手数料がかかる感じですね。

さいごに

ついこの間公開したトランザクションを監視する Skype の Bot ですが、

これでいきなりマルチシグに対応できてないというポカをやらかしたこともあり(現在は修正済みです)、自戒の念をこめてちゃんとマルチシグトランザクションの構造などを調べてみました。

nem-kotlin のマルチシグトランザクション対応は実装済みで、v0.3.0 にて入れます。これでもうマルチシグで迷わない!かな。


最後まで読んでいただきありがとうございます。 このブログを「いいな」と感じていただけましたら、Twiter にてフォローいただけるとうれしいです。ブログ更新情報などもお届けします。



この記事をシェアする




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA