DataSpiderとブロックチェーン その11
前回は、NFTとして登録するPDFデータの生成とPinataサービスへのPDFアップロードまでを行いました。
今回は、TRC-721スマートコントラクトの準備からTRC-721スマートコントラクトにPDF情報をNFTとして登録するまでの実装を行います。
今回も手順が多いので順をおって説明します。
やること
シナリオの❺ (※以前の記事で紹介しましたシナリオを掲載) で、NFT登録用のスマートコントラクト関数を呼び出す実装をします。
開発環境の準備から動作確認までの概要
-
ローカル環境のTRONサービスの起動
Dockerを立ち上げ、TRONサービスを起動します。以前の記事に投稿しているので参照ください。 -
TRC-721スマートコントラクト(MyFNTToken)のデプロイ
以前の記事に投稿しているので参照ください。ただし、今回デプロイするスマートコントラクトはNFT用のものとなります。 - TronLinkウォレットの設定
TRONサービス起動時のニーモニック情報を使用してウォレットをセットアップします。 - remixdのダウンロードとremixdサービスの起動
TronIDEを使用するための準備です。 - NFT登録アドレス(ユーザ)へのNFT登録権限の付与
特定のアドレス(ユーザ)のみNFTを登録できるようにします。 - TronIDE上でMyFNTTokenのソースコードのコンパイル
TronIDEでコンパイルし、各関数をTronIDEから呼び出せるようにします。 - 実装
アダプタに実装する予定のソースコードを抜粋して紹介します。 - 動作確認
TronIDEから参照系のスマートコントラクトを呼び出し、ブロックチェーン上の登録内容を確認します。
手順詳細
開発環境の準備から実装までを順をおって説明します。
ローカル環境のTRONサービスの起動
Dockerを立ち上げて、TRONサービスを起動します。
上記記事内でDockerを起動するときの"mnemonic=hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge"部分に welcome frozen trade sail tennis animal effort someone caution logic gift volume
を入力します。
(hogeの連続した文字列だと後続のTronLinkウォレット初期設定でエラーになるため)
上記で使用しているmnemonic文字列は、mainnet用ウォレットにインポートしないでください。Testnetもしくはローカル環境での検証用としてご利用ください。
TRC-721スマートコントラクトのデプロイ
ソースコードのダウンロード
実際にデプロイを行うためにソースコードのほかに必要なファイルを用意します。
こちらにデプロイするためのサンプルを作成しました。参考にご利用ください。
デプロイ
ローカル環境のTRONサービス上にデプロイします。
git clone https://github.com/dataspider-fan/TRC721-Contract.git
cd TRC721-Contract
npm install
上記からダウンロードしたtronbox-config.jsファイルを修正します。
tronbox-config.jsファイルを開き、デプロイするアカウントの秘密鍵'your key'部分に b17e3c406d673ec5592aaced8a3c099134b25d653f43252dd8845c5e3d816d6e
を記載します。
今回は、上記Dockerを起動した1つ目のアカウントをデプロイアカウントとします。
tronbox-config.js
:
:
fullHost: 'https://api.shasta.trongrid.io',
network_id: '2'
},
nile: {
privateKey: 'your key',
userFeePercentage: 100,
feeLimit: 1000 * 1e6,
fullHost: 'https://api.nileex.io',
solidityNode: 'https://api.nileex.io',
eventServer: 'https://api.nileex.io',
network_id: '*'
},
dev: {
// For tronbox/tre docker image
userFeePercentage: 100,
:
:
'your key'を修正したら以下のコマンドでソースコードをデプロイします。
tronbox migrate --network dev
デプロイ結果
デプロイ結果は以下です。
後続のオペレーションで、MyNTFTokenのアドレスTJoqUFqRyzXjYX8X9agahqa5ZREqKpSWLB
を使用します。
tronbox migrate --reset --network dev
Using network 'dev'.
Running migration: 1_initial_migration.js
Deploying Migrations...
Migrations:
(base58) TRSL8syn1xWzZjq9ezxguKScPEdEaocTYZ
(hex) 41a9ab12d6cd07fe76a11bfe41e996acf45ac7f56a
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying MyNFTToken...
MyNFTToken:
(base58) TJoqUFqRyzXjYX8X9agahqa5ZREqKpSWLB
(hex) 4160f36a47fa5766fd310a92b3ce1e0a074025f9a8
Saving successful migration to network...
Saving artifacts...
TronLinkウォレットの設定
TronLinkウォレットのインストールとアドレスの登録(ニーモニックのインポート)、ローカル環境のTRONノードを登録します。
TronLinkウォレットのセットアップ
-
ChromeブラウザからChromeウェブストアを開きます。
Chromeに追加 ボタンを押します。
ライブラリがダウンロードされインストールされます。
https://chrome.google.com/webstore/detail/tronlink/ibnejdfjmmkpcnlpebklmnkoeoihofec/related
-
画面右側の ImportWallet (青ボタン)をクリックします。
-
ニーモニックを入力します。
Tronサービスを起動したときのニーモニックを入力します。
Dockerを起動したときの"mnemonic=welcome frozen trade sail tennis animal effort someone caution logic gift volume"のwelcome frozen trade sail tennis animal effort someone caution logic gift volume
を以下のテキストボックスに入力して、 Next ボタンをクリックします。
-
画面下部にパスワード欄が表示されますので、パスワードを入力します。
ここで入力したパスワードは、TronLinkウォレット起動時に求められるログインパスワードになります。
Import Mnemonic Phrase ボタンをクリックします。
-
アドレスが1つ表示されます。
ここで表示されたアドレスと、Dockerを起動時の1つ目のアドレスが一致していることを確認します。
Confirmボタンをクリックしてウォレットのアドレスの登録作業は完了です。
TronLinkにローカル環境のTRONノードの追加
- TronLink画面からノードを登録します。TronLinkの歯車ボタンをクリックします。
-
Nodeメニュをクリックします。
- AddNodeボタンをクリックします。
- 設定名称とローカル環境のURLを入力します。入力後、Add custom nodeボタンをクリックします。
Full nodeおよびEvent serverにはhttp://127.0.0.1:9090
を指定します。
- Node一覧画面に戻りますので、画面をスクロールしPrivateNetのチェックボックスをONにします。
- TronLinkのトップ画面に戻り、上部のリストボックスからPrivateNet(上記で入力したNode name部分)を選択します。
残高欄にDocker起動時に指定した数値が表示されれば設定は完了です。
remixdのダウンロードとremixdサービスの起動
デプロイしたスマートコントラクトの初期設定をするため、TronIDEを使用します。
ブラウザ版のTronIDEからローカル環境にアクセスするためremixdサービスが必要となります。
- remixdのダウンロードとremixdサービスの起動
npm install -g @remix-project/remixd
remixd -s <上記にてCloneしたTRC721-Contractまでのフルパスを指定> -u https://www.tronide.io/#optimize=false&runs=200&evmVersion=null&version=soljson_v0.8.6+commit.0e36fba.js
上記より、TronIDE(ブラウザ)を使用してローカルのソースコードにアクセスができるようになります。
起動結果
> remixd -s C:\MyToken\TRC721-Contract -u https://www.tronide.io/#optimize=false&runs=200&evmVersion=null&version=soljson_v0.8.6+commit.0e36fba.js
[INFO] you are using the latest version 0.6.10
[WARN] You are using IDE from an unsupported origin.
Check https://gist.github.com/EthereumRemix/091ccc57986452bbb33f57abfb13d173 for list of all supported origins.
[WARN] You may now only use IDE at https://www.tronide.io/#optimize=false to connect to that instance
[WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.
[WARN] Symbolic links are not forwarded to Remix IDE
[INFO] Sat Jan 01 8888 13:18:00 GMT+0900 (GMT+09:00) remixd is listening on 127.0.0.1:65520
[INFO] Sat Jan 01 8888 13:18:00 GMT+0900 (GMT+09:00) slither is listening on 127.0.0.1:65523
- TronIDEを開きます。TronLinkを接続するダイアログが表示されます。Connectボタンをクリックします。
- IDEのトップ画面の左側からローカル環境のワークスペースに接続します。
connect to localをクリックします。
-
Connectボタンをクリックします。
- IDEのトップ画面に戻り、remixd起動時の引数に指定したスマートコントラクトのパス下のファイル群が表示されれば起動の完了です。
NFT登録アドレス(ユーザ)へのNFT登録権限の付与
Tron IDEを使用して、ローカルにデプロイしたスマートコントラクトの関数(addMinter)を呼び出します。
ここで呼び出す関数は、NFTを登録できるアドレス(ユーザ)を登録するというものです。
だれでもNFTを登録ができると運用上よろしくないということで、TRC-721スマートコントラクトの仕様上、NFTを登録できるアカウントを限定するという目的で以下の設定が必要となります。
- IDE上で使用するスマートコントラクトおよびそのアドレス(ユーザ)を指定します。
IDE画面左側メニューからダイヤ(※)アイコンをクリックし、ENVERONMENTからInjected TronWebを選択します。
※ ほぼイーサリアムのロゴマーク - TronIDEで切り替え後、IDE上のアドレスとTronLink上のアドレスが一致していることを確認します。
IDE上でMyFNTTokenのソースコードのコンパイル
上記よりCloneしたサンプルコードのMyNFTToken.solを開き、ビルドツールのバージョンを指定しコンパイルします。
- IDEのトップ画面からMyNFTToken.solを開きます。
- コンパイラのバージョンを指定しコンパイルします。
上記からcloneしたサンプルコードは、SolidityのVer0.5.14を想定しています。IDE上でも同様のパージョンを指定します。
コンパイラのバージョンの確認
solcのvalue部分がSolidityのVer0.5.14です。
tronbox-config.js
dev: {
// For tronbox/tre docker image
userFeePercentage: 100,
privateKey: 'b17e3c406d673ec5592aaced8a3c099134b25d653f43252dd8845c5e3d816d6e',
userFeePercentage: 0,
feeLimit: 1000 * 1e6,
fullHost: 'http://127.0.0.1:' + port,
network_id: '1337'
},
compilers: {
solc: {
version: '0.5.14'
}
}
3. 選択すると自動的にビルドが開始されます。以下のチェックマークが表示されればコンパイルは完了です。
自動的にコンパイルされない場合は、LANGUAGEにsolidityが、さらに、Auto compileにチェックがONであることを確認します。
IDE上でNFT登録者アドレスを登録します。
- IDEの左側メニューのダイヤアイコンをクリックします。
CONTRACTにMyNFTTokenのソースコードMyNFTToken.sol
を指定します。
At addressに上記手順でコンパイルした結果のMyNFTTokenアドレスTJoqUFqRyzXjYX8X9agahqa5ZREqKpSWLB
を入力します。
-
At Addressボタンをクリックすると、その下に関数一覧が表示されます。
- 関数一覧からaddMinter欄にNFTが登録できるユーザのアドレスを入力し、addMinterボタンをクリックします。
ここで登録するアドレスは、2つ目のアドレスにします。TCpB9Ei8dUY6vdxB5RNPJzTCuEjWGkCy5u
を入力します。
- addMinterボタンをクリック後、TronLinkポップアップが表示されます。Signボタンをクリックします。
- 関数呼び出し後メッセージが表示されたら登録の完了です。
ここまでで開発準備は完了です。
実装
NFT登録処理の実装を行います。
前提
- NFT登録時のアドレス(発行する側)は上記手順でNFT登録ユーザとして指定(addMinterの第一引数のアドレス)したアドレスを使用します。
- ブロックチェーンにNFTとして埋め込む情報は、当該NFTの所有者(ローカル環境起動時の3つ目のアドレス)、TokenID、IPFSサービスに登録したJSONファイルのHASH値です。
(補足)NFTの情報
- PDFファイルアドレス:
https://gateway.pinata.cloud/ipfs/QmNWNQSyTq2WiPNT72RwjFA3QPvTTBFKD2meUqEnjHa4Pp - IPFSサービスに登録したJSONファイルのHASH値(PDFJSONファイルのアドレス):
https://gateway.pinata.cloud/ipfs/QmNoLMwaZ2zVTHfmQ3VwvdbPBnmUxcWn5c8BxoS9XAb6wg
NFT登録までの処理概要
ソースコード
// NFT登録者アドレスの秘密鍵
// ローカル環境サービスの起動時の2つ目のアドレスの秘密鍵です
// (adMinter関数にて登録したアドレスの秘密鍵)
String pivateKey = "528cfbef25ecb1fdddf0f78c61a557f58342635f5ee785cb64974f2d5420e6cb";
ApiWrapper wrapper_local = new ApiWrapper("localhost:50051", "localhost:50052", pivateKey);
KeyPair keyPair_local = new KeyPair(pivateKey);
String nftAddHasRole = keyPair_local.toBase58CheckAddress();
// MyNFT Token スマートコントラクトアドレス
String cntrAddr_local = "TJoqUFqRyzXjYX8X9agahqa5ZREqKpSWLB";
// 後続の処理でエネルギーは再計算する
long limitForFee = 1000;
/*
* JSONファイルのIPFSを指定 IPFS登録後返却されたHash値と
* PinataサービスのURLを連結してブロックチェーンに書き込みます。
*/
// Pinataサービスから返却されえたJSONデータのHash値
String addUri = "https://gateway.pinata.cloud/ipfs/QmPdMmXpKUAmX6cEwMSY8JM64NVVnHCfMK45x7AUsgquxX";
// NFTの受取者の指定 ローカル環境サービスの起動時の3つ目のアドレスにNFTを発行します。
String destAddr = "TQJxiM1FZyBRPpQvLyBaV984BvwwGbnhwj ";
/*
* NFT数を取得
* ここで取得した数+1をNFT登録時のTokenIDにします
*/
Function function = new Function("totalSupply", Arrays.asList(), Arrays.asList(new TypeReference<Uint256>() {}));
TransactionExtention txnExt_local = wrapper_local.constantCall(nftAddHasRole, cntrAddr_local, function);
String result_local = Numeric.toHexString(txnExt_local.getConstantResult(0).toByteArray());
log.debug("totalSupply : " + FunctionReturnDecoder.decode(result_local, function.getOutputParameters()).get(0).getValue());
// 登録するNFT IDの決定
Object totalSupply = FunctionReturnDecoder.decode(result_local, function.getOutputParameters()).get(0).getValue();
Long myIndex = Long.parseLong(String.valueOf(totalSupply));
myIndex = myIndex + 1;
/*
* NFT登録関数のオブジェクト生成
*/
function = new Function("mintWithTokenURI",
Arrays.asList(
new Address(destAddr),
new Uint256(BigInteger.valueOf(Long.parseLong(String.valueOf(myIndex)))),
new Utf8String(addUri)
),
Arrays.asList(new TypeReference<Uint256>() {}));
/*
* CPUエネルギー見積もり
* 更新系スマートコントラクト関数を呼び出すため、エネルギー量(ガス代)を算出します
*/
TransactionExtention txnExtEstimate = wrapper_local.constantCall(nftAddHasRole, cntrAddr_local, function);
ChainParameters chainparams;
long eg = 0;
try {
chainparams = wrapper_local.getChainParameters();
eg = chainparams.getChainParameter(11).getValue(); // TODO not found this getter.
} catch (IllegalException e) {
e.printStackTrace();
}
limitForFee = (long)txnExtEstimate.getEnergyUsed() * eg;
log.debug("エネルギー見積もり : " + txnExtEstimate.getEnergyUsed());
/*
* トランザクションデータへのサイン
*/
TransactionBuilder builder = wrapper_local.triggerCall(nftAddHasRole, cntrAddr_local, function);
builder.setFeeLimit(limitForFee);
Transaction signedTxn = wrapper_local.signTransaction(builder.build());
/*
* 登録処理 ブロードキャスト
*/
String result = wrapper_local.broadcastTransaction(signedTxn);
log.debug("transactionHash : " + result);
result_local = Numeric.toHexString(txnExt_local.getConstantResult(0).toByteArray());
log.debug("mintWithTokenURI : " + FunctionReturnDecoder.decode(result_local, function.getOutputParameters()).get(0).getValue());
登録内容の確認
TronIDEを使用して、参照系のスマートコントラクト関数をコールします。
ここまでで1件NFT情報がブロックチェーンに書き込まれています。
NFTスマートコントラクトに用意されている参照系の関数をTronIDEを介して呼び出し、その結果を確認します。
PDF保持している利用者のアドレスを指定したTokenIDの取得
- TronIDEの左側メニューを下にスクロールすると、tokenOfOwnerByIndex関数があります。
tokenOfOwnerByIndex関数に以下の引数を指定し、callボタンをクリックします。
uint256 : 1 がTokenIDです。
- つづいてTokenIDに紐づく登録されたURLを確認します。
TronIDEの左側メニューをさらに下にスクロールすると、tokenURI関数があります。
tokenURI関数に以下の引数を指定し、callボタンをクリックします。
string : https://gateway.pinata.cloud/ipfs/QmPdMmXpKUAmX6cEwMSY8JM64NVVnHCfMK45x7AUsgquxX が表示されます。
ソースコード内で指定した、JSONデータのURIが登録されていることが確認できます。
登録内容の確認は以上です。
次回は
NFT連携の掲載は以上です。
ここまで、PDF発行からIPFSサービスへの登録、PDF情報のブロックチェーンへの書き込みについて紹介してきました。DataSpiderSDKを使用して、DPFをNFTとしてブロックチェーン上にのせるというやりたいこと観点で実装してきました。
次回は、DataSpiderSDKが提供する各機能を使用して、データ連携パッケージアプリケーションソフトウェアとしてのスマートコントラクトアダプタを作成していきます。