本記事は生成AIと共同で執筆しています。事実関係は可能な範囲で公式ドキュメント・一次情報と照合していますが、誤りが含まれている可能性があります。重要な判断を行う前にご自身でも一次情報をご確認ください。
データスペースに資料を載せる、というのが具体的に何をすることなのか。手を動かして確かめました。
使ったのは Clio-X(ciferresearch/ClioX-mvg-portal)というポータルです。UBC が中心となって開発している、アーカイブズ向けのデータスペース実装で、Ocean Protocol の上に乗っています。
チュートリアルです。 ただし公式手順のなぞりではありません。素の状態では STEP 2 から先に進めませんでした。その原因4点も含めて記録します。
そもそも何をする行為なのか
「publish する」と言いますが、実際に起きるのは3つです。
- NFT とデータトークンを作る(オンチェーン取引1本目)
- メタデータを暗号化して、その NFT 自身に書き込む(オンチェーン取引2本目)
- 索引に載る(ノードがイベントを拾って検索可能にする)
データ本体はチェーンに載りません。 載るのは「暗号化された参照」だけです。ファイルは元の場所(URL)に置いたままで、Compute-to-Data ではそこへ計算を持っていきます。
6段のウィザードは「4つの宣言 + 確認 + 実行」
| # | 画面名 | 何を宣言する段か |
|---|---|---|
| 1 | Metadata | これは何か(題名・説明・著者・種別) |
| 2 | Access | どう渡すか(鍵を配る主体、渡し方、実ファイル) |
| 3 | Policies | 誰に・いつまで・どの条件で |
| 4 | Pricing | いくらで |
| 5 | Preview | 上の4つを合成した資産ページを見せるだけ |
| 6 | Submit | 実行 |

前半4段では通信もチェーンへの書き込みも起きません。 1つのフォームに値を貯めているだけです。したがって ページを再読込すると入力は全部消えます(実装にも「CAUTION: all data will be deleted anyway」と書いてあります)。
例外が1つ。STEP 2 のファイル検証だけは実際に通信します。
STEP 2 が一番重い
ここで決めるのは3つです。
- Access Token(datatoken) — この資産へのアクセス権を表すトークンの名前と記号
- Access Controller(Provider) — どの Ocean Node に任せるか
- File — データ本体の URL
Access Controller の指定が効きます。 ここで選んだノードが、後に計算環境の一覧を提供します。データ提供者が「どの計算拠点群に任せるか」を決める場所であって、個々の計算環境を選ぶ場所ではありません。環境の選択は、利用者が実行時に行います。
File の URL を入れると ノードが実際にその URL を取りに行きます。到達できて ✓ File confirmed が出るまで、次へ進めません。ここだけは宣言ではなく検証です。

STEP 3 では「誰に・いつまで・どの条件で」を決めます。ここで入れた License は、あとで資産ページに表示されます。

STEP 4 の価格。今回は無償配布(dispenser)にしました。無償にしても後述のガス代はかかります。

資産は3種類ある
STEP 1 の Asset Type で Dataset / Algorithm / SaaS を選びます。選んだ瞬間にフォームの中身が変わります。
| Dataset | Algorithm | SaaS | |
|---|---|---|---|
| Docker Image(STEP1) | — | あり | — |
| 個人情報の申告 | あり | — | あり |
| File のタブ(URL/API/…) | あり | あり | なし |
| Access Type の箱 | あり | なし | なし |
| Algorithm Privacy | — | あり(既定 ON) | — |
| Redirect URL / 課金モード | — | — | あり |
| ファイルの到達性検証 | 必要 | 必要 | 不要 |
つまずきやすい点を3つ。
- Docker Image は STEP 2 ではなく STEP 1 にあります。 アクセスの話に見えますが、Ocean のデータモデル上は「そのアルゴリズムが何であるか」の一部なので Metadata 側です
- Algorithm には Access Type の箱が出ません。 代わりに「Keep my algorithm private for Compute-to-Data」が既定 ON で出ます。これがサービス種別を
computeに倒すため、アルゴリズムはダウンロード不可になります - SaaS はファイルの到達性を検証しません。 URL の書式が正しければ通ります。誰も到達性を確かめません
SaaS はチェーン上では「型」ではない
ここが一番意外でした。このポータル(mvg-portal 系のフォーク)から SaaS を選んで公開しても、書き込まれる metadata.type は dataset のままです。画面で SaaS を選んだ瞬間、フォームの内部では metadata.type に dataset が代入され、SaaS であることは別のフィールドに退避されます。
"metadata": {
"type": "dataset",
"additionalInformation": {
"saas": {
"paymentMode": "Pay per use",
"redirectUrl": "https://tify.rocks/?manifest=..."
}
}
}
カタログの絞り込みも、型ではなくこの目印の有無を見ています。
const saasFieldExists = {
exists: { field: 'metadata.additionalInformation.saas.redirectUrl' }
}
画面上の3タイプは、このポータルが書き込む DDO では「2つの型 + 1つの目印」です。
ただしこれはこの公開経路の実装の話で、Ocean のデータモデルが 2 種類しか許さないという意味ではありません。実際、Pontus-X の公開カタログを curl で覗くで集計したとおり、metadata.type に SaaS や compute を持つ資産も少数ながら存在します。
そして SaaS は Compute-to-Data の枠組みの外にあります。データを渡すのでも計算するのでもなく、「稼働中のサービスへのアクセス権」を流通させるための型です。購入するとその URL へ飛ばされます。
Submit で何が起きるか
ここで初めてチェーンに書きます。画面にも3段として説明が出ます。

取引1本目 — トークンと蛇口を作る
ERC721Factory.createNftWithErc20WithDispenser を1回呼び、NFT・データトークン・無償配布の蛇口(dispenser)をまとめて作ります。
取引なし — DDO を組み立てて暗号化
入力から DDO(資産のメタデータ文書)を組み立て、Ocean Node に暗号化してもらいます。ファイル URL は別途、単独で暗号化されます。ここはチェーンを使いません。
取引2本目 — DDO を NFT に書き込む
暗号化済みの DDO を、NFT 自身の setMetaDataAndTokenURI で書き込みます。

索引に載るまで 20〜30 秒かかります。直後に資産ページを開くと「見つからない」ことがありますが、待てば出ます。

ブロックチェーンとして何が起きているのか
ここは私がブロックチェーンを学びながら書いている部分です。実際に公開した1件の取引を、チェーンから読み直して確かめました。
まず「誰の何が減るのか」
減るのは、公開する人の ETH です。 データを登録するだけでお金がかかります。
ここで混同しやすいのですが、この publish には2種類のトークンが登場し、動きが逆向きです。
| 何のためのもの | publish のとき | |
|---|---|---|
| ETH(Sepolia のテスト ETH) | ネットワークに払う手数料(ガス代) | 公開者から減る |
データトークン(今回は GXAT) | この資産へのアクセス権を表す引換券 | 新しく作られる(減らない) |
つまり「トークンが減る」のは ETH の話であって、データトークンはむしろ publish で生まれます。データトークンを使うのは、あとで資産を利用する側です。今回は価格を無償配布(dispenser)にしたので、利用者は蛇口から 1 枚もらって引き換えるだけで、支払いは発生しません。それでも公開者のガス代はかかります。
実際いくらかかったか
この記事の日本語版デモで公開した1件(Sepolia)の実測です。
| 1本目 | 2本目 | |
|---|---|---|
| 呼んだ関数 | createNftWithErc20WithDispenser | setMetaDataAndTokenURI |
| 宛先 | ERC721Factory(0xef62fb49…) | 作られた NFT 自身(0x04ECc497…) |
| ブロック | 11482338 | 11482339 |
| 使ったガス | 1,316,967 | 516,615 |
| ガス単価 | 2.599 Gwei | 2.574 Gwei |
| 手数料 | 0.003423 ETH | 0.001330 ETH |
| 送ったデータ | 1,252 バイト | 3,940 バイト |
| 出たイベント | 15 件 | 2 件 |
合計 0.004753 ETH。 本番の Ethereum メインネットで同じことをすれば、ETH の実勢価格とガス単価次第で数千円〜数万円になります。「データを1件登録するのにお金がかかる」というのは、そういう意味です。
ガス代の考え方: 手数料 = 使ったガス量 × ガス単価。ガス量は計算と保存の重さで決まり、単価はそのときのネットワークの混み具合で決まります。1本目のほうが高いのは、契約を3つ(NFT・データトークン・蛇口)新規に作っているからです。契約を作る操作はチェーン上で最も高価な部類に入ります。
NFT の知識は要るか — 要りますが、絵の話ではありません
「NFT」というと美術品の話に聞こえますが、ここでの NFT は2つの役割を持つ道具です。
- 所有権の記録 — 誰がこの資産の持ち主かをチェーンが保証する。持ち主だけがメタデータを書き換えられる
- 書き込める保管場所 — NFT の契約自身が、メタデータを入れておくための領域を持っている
2つ目が肝心です。普通の NFT は「画像の URL を指す」だけですが、Ocean の NFT は暗号化したメタデータ本体をその中に持ちます。だから2本目の取引の宛先が、ファクトリではなく作られた NFT 自身になっています。上の表で宛先が変わっているのは、そういう理由です。
資産の ID(DID)も NFT から機械的に決まります。
did:op: + sha256( NFTアドレス(チェックサム表記) + チェーンID )
実際に計算して、公開された DID と一致することを確認しました。
sha256("0x04ECc497632847529FC431bA780Ffc573Fe4aC47" + "11155111")
= 89e6023a8609bdfc1f28e99b65955683d7d4ddd07fc783de1549a9b8112befb1
→ did:op:89e6023a8609bdfc1f28e99b65955683d7d4ddd07fc783de1549a9b8112befb1
つまり DID は誰かが採番したものではなく、NFT のアドレスとチェーン ID から誰でも再計算できる値です。名前空間を管理する主体が要りません。
「NFT には JSON が要る」はどうなっているのか
NFT の基礎として、tokenURI が JSON を指し、その JSON に名前や画像が書いてある、という約束があります(ERC-721)。ふつうは JSON を IPFS や自社サーバに置き、その URL をチェーンに書きます。
Ocean の場合、JSON が2種類あって、置き場所も役割も違います。 ここが分かりにくいところでした。
(a) 標準の NFT 用 JSON — チェーンの中に埋まっている
tokenURI(1) を実際に読むと、URL ではなくこれが返ってきました。
data:application/json;base64,eyJuYW1lIjoiUFggRGF0YSBORlQiLCJzeW1ib2wiOiJQWC1ORlQi…
data: で始まる データ URI です。つまりどこにも置かれておらず、JSON そのものがチェーン上に埋め込まれています。外部サーバが消えても壊れません。デコードするとこうです。
{
"name": "PX Data NFT",
"symbol": "PX-NFT",
"description": "Data NFTs are unique digital assets that represent the intellectual property of your digital services.",
"external_url": "https://cliox.org/asset/did:op:89e6023a…befb1",
"background_color": "ffffff",
"image": "/images/cliox_text.svg"
}
注意すべきは、この JSON には資料の情報が一切入っていないことです。「歳旦発句牒」も国立国会図書館も出てきません。全資産で同じ定型文で、変わるのは external_url だけ。これはウォレットや NFT マーケットで表示するための顔であって、資産の中身ではありません。
(ついでに言うと image が /images/cliox_text.svg という相対パスです。チェーン上のデータ URI から相対パスを書いても解決先がないので、外部のウォレットでは画像が出ません。ポータル内でしか意味を持たない書き方です)
(b) Ocean の DDO — イベントログに入っている
資料の実際のメタデータ(題名・説明・ライセンス・サービス定義)は DDO のほうです。これは tokenURI とは無関係で、2本目の取引が出したイベント MetadataCreated の中に入っていました。
MetadataCreated
createdBy = 0xa60eF4E6E8F821F3bd5D42f8067BD5d4a96e0CEf
state = 0
decryptorUrl = http://16.192.66.21:8001
data = 0x04009ab5bfa68348330fb182c0e8a8eb85… (2,872 バイト・暗号化済み)
metaDataHash = 0xc717a9eb053d7b23db3da5b30a26ba4c57a19939e697fc52c10691b055d5d78b
つまり 「URI で外部を参照する」のではなく、暗号化した本体をチェーンに直接載せているわけです。私はここを勘違いしていました。
一方、契約の保管領域(getMetaData() で読める部分)に入っているのは、本体ではなくこれだけでした。
| 項目 | 値 |
|---|---|
| 復号してくれるノードの URL | http://16.192.66.21:8001 |
| 復号者のアドレス | (空) |
| 状態 | 0(有効) |
| メタデータを持っているか | true |
本体はイベントログに、目印だけが保管領域に、という分担です。これは節約のためです。EVM ではイベントログのほうが保管領域よりはるかに安く、契約自身はイベントを読み返せない代わりに、外部の索引プログラムなら読める。Ocean Node がまさにそれをやっています——イベントを拾い、decryptorUrl のノードに復号させ、検索できる形にする。
metaDataHash があるので、復号した結果が改竄されていないかを誰でも突き合わせられます。
利用者の資格は NFT ではない
「データセットが NFT なら、利用者の資格も NFT か」と考えたくなりますが、違います。Clio-X は2つの信頼の仕組みを併用しています。
| データセット・アルゴリズム | 参加者・サービスの資格 | |
|---|---|---|
| 仕組み | ブロックチェーン(Ocean / ERC-721) | 公開鍵基盤(PKI)(Gaia-X の Verifiable Credential) |
| 識別子 | did:op:…(NFT から計算) | did:web:…(ドメイン名) |
| 信頼の根拠 | チェーンの合意 | X.509 証明書の信頼チェーン |
| 費用 | ガス代がかかる | かからない |
| 記録の場所 | チェーン上 | 署名付き JSON 文書 |
ポータルの Verify 画面は、チェーンを一切触りません(実装にもウォレット・契約・トランザクションへの参照が一つもありません)。やっているのは、提示された Verifiable Presentation を Gaia-X の Compliance API に投げて、署名と発行者を検証することです。
「資産の来歴はチェーン、参加者の身元は証明書」という役割分担になっています。データスペースの議論で Web3 と Gaia-X が同時に出てくるのは、この2階建てのためです。
具体的に何が書き込まれるのか
2本目で送った 3,940 バイトの中身は、暗号化された DDOです。DDO は資産のメタデータ文書で、題名・説明・ライセンス・サービス定義などが入っています。
チェーン上に残るものと残らないものを分けると:
残るもの(誰でも読める)
- 公開者のアドレス(
0xa60e…0CEf)と、所有者であるという記録 - NFT・データトークン・蛇口の各アドレス
- 暗号化された DDO のかたまり(読めるが、復号はできない)
- 取引の日時・手数料
残るが、そのままでは読めないもの
- ファイルの URL。DDO の中で
filesとして、さらに別に暗号化されています
"files": "0x047de213de3c16611fc4b8cee0d7b3e1835d1d978ba87109faf318a66a17780149b47…"
そもそもチェーンに載らないもの
- データ本体。今回なら国立国会図書館の IIIF マニフェストそのもの。ファイルは元の場所に置いたままです
ここが Compute-to-Data の考え方の土台です。チェーンに載せるのは「誰が・何を・どういう条件で提供しているか」という約束事だけで、中身は動かしません。計算のほうをデータの場所へ持っていきます。
復号できるのは誰か
暗号化された DDO は、Ocean Node が鍵を持っています。カタログ表示のためにノードが復号し、検索できる形にします。一方でファイルの URL は、アクセストークンと引き換えた相手にだけ渡されます。
「メタデータは公開、URL は非公開」という二段構えです。実際、資産ページの説明文は誰でも読めますが、マニフェストの URL は画面のどこにも出ません。
学ぶうえで引っかかった点
- 「無料」でも無料ではない。価格を無償配布にしても、公開者のガス代は変わりません。無料なのは利用者から見た話です
- 取引が2本に分かれている理由。1本にまとめられそうに見えますが、間に「ノードに暗号化してもらう」というチェーン外の往復が挟まるため、分けざるを得ません
- チェーンは「書けたか」しか保証しない。書いた内容が正しいか、URL が生きているか、説明が実物と合っているかは、チェーンの保証外です。だから STEP 2 でノードが URL を実際に取りに行く検証が別に要ります
- 索引に載るのは別の仕組み。チェーンに書いた瞬間には検索できません。ノードがイベントを拾って初めてカタログに出ます。「取引は成功したのに資産ページが見つからない」のはこの時間差です
素の状態では通らなかった4点
ここからが本題かもしれません。ocean.js 3.1.3 と Ocean Node 3.2.0 の版ずれに、手元の索引環境の設定が重なり、何も手当てしないと STEP 2 から先に進めませんでした。4 点すべてが版ずれというわけではありません。
(1) キー名の大文字小文字
ocean.js は応答から fileinfo を探しますが、ノードは fileInfo で返します。見つからないと fetch すらせず null になり、画面には
Could not fetch file info. Is your network down?
とだけ出ます。ネットワーク障害に見えますが、通信は成功しています。
(2) File の「URL」タブが使えない
フォーム定義で URL タブは methods: false になっており、method を送りません。ところが Ocean Node 3.2.0 の fileInfo は method を必須とし、無いと
500 "Error validating the URL file: URL or method are missing"
を返します。method を選べる「API」タブなら、同じ URL がそのまま通ります。
(3) 承認済みベーストークンが空
手元の subgraph が新しいブロックからしか索引しておらず、承認済みトークンの一覧が空になっていました。結果 feeToken が空文字になり、ethers が弾いて 「No Token created.」。
恒久対応は subgraph を張り直すことです。
(4) DDO の暗号化に署名が付かず 401
ポータルはファイル URL の暗号化には自前の署名付き関数を持っているのに、DDO 本体は素の encrypt を呼んでいます。Ocean Node 3.2.0 は認証必須なので 401 になります。
おまけ: $ALGO は相対パス
アルゴリズムの実行時、entrypoint の $ALGO は data/transformations/algorithm(先頭スラッシュ無し) に置換されます。つまり コンテナの WORKDIR が / でないと解決できません。
nvidia/cuda は / なので動きますが、pytorch/pytorch は /workspace なので、イメージを差し替えた瞬間に
bash: data/transformations/algorithm: No such file or directory
で無言で失敗します。絶対パス bash /data/transformations/algorithm を指定すれば回避できます。
まとめ
- publish は「NFT を作り、暗号化したメタデータをその NFT に書き込む」こと。データ本体は載らない
- 登録にはお金がかかる。減るのは公開者の ETH(ガス代)で、実測 1件あたり 0.004753 ETH。価格を無償にしても変わらない
- データトークンは減るのではなく作られる。減るのは、あとで利用する側
- 6段のうち書き込みが起きるのは最後だけ。前半は入力を貯めているだけで、再読込で消える
- STEP 2 の Access Controller が、後の計算拠点を決める
- SaaS はチェーン上では型ではなく目印。Compute-to-Data の枠外
- そして 公式手順のままでは通らない。この4点は、いずれも「エラーではなく、静かに何も起きない」形で現れる
最後の点が一番厄介でした。「ネットワーク障害に見えるが通信は成功している」「トークンが作れないと言われるが原因は索引の開始ブロック」——症状と原因が離れているので、切り分けに時間がかかります。同じところで止まっている人の役に立てば幸いです。
コメント
…