はじめに

こんにちは。ブロックチェーン推進室の鈴木です。

私の所属するブロックチェーン推進室では、企業間取引に特化したエンタープライズブロックチェーンプラットフォーム:Cordaに関して機能調査を行っております。
Cordaは世界で350社を超える金融機関、規制当局、中央銀行、業界団体、システム・インテグレーターやソフトウェアベンダーにより構成されるR3エコシステムから、エンドユーザー目線で設計・開発されています。
また、4半期に1度のバージョンアップにより機能追加がされていますが、その機能がお客様に活用できるものなのか、ドキュメントだけではわからないことも多く、ブロックチェーン推進室独自で調査を進めています。

このブログでは、そういったCordaの機能調査をした結果を機能の使い方含めて紹介していきます。

Cordaの導入方法についてはこちらのドキュメントをご参照ください。

今後以下の内容で紹介しようと思います。

  1. Corda JMeterの使い方

  2. Corda Enterprise Performance検証 ノードスペックを変化することによる性能変化

  3. Corda Tokens SDK and Accounts

  4. Corda Enterprise Collaborative Recovery

  5. Corda Enterprise Archive Service(←今回はこちらの記事)

  6. Corda Firewallの設定方法

  7. Corda re-issuance Tokens SDK and Accountsを利用した一括「re-issuance」

  8. Corda Time-windows

  9. Corda Oracle

  10. Corda attachment

  11. Corda Webアプリケーション開発について

  12. Cordaを用いたNonFungibleTokenの実装

  13. CordaのTokens SDKでNFTマーケットプレイスを作ってみた

(以降、バージョンアップの都度、新機能を紹介予定)

第5回目は「Corda Enterprise Archive Service」について紹介します。

概要

「Archive Service」は2020年12月にリリースされたCorda Enterprise 4.7で新しく追加された機能です。

アーカイブとは、使わなくなったデータを長期保管するために専用の領域に移動すること、またはそのデータそのものを指します。
Archive Serviceはすでに終了したトランザクションのアーカイブを作成し、それを必要な時に復元できます。
アーカイブすることにより、ノードのデータベースへの負荷を軽減し、vaultを整理できます。アーカイブはトランザクションチェーン単位で実施します。
またアーカイブできる条件として、対象のトランザクションチェーン内に未消費のStateがないことが条件になります。

例として、図1のトランザクションではアーカイブ可能になります。 円に書かれたアルファベットは所有者を示します。 tx1でOutput Stateを作成し、tx2でそのStateを消費して終了するトランザクションチェーンです。

図1:未消費のstateがない場合

一方で図2のトランザクションではアーカイブ不可になります。
tx1でOutput Stateを作成し、tx2でそのStateを消費してOutput Stateを作成します。
tx2で作成されたOutput Stateがまだ消費されていないためこのトランザクションチェーンのアーカイブはできません。

図2:未消費のstateがある場合

◎用語説明

◆fillter

filterは条件を指定して、どのトランザクションチェーンをアーカイブするかを仕分けします
独自のfilterを実装することもでき、デフォルトでは現在以下の3つのfilterが用意されています。

  • AttachmentNameFilter
  • PartyFilter
  • TransactionIdFilter

◆ExporterとImporter

Exporterは形式を指定して、その形式のアーカイブファイルを作成します。
export対象のテーブルはQueryable state tables(自分で定義したテーブルなど)とcordaが用意しているテーブル(node_transactionsなど)になります。
Queryable state tablesのデータはCSV形式でexportできます。
また、Importerを利用してアーカイブをvaultに復元できます。 filterと同様にExporterとImporterも独自のものを実装できます。

◆バックアップスキーマ

バックアップスキーマを利用することで、Archive Service操作中に障害が起きてもデータを復元できます。
バックアップスキーマの利用は必須ではありませんが、安定運用を考えた場合、導入することをお勧めします。
注意点としてアーカイブ実施時はバックアップスキーマにバックアップ対象の全データを書き出す為、一時的にデータ容量がふえます。

◆job

Archive Serviceの一連の流れのことを指します。

◆App Entity Manager

台帳外のテーブルへアクセスするための機能です。

Archive Serviceの構築

1. jarの配置

アーカイブを行うノードのcordapps直下に下記のjarを配置します。

  • archive-service-1.0.jar(2021年10月時点では1.0.1が最新版です。)
  • ledger-graph-1.2.jar(2021年10月時点では1.2.1が最新版です。)

2. 設定ファイルの配置

上記のcordappsのconfig直下にarchive-service-1.0.confを作成します。
※ファイル名は1で配置したarchive-service-X.X.jarと同じ名前にします。(拡張子は.conf)

3. アーカイブサービスコマンドラインツールの配置

corda-tools-archive-service-1.0.jar(2021年10月時点では1.0.1が最新版です。)
引数にRPCの情報を渡してあげればどこに配置しても利用できます。
Cordaノード直下(具体的にはCorda.jarが配置されているディレクトリと同じ場所。以下同じ。)であれば自動的にnode.confから必要な情報を読み込んでくれるため、今回はCordaノード直下に配置します。
また、APIも用意されているのでアーカイブサービスコマンドラインツールなしでもFlowから実行できます。

4. バックアップスキーマの利用

4-1. ユーザ、スキーマの作成

対象のノードのDBで下記のテンプレートを実施します。archiveユーザを 作成し、archiveスキーマを作成します。my_schemaを参照できるようにするために権限を付与します。

Postgresの場合

create user archive password ‘archive’; 
create schema archive AUTHORIZATION archive; 
grant usage on schema my_schema to archive; 
grant select on all tables in schema my_schema to archive; 
grant insert on all tables in schema my_schema to archive;

4-2. confファイルの設定

2で作成したファイルに下記の記述を追加します。これはバックアップ スキーマのDBの接続設定です。
バックアップスキーマはノードのvaultと同じDB内に存在しないといけません。また所有者はcordaユーザとは異なる必要があります。

target: {
    url: “jdbc:postgresql://IPアドレス:port /DB名”
    user: “archive”
    password: “archive”
    schema: “archive”
  }

5. アーカイブ用テーブルの初期化

CordappsのArchive Serviceで利用するテーブルを初期化します。

java -jar corda-X.X.jar run-migration-scripts --core-schemas --app-schemas

ここでArchive Serviceの構築が完了しました。次は実際にArchive Serviceを利 用していく手順を紹介します。

Archive Serviceの実施

アーカイブしたい対象のCordaノードを起動します。
その後、corda-tools-archive-service-1.0.jarの配置してある箇所に移動し、Archive Serviceを起動します。(今回はCordaノード直下に配置しているため移動は必要ありません。)
アーカイブ対象のCordaノードが起動していないとArchive Serviceは起動しません。

1. 進行中のjobの確認

引数に-t list-jobsを指定します。

java -jar corda-tools-archive-service-1.0.jar -t list-jobs

There are no active archive jobs

上記はまだ進行中のjobがないため、There are no active archive jobsと表示されます。現在進行中のjobがあればそのjob情報を表示します。

2. アーカイブできるトランザクションの数と情報を表示

引数に-t list-itemsを指定します。

java -jar corda-tools-archive-service-1.0.jar -t list-items

? Starting
  ? Reading configuration
  ? Loading filters
  ? Executing filters
  ? Done
Number of archivable transactions: 3
Number of archivable attachments: 0
Approximate size of archivable transactions: 32KB
Approximate size of archivable attachments: 0B

アーカイブ可能なトランザクションの数とバイト数が表示されます。 この段階ではまだアーカイブは実施されません。

3. アーカイブjobの作成

引数に-t create-snapshot を指定します。

java -jar corda-tools-archive-service-1.0.jar -t create-snapshot <job名>

? Starting
  ? Reading configuration
  ? Check workflow progress
  ? Loading filters
  ? Executing filters
  ? Clear previous result
  ? Marking transactions
  ? Marking attachments
  ? Create snapshot name
  ? Recording table schema
  ? Get expected row counts
  ?   NODE_TRANSACTIONS
  ?   VAULT_STATES
  ?   VAULT_TRANSACTION_NOTES
  ?   STATE_PARTY
  ?   VAULT_FUNGIBLE_STATES
  ?   VAULT_FUNGIBLE_STATES_PARTS
  ?   VAULT_LINEAR_STATES
  ?   VAULT_LINEAR_STATES_PARTS
  ?   NODE_SCHEDULED_STATES
  ?   CAR_STATES
  ?   NODE_BFT_COMMITTED_STATES
  ?   NODE_BFT_COMMITTED_TXS
  ?   NODE_RAFT_COMMITTED_TXS
  ?   NODE_ATTACHMENTS
  ?   NODE_ATTACHMENTS_CONTRACTS
  ?   NODE_ATTACHMENTS_SIGNERS
  ? Recording transactions
  ?   NODE_TRANSACTIONS
  ?   VAULT_STATES
  ?   VAULT_TRANSACTION_NOTES
  ?   STATE_PARTY
  ?   VAULT_FUNGIBLE_STATES
  ?   VAULT_FUNGIBLE_STATES_PARTS
  ?   VAULT_LINEAR_STATES
  ?   VAULT_LINEAR_STATES_PARTS
  ?   NODE_SCHEDULED_STATES
  ?   CAR_STATES
  ? Recording attachments
  ?   NODE_BFT_COMMITTED_STATES
  ?   NODE_BFT_COMMITTED_TXS
  ?   NODE_RAFT_COMMITTED_TXS
  ?   NODE_ATTACHMENTS_CONTRACTS
  ?   NODE_ATTACHMENTS_SIGNERS
  ? Verify results
  ? Update job records
  ? Done
Number of transactions marked: 3
Number of attachments marked: 0
Approximate size of archivable transactions: 32KB
Approximate size of archivable attachments: 0B
Transaction Tables
NODE_TRANSACTIONS: 3 rows
VAULT_STATES: 2 rows
STATE_PARTY: 2 rows
CAR_STATES: 2 rowsAttachment TablesQueryable Tables
VAULT_STATES: 2 rows
CAR_STATES: 2 rows

このコマンドでjobを作成します。Job名は自身で設定でき、デフォルトは現在の日付です。
ここでアーカイブするトランザクションの情報やjobの情報をアーカイブ用のテーブルに登録します。
バックアップスキーマを利用している場合はここでコピーされます。また、バックアップスキーマを利用し、正しくarchiveユーザに権限が付与されていない場合はここでエラーが発生します。
その際はjobをキャンセルし(後述参照)、archiveユーザに権限が付与されているか確認してください。

4. トランザクションをアーカイブする

引数に-t export-snapshot –exporters=を指定します。

java -jar corda-tools-archive-service-1.0.jar -t export-snapshot --exporters =ZippedFileExporter

? Starting
  ? Reading configuration
  ? Check workflow progress
  ? Retrieve table schema
  ? Executing exporters
  ?   Exporting transactions
  ?   Exporting attachments
  ?   Exporting queryable state tables
  ? Update job records
  ? Done
ZippedFileExporter:
  Completed export of 3 transactions to transaction-job名.zip
  Completed export of 0 attachments to attachment-job名.zip

exportersにはもともと用意されているZippedFileExporterを指定します。これによりCordaノード直下にzipファイルとしてアーカイブデータが作成されます。

5. vaultを削除する

引数に-t delete-vaultを指定します。

java -jar corda-tools-archive-service-1.0.jar -t delete-vault

? Starting
   ? Reading configuration
   ? Check workflow progress
   ? Retrieve table schema
   ? Purge transactions
   ?   NODE_TRANSACTIONS
   ?   VAULT_STATES
   ?   VAULT_TRANSACTION_NOTES
   ?   STATE_PARTY
   ?   VAULT_FUNGIBLE_STATES
   ?   VAULT_FUNGIBLE_STATES_PARTS
   ?   VAULT_LINEAR_STATES
   ?   VAULT_LINEAR_STATES_PARTS
   ?   NODE_SCHEDULED_STATES
   ?   CAR_STATES
   ?   NODE_BFT_COMMITTED_STATES
   ?   NODE_BFT_COMMITTED_TXS
   ?   NODE_RAFT_COMMITTED_TXS
   ? Purge attachments
   ?   NODE_ATTACHMENTS
   ?   NODE_ATTACHMENTS_CONTRACTS
   ?   NODE_ATTACHMENTS_SIGNERS
   ? Update job records
   ? Done
 Transaction Tables
 NODE_TRANSACTIONS: 3 rows
 VAULT_STATES: 2 rows
 STATE_PARTY: 2 rows
 CAR_STATES: 2 rows
 
 Attachment Tables
 
 Queryable Tables
 VAULT_STATES: 2 rows
 CAR_STATES: 2 rows

delete-vaultを実施すると、トランザクションテーブル、vaultテーブルからデータが削除されます。
create-snapshotを実施するとdelete-vault、もしくはバックアップスキーマを利用している場合delete-snapshot(後述参照)まで実施し、jobを完了させます。1つのjobを完了するまで別のjobを作成することはできません。

5.’ アーカイブをキャンセルする

引数に-t restore-snapshotを指定します。

java -jar corda-tools-archive-service-1.0.jar -t restore-snapshot

バックアップスキーマを作成している場合はdelete-vaultで削除したデータを復元し、jobを終了できます。
また、delete-vaultより前、またはバックアップスキーマを利用していない場合、このコマンドを入力するとjob情報を削除し、jobを終了できます。

6. バックアップスキーマの削除

引数に-t delete-snapshotを指定します。

java -jar corda-tools-archive-service-1.0.jar -t delete-snapshot

? Starting
  ? Reading configuration
  ? Check workflow progress
  ? Retrieve table schema
  ? Purge transactions
  ?   NODE_TRANSACTIONS
  ?   VAULT_STATES
  ?   VAULT_TRANSACTION_NOTES
  ?   STATE_PARTY
  ?   VAULT_FUNGIBLE_STATES
  ?   VAULT_FUNGIBLE_STATES_PARTS
  ?   VAULT_LINEAR_STATES
  ?   VAULT_LINEAR_STATES_PARTS
  ?   NODE_SCHEDULED_STATES
  ?   CAR_STATES
  ?   NODE_BFT_COMMITTED_STATES
  ?   NODE_BFT_COMMITTED_TXS
  ?   NODE_RAFT_COMMITTED_TXS
  ? Purge attachments
  ? Update job records
  ? Done
Transaction Tables
NODE_TRANSACTIONS: 3 rows
VAULT_STATES: 2 rows
STATE_PARTY: 2 rows
CAR_STATES: 2 rowsAttachment TablesQueryable Tables
VAULT_STATES: 2 rows
CAR_STATES: 2 rows

バックアップスキーマを利用している場合、そのデータを削除します。このコマンド後にjobが完了します。 バックアップスキーマを利用していない場合、このコマンドは必要ありません。

7. アーカイブしたデータを復元する

引数に-t import-snapshot –importer=を指定します。

java -jar corda-tools-archive-service-1.0.jar -t import-snapshot <job名> --importer=ZippedFileImporter

? Starting
  ? Reading configuration
  ? Check workflow progress
  ? Executing importer
  ?   Importing attachments
  ?   Importing transactions
  ?     Reading transactions
  ?     Parsing transactions
  ?     Sorting transactions
  ?     Recording transactions
  ? Verify results
  ? Delete job records
  ? Done
Number of transactions imported: 3
Number of attachments imported: 0

Importerにはもともと用意されているZippedFileImporterを指定します。
データベースにアーカイブしたデータを復元します。import前にCordaノードを再起動する必要があります。

データベースについて

実際にデータベースがどのように変化していくかを記述していきます。
create-snapshotを実施するとjobに関する情報が登録されます。

  • archiving_jobにはjob名やjobのIdが登録されます。
  • archiving_job_tableにはアーカイブするtableの情報が登録されます。
  • archivable_txにはアーカイブできるものとしてマークされた各トランザクションのidと関係者情報が登録されます。

delete-vaultを実施するとアーカイブ対象のレコードが削除されます。

import-snapshotを実施すると、アーカイブされた情報が復元され、create-snapshotで登録された情報は削除されます。その際、node_transactionsやvault_statesのtimestampはimportした時刻が記述されます。

アーカイブ可能パターンの検証結果

実際どのようなトランザクションのパターンでアーカイブできるかを検証しました。検証結果としては下記の表になります。
検証の基準として、自ノードのみか他ノードが関係するか、未消費のStateの有無、トランザクションの合流と分岐の有無を挙げています。
他ノードが関係するパターンでは各ノード視点でアーカイブ可否を記述しています。
例えばNo1では自ノードのみが関係するトランザクションチェーンで未消費のStateが存在し、トランザクションが分岐、合流しないパターンでの結果はアーカイブ不可ということを示しています。
No10では他ノードが関係するトランザクションチェーンで未消費のStateが存在せず、トランザクションが分岐、合流しないパターンでの結果は自ノード自身でのアーカイブは不可で他ノード自身でのアーカイブは可ということ示しています。
未消費のStateがある場合にはどのパターンでもアーカイブは不可になります。自分のノードのみで完結するパターンであれば表の通りになりますが、他のノードが関係するパターンではアーカイブ可否が表と異なる場合があります。

アーカイブ可否の検証パターンと結果

アーカイブ可否のポイントになる箇所を例として考えます。 図3のチェーンではBのみアーカイブ可能です。
このパターンではトランザクションチェーンに未消費のStateがありませんが、A側ではアーカイブできません。
B側ではトランザクションチェーンの終了を認知できますが、A側からはチェーンの終了を認知できないためアーカイブ不可だと考えられます。

図3:Stateの生成者と消費者が異なる場合

また図4のチェーンではA、Bともにアーカイブ不可です。
Aから見てtx2の所有者がBのOutput State、Bから見てtx2の所有者がAのOutput Stateに対して、両者ともそのStateを消費できたか認知できないため、このトランザクションチェーンが終了しているかわからず、A、Bともにアーカイブすることはできません。

図4:トランザクションが複数のノードに分岐する場合

また図の5のチェーンでは両者ともアーカイブ可能です。
これは図3のトランザクションチェーンと相似していますがtx2のOutput Stateの所有者が二者になっており、そのStateを消費するトランザクションチェーンです。
図3ではBのみアーカイブ可能でしたがこの場合はAもチェーンの終了を認知できるためアーカイブできます。

図5:共有するStateを消費する場合

考察と所感

調査していく中で色々とアーカイブにおける条件がわかりましたので、まとめます。

【アーカイブできる条件】

  • 未消費のStateがないこと。
  • チェーンの終端全ての関係者であること。

分岐や合流、他者を含むトランザクションにおいても上記2つの条件に当てはまればアーカイブが可能です。

【importできる条件】

  • importするファイル名はexportされた時のファイル名であることです。 例えばファイル名をリネームしてimportを実施しても失敗してしまいます。
  • importするファイルはCorda.jarを配置している場所と同じ場所に存在する必要があります。
  • job名は一致していても基本的に対象のノードでexportしたものしかimportできません。 例えばNodeAとNodeBがそれぞれトランザクションを発行し、同じjob名でアーカイブを作成します。
    exportしたファイルをNodeA、NodeBで入れ替えそれぞれimportをすると失敗します。
    例外として、ObserverやNodeA、B間でStateを共有するなどして、同一のトランザクションチェーンのみをアーカイブし、exportしたファイルであれば、それぞれ入れ替えてimportをしても成功します。

【苦労した点】

この度アーカイブサービスを調査するにあたり、ExporterやImporter、filterに関してとても苦労しました。
それぞれ、独自に実装できるためもともと用意されているものがあるか、一から全て実装しなければいけないのかというところで試行錯誤しました。
また、アーカイブする条件では、NodeAだけならば想像つきやすかったのですがNodeBとの取引においてどちらのvaultにデータがあるかを考え、チェーンがどのようになっているかを意識しないといけなかった点にも苦労しました。

【結果分かったこと】

アーカイブ可否がある以上、Archive Serviceに適したCordappsを作成する必要があります。またCordaの公式ページにはアーカイブに適したCordappsの特徴として以下とあります。

• Short transaction chains that will get consumed in their entirety.
• Consumes and redeems ‘irrelevant states’ — for example if you store evolvable data it should be consumed even if it is no longer directly queried or used in a transaction.
• Avoids consuming outputs of one transaction via multiple transactions. This could mean ensuring fungible assets are distributed as narrowly as possible — rather than from multiple cash supplies.

要約すると、Archive Serviceに適したCordappsの特徴は以下となります。

  • 短いトランザクションチェーンで完結する、もしくはトランザクションチェーンを定期的に切断しStateを再発行するような機能を有していること。
  • ビジネスロジック上使用されなくなったStateに関しても償還できる機能や処理を有していること。
  • Transactionが生成したOutput Stateを複数のTransactionのInput Stateとして使用されない仕組みになっていること。 したがって枝分かれしていくものや様々な人が交互に関係するものには適していないと考えます。

今回は以上になります。