geth consoleを使わずJavaScriptのみでブロックチェーン(Ethereum)を操作する方法

# この記事について
- ブロックチェーンのプラットフォームである、Ethereumへ接続し、送金したり、コントラクトコードを実行するためには、[こちら](https://www.ethereum.org/cli)の手順にある通り、gethと呼ばれるCLIツールをインストールして、操作することが一般的な手法として公開されています。
- しかし例えば、Ethereum上の個人アカウントで送金する機能を持ったWebアプリケーションを作成し、非エンジニア以外のユーザーに使ってもらうためには、gethのインストールを前提条件とすることは難しく、ブラウザを立ち上げるのみで、使えることが理想です。
- この記事では、上記のgethをインストールすることなく、JavaScriptのライブラリのみを用いて、Ethereumに接続し、送金などの操作ができるようにするための方法について説明します。
- この手順に従えば、gethを使うことなくブラウザのみで動作する、ブロックチェーンベースのWebアプリケーションの開発が可能です。
- さらに言えば、純粋にJavascriptのみで稼働するため、railsなどのサーバサイドのプログラミングも不要です。

# 手順

## Ethereum接続のためのJSON RPC Endpointの準備
- Ethereumに接続するために、HTTP(JSON RPC)を経由して、接続するためのEndpointを用意する必要があります。
- [infura](https://infura.io/)と呼ばれる、Ethereum接続のための JSON RPC Endpointを提供するホスティングサービスを利用することで、このEndpointを簡単に構築することができます。
- [こちら](https://infura.io/signup)の登録画面にて必要な情報を入力することで、以下の画面のように、EndpointのURLが発行されます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/64437/616bb58e-abb9-26f1-eff5-a02a2a58786a.png)

- 本番Ethereum接続用のMainNet　URLや、Ropstenなどのテスト用ネットワークなどのURLが表示されますが、今回は検証用なのでテスト用のURLを用いることにします。

## Ethereum Wallet (private key)の作成
- Ethereum Wallet file(private key)は、[ethereumjs-wallet](https://github.com/ethereumjs/ethereumjs-wallet)というJavaScriptライブラリを用いることで作成することができます。
- 以下のような簡単なコードで、Walletインスタンス作成し、privateキーを取得可能です。(上記ライブラリを `npm install` してください。)
- この記事では、 `wallet.getPrivateKeyString()` によって得られるprivate keyを用いて、署名付きトランザクションの処理を行います
- 実際のWebアプリケーションを作る際は、この発行されたprivate keyを一度だけ画面に表示させて、ユーザーが何かしらの手段で保存できるようにしておくと良いかと思います。
- またKey Fileを生成する際は、Passwordを設定する必要がありますが、こちらも画面上でユーザーがパスワードを設定できるようにし、その値を渡すと良いと思います。

```javascript

var Wallet = require('ethereumjs-wallet');

// Wallet オブジェクトの生成
const wallet = Wallet.generate();

// Walletからのprivate keyの取得
const privateKey = wallet.getPrivateKeyString();                                                                                                                                                                                                                                                               
console.log(privateKey)

//Walletのaddressを取得
const address = wallet.getAddress();     
console.log(address);

// keyfileのファイル名を取得
console.log(wallet.V3Filename());
// keyfileの内容を取得(任意のパスワードを設定)
console.log(toV3('password'));

```

## Private Keyを用いた署名付きトランザクションの実行 (送金処理)
- 上記で取得したprivate keyを用いることで、送金など署名が必要なトランザクションを実行させることができます。
- 　署名付きトランザクションを行うためには、[ethereumjs-tx](https://github.com/ethereumjs/ethereumjs-tx)というjsライブラリを用いる必要があります。
- 　また当然ながら、EthereumのJavascript APIである[web3.js](https://github.com/ethereum/web3.js/)のライブラリは必須です。

### 処理全体のソースコード
- 処理全体のソースコードは以下の通りとなっています。 (詳しい手順は後述します。)
- こちらのコードを実行することで送金処理が可能です。

```javascript
const Web3 = require('web3');                                                                                                                                                                                                                                                                                                 
const keythereum = require('keythereum');
const ethTx = require('ethereumjs-tx');

const web3 = new Web3();       
// infuraで取得した Ethereum JSON RPC EndpointのURLを設定する
web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/xxxxxxxxxxxxxxxx')); 

async function main() {
  // 送信元のアドレス (Walletの作成手順にあるwallet.getAddress()のメソッドによって得られたaddress)     
  const fromAddress = "0xXXXXXXXXXXXX";
  // 送信先のアドレス
  const toAddress = "0xZZZZZZZZZZZZ"
  
  // 著名付きトランザクションのnonce値として必要なため、送信元アドレスのTransaction countを取得する
  const count = await web3.eth.getTransactionCount(fromAddress);
  const countHex = `0x${count}`;  

  // 上記のWallet作成手順にある、wallet.getPrivateKeyString()によって得られた、Private keyの値を設定する
  const privateKey = <private key value>; 

  // transactionのパラメータの設定
  const txParams = {
    nonce: countHex, 
    // 適切なgasPriceとgasLimitを設定する
    gasPrice: '0x09184e72a000',     
    gasLimit: '0x30000',
    to: toAddress, 
    // 送金する金額
    value: '0x00'
  };
  // Transactionオブジェクトの生成
  const tx = new ethTx(txParams);
  // 秘密鍵での署名 
  tx.sign(privateKey);
　　　// Transactionオブジェクトをシリアライズして、16進数で表現
  const serializedTx = tx.serialize();
  const rawTx = '0x' + serializedTx.toString('hex'); 
  // 署名付きトランザクションの送信
  await web3.eth.sendSignedTransaction(rawTx);
}

main();
```

## 署名付きトランザクション処理の詳しい説明
- 上記の処理全体の流れについて、step by stepで流れを説明します。

### 必要なライブラリのインポート
- まずは以下の通り必要なライブラリをインポートします。

```javascript
const Web3 = require('web3');                                                                                                                                                                                                                                                                                                 
const keythereum = require('keythereum');
const ethTx = require('ethereumjs-tx');
```

### web3オブジェクトの初期化 (JSON RPC Endpointの設定)
- Web3インスタンスの生成と、JSON RPC EndPoint(HttpProvider)を設定します。
- Endpointには、infuraで取得したテスト用のEndpointを設定します。

```javascript
const web3 = new Web3();       
// infuraで取得した Ethereum JSON RPC EndpointのURLを設定する
web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/xxxxxxxxxxxxxxxx')); 
```

### 送信元アドレスのTransaction Countの取得
- 署名付きトランザクションを実行するための引数に必要となるため、送信元アドレスの現状のトランザクションID (Transaction count)を取得します
- Transaction Countは16進数 Stringにしておきます。

```javascript
const count = await web3.eth.getTransactionCount(fromAddress);
const countHex = `0x${count}`;
```

### Transactionパラメータの設定
- 署名付きトランザクションを実行するためのパラメータの設定をします。
- nonceには、上の手順で取得した、Transaction countの値を設定します。

```javascript

const txParams = {
  nonce: countHex, 
  // 適切なgasPriceとgasLimitを設定する
  gasPrice: '0x09184e72a000',     
  gasLimit: '0x30000',
  to: toAddress, 
  // 送金する金額
  value: '0x00'
};
```

### 署名付きトランザクションの実行
- さて、いよいよ全ての準備が揃ったので署名付きトランザクションを実施します。
- まず、 `ethTx` クラスのコンストラクタの引数に上述のトランザクションパラメータを設定し、ethTxオブジェクトの生成を行います
- 次に、 `tx.sign(privateKey)` メソッドによって、秘密鍵での署名を行います。
- その後、ethTxオブジェクトをシリアライズして16進数で表現します。
- 最後に、このシリアライズ化されたデータを用いて、 `web3.eth.sendSignedTransaction(rawTx)` をCallすると、署名付きのトランザクション処理を実行することができます。
- またこの手順では割愛しますが、送金処理だけでなく、dataという属性をトランザクションパラメータに設定することで、コントラクトコードを実行させることも可能です。

```javascript
  // Transactionオブジェクトの生成
  const tx = new ethTx(txParams);
  // 秘密鍵での署名 
  tx.sign(privateKey);
　　　// Transactionオブジェクトをシリアライズして、16進数で表現
  const serializedTx = tx.serialize();
  const rawTx = '0x' + serializedTx.toString('hex'); 
  // 署名付きトランザクションの送信
  await web3.eth.sendSignedTransaction(rawTx);
```

# 最後に
- 上述の手順に従うことによって、　gethコンソールをローカルで立ち上げることなく、JavaScriptだけで、Ethereum上の全てのトランザクション処理が実行可能になるため、ブラウザを立ち上げるだけで利用可能なブロックチェーンWebアプリケーションの構築が可能となります。
- gethをインストールすることが前提になってしまうと、一般ユーザーが利用可能なWebサービスとして世に広めるのは一気に敷居が高くなりますが、この手順に従えば、必要な動作環境はブラウザのみであり、GUIでの操作も可能になるため、ユーザーフレンドリーなサービスを作れるようになるかと思います。