DataSpiderから参照系コントラクトを呼び出す

DataSpiderとブロックチェーン　その４
## DataSpiderからスマートコントラクトの呼び出し
スマートコントラクトを操作する場合、RESTfullAPIを利用するもの１つの選択肢です。
しかし、今回は、Tron Java ライブラリをできるだけ使用して実装を進めたいと思います。

## なにをするか
1\. TrunBoxに付属するMetaCoinのソースコードをデプロイします。
今回は、TrunBoxを使用しコマンドラインから手動でデプロイを行います。しかし、今後DAO連携も考えているため、プログラムから自動でデプロイする方法は、DAOアダプタを作成する場合に別途紹介します。

2\. MetaCoinのスマートコントラクトを呼び出します。
参照系のスマートコントラクトを呼び出すためのコードを紹介します。

## 開発環境の準備
[前回までの環境](https://qiita.com/dataspider-fan/items/1fa23384ec0ccfa31461#%E9%96%8B%E7%99%BA%E6%BA%96%E5%82%99)に加え、今回はBash環境が必要になります。
以下のいずれかをご利用のPCにセットアップします。
* Ubuntu 18.04
* MINGW
* Git BASH (※)
※ https://gitforwindows.org/

## MetaCoinの準備
以下の手順でセットアップを行います。
### TronBoxのインストール
DOSプロンプトを開き以下のコマンドを実行します。
```dosbatch
npm install -g tronbox
tronbox version
```

### MetaCoinのダウンロード
Shell環境を開き、以下のコマンドを実行します。
私は、Git BASHにて実行しました。
```dosbatch
mkdir MetaCoin
cd MetaCoin
tronbox unbox metacoin
```

### MetaCoinビルド時の定義ファイルの編集
tronbox.jsにコンパイルに必要な情報およびデプロイ時の定義、デプロイ先が定義されています。
今回は、NILE testnet（※）上にデプロイをします。

:::note info
TRONは、4種類の環境が想定されています。  
| 名称 | 概要|
|:-----------:|:------------|
| mainnet       | TRONネットワークの本番環境です。|
| shasta     | testnetです。1つ目のテスト環境です。|
| nile       | testnetです。2つ目のテスト環境です。**今回はこの環境にデプロイします。**|
| development         | Tron Quickstartを使用してローカルに構築された環境です。|

:::
スマートコントラクトをデプロイするため、以下の内容を修正します。

tronbox.jsをエディタで開き、以下の点を修正します。
デプロイするアカウントの秘密鍵を記載します。
**前回蛇口サイトで指定したTRONアドレスの秘密鍵を記載します。**
もしくは、.envファイルを作成し、その中に秘密鍵を記載します。
今回は、tronbox.jsに直接記載しています。なお、mainnetへデプロイする場合は、秘密鍵を公開しないように、.envに記載し.envを公開しないようにします。
```diff_java
const port = process.env.HOST_PORT || 9090

module.exports = {
  networks: {
    // ※ 一部割愛
    nile: {
-     privateKey: process.env.PRIVATE_KEY_NILE,
+     privateKey: 'b59e5dfbd74a50122277340d4d8642bc78370da396da4brfigie83wqa6b4bece',
      userFeePercentage: 100,
      feeLimit: 1000 * 1e6,
      fullHost: 'https://api.nileex.io',
      network_id: '3'
    },
    // ※ 一部割愛
  }
}
```
:::note warn
Windows環境をご利用のかたは、MetaCoinフォルダにある定義ファイル名を変更する必要があります。
DOSプロンプトからMetaCoinフォルダに移動し、以下のコマンドを実行します。
```
move tronbox.js tronbox-config.js
```
:::

### MetaCoinのコンパイルとビルド
DOSプロンプトを開き以下のコマンドによりMetaCoinをコンパイルします。
```dosbatch
REM コンパイル
tronbox compile
REM NILE testnet環境へデプロイ
tronbox migrate --reset --network nile
```
以下のメッセージが表示されればデプロイの完了です。
```
> tronbox migrate --reset --network nile
Using network 'nile'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  Migrations:
    (base58) TWq1RkADSQzz5ifieoAiGK19roQGk7LDo4
    (hex) 41e4cda6e6c5bbefkei9301jf3a521e8f8afa42da
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying ConvertLib...
  ConvertLib:
    (base58) TE2rFFQ5TXegGJmD596isDkw38VjhNPRea
    (hex) 412c90d75f06b3e88d60kfie2wf1496ded732197
  Linking ConvertLib to MetaCoin
  Deploying MetaCoin...
  MetaCoin:
    (base58) TTq6PiZee7XHiMUHEOC93IWALSrdXrHnLVbw
    (hex) 41c3e93049gjei1q3fieoakv913aa647eeabcf1e6d11
Saving successful migration to network...
Saving artifacts...
```
デプロイ時に表示された内容で、以下の緑色部分がスマートコントラクトにアクセスする際の重要な情報です。
別途メモに残しておきます。
```diff
  Linking ConvertLib to MetaCoin
  Deploying MetaCoin...
  MetaCoin:
+   (base58) TTq6PiZee7XHiMUHEOC93IWALSrdXrHnLVbw
    (hex) 41c3e93049gjei1q3fieoakv913aa647eeabcf1e6d11
Saving successful migration to network...
Saving artifacts...
```
以上で、MetaCoinの準備は完了しました。
次の章からDataSpiderを使用して、スマートコントラクトにアクセスするための実装をしていきます。

## MetaCoinのスマートコントラクトの関数呼び出し
Eclipseを開き、前回作成したHelloWorldにスマートコントラクトの関数をコールするための関数を記載し、取得した内容をDataSpiderの実行ログに出力する実装を行います。

### 実装概要
MetaCoinのスマートコントラクトにある、getBalance関数を呼び出します。
getBalanceにTRONアドレスを第一引数にわたすことにより、そのアドレスのMetaCoin残高を取得することができます。
MetaCoinは、デプロイしたアドレス宛に10000コインが発行されます。
その残高を取得し、DataSpiderの実行ログに表示します。
実装内容を以下に記します。

#### HelloWorldAdapterOperation.java
```java
package com.appresso.ds.dp.modules.adapter.helloworld;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.tron.trident.abi.FunctionReturnDecoder;
import org.tron.trident.abi.TypeReference;
import org.tron.trident.abi.datatypes.Address;
import org.tron.trident.abi.datatypes.Function;
import org.tron.trident.abi.datatypes.generated.Uint256;
import org.tron.trident.core.ApiWrapper;
import org.tron.trident.core.contract.Contract;
import org.tron.trident.core.key.KeyPair;
import org.tron.trident.proto.Response.TransactionExtention;
import org.tron.trident.utils.Numeric;

import com.appresso.ds.common.fw.LoggingContext;
import com.appresso.ds.dp.spi.Operation;
import com.appresso.ds.dp.spi.OperationContext;

public class HelloWorldAdapterOperation implements Operation {
	private final OperationContext context;

	public HelloWorldAdapterOperation(OperationContext context) {
		this.context = context;
	}

	@Override
	public Map execute(Map inputData) throws Exception {

		/*
		 * TRONアドレス生成
		 */
		KeyPair keyPairGenarate = KeyPair.generate();
		String publicAddress =keyPairGenarate.toBase58CheckAddress();
		String privateKey = keyPairGenarate.toPrivateKey();

		LoggingContext log = context.log();
		log.finest("*******************");
		log.info("** Tron address **");
		// 実行ログに生成したアドレスを表示する
		log.info("PUBLIC_ADDRESS : " + publicAddress);
		log.info("PTIVATE_KEY : " + privateKey);
		log.finest("*******************");


		/*
		 * スマートコントラクトの関数呼び出し（参照系）
		 */

        // NILE testnet wrapperの生成
        // アドレスの秘密鍵をofNileメソッドの引数に渡す
        ApiWrapper wrapper = ApiWrapper.ofNile("08b284c0e6122da673cdd9b5599699aabe5e6353412c1c72f37189a5790a4f86"); ///ofShasta()/ofNile()

        // MetaCoinをデプロイしたアドレスの秘密鍵をKeyPairメソッドに渡す
		KeyPair keyPair = new KeyPair("b59e5dfbd74a50122277340d4d8642bc78370da396da4bf9b33757cfa6b4bece");
        
        // MetaCoinの残高（balanceOf）を取得するアドレスを変数に格納する
		String ownerAddr = keyPair.toBase58CheckAddress();

        // 上記、MetaCoinのデプロイ後のスマートコントラクトアドレスを指定する
		String cntrAddr = "TTq6PiZee7XHiMUdcY5s4UXSrdXrHnLVbw";

		// getBalance関数の呼び出し
        Function balanceOf = new Function("getBalance",
                Arrays.asList(new Address(ownerAddr)), Arrays.asList(new TypeReference<Uint256>() {}));

        // getBalanceの取得結果を実行ログに表示
        TransactionExtention txnExt = wrapper.constantCall(ownerAddr, cntrAddr, balanceOf);
        String result = Numeric.toHexString(txnExt.getConstantResult(0).toByteArray());
        log.info("getBalance : " + FunctionReturnDecoder.decode(result, balanceOf.getOutputParameters()).get(0).getValue());


		return new HashMap();
	}

	@Override
	public void destroy() {
	}
}
```

:::note info
スマートコントラクを操作する関数をコールする際に、ほかの外部jarファイルが必要になります。
コールするTronの関数に必要となるファイルをローカルのgradleキャッシュディレクトリからDataSpiderのライブラリフォルダにコピーをします。
:::

### 実行結果
実行ログのgetBalanceにMetaCoinの残高が表示されたことが見て取れると思います。
![getBalance.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2849535/84a079be-02f4-b24f-5a9d-d8d283ebbf4d.png)

:::note info
上記ソースコードは、こちらに公開しています。
Github : [dataspider-fan/qiitacode](https://github.com/dataspider-fan/qiitacode/tree/main/HelloWorld)
参考にしていただければと思います。
:::

## 次回は
ここまでで、スマートコントラクトの参照系の関数の呼び出し方法が分かりました。
次回は、スマートコントラクトの更新系の関数呼び出し方法を紹介したいと思います。
更新系の呼び出しは、TRXが必要となるため蛇口サイトからTRXを取得しておきましょう。
**追記**
今後、更新系のスマートコントラクトの実装および検証を行いますが、さきだって[ローカル環境にTRONネットワークのサービスの構築](https://qiita.com/dataspider-fan/items/b8c7edf274c7099eb872)を紹介します。