EthereumでHDウォレットを実装できるtruffle-hdwallet-providerの仕組みについて




truffle-hdwallet-providerとは

truffle-hdwallet-provider を簡単に説明するとmnemonic(ニーモニック)からウォレットを作成し、そのウォレットのアカウントを使ってプログラム上から簡単にトランザクションを発行できる仕組みです。ソースコードもわずか69行とものすごく短いので1個ずつ説明していきたいと思います。

mnemonicとは1~24個のランダムな単語のことを指します。MetaMaskのウォレットではmnemonicから秘密鍵を作る仕組みがあり、MetaMaskを削除してしまってもmnemonicさえあれば全てを復元できます。この仕組みはMetaMaskだけでなく様々なウォレットで使われているので仕組みを把握しておくといいと思います。

ソースコード

var bip39 = require("bip39");
var hdkey = require('ethereumjs-wallet/hdkey');
var ProviderEngine = require("web3-provider-engine");
var FiltersSubprovider = require('web3-provider-engine/subproviders/filters.js');
var HookedSubprovider = require('web3-provider-engine/subproviders/hooked-wallet.js');
var Web3Subprovider = require("web3-provider-engine/subproviders/web3.js");
var Web3 = require("web3");
var Transaction = require('ethereumjs-tx');

function HDWalletProvider(mnemonic, provider_url, address_index=0, num_addresses=1) {
  this.mnemonic = mnemonic;
  this.hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(mnemonic));
  this.wallet_hdpath = "m/44'/60'/0'/0/";
  this.wallets = {};
  this.addresses = [];

  for (let i = address_index; i < address_index + num_addresses; i++){
    var wallet = this.hdwallet.derivePath(this.wallet_hdpath + i).getWallet();
    var addr = '0x' + wallet.getAddress().toString('hex');
    this.addresses.push(addr);
    this.wallets[addr] = wallet;
  }

  const tmp_accounts = this.addresses;
  const tmp_wallets = this.wallets;

  this.engine = new ProviderEngine();
  this.engine.addProvider(new HookedSubprovider({
    getAccounts: function(cb) { cb(null, tmp_accounts) },
    getPrivateKey: function(address, cb) {
      if (!tmp_wallets[address]) { return cb('Account not found'); }
      else { cb(null, tmp_wallets[address].getPrivateKey().toString('hex')); }
    },
    signTransaction: function(txParams, cb) {
      let pkey;
      if (tmp_wallets[txParams.from]) { pkey = tmp_wallets[txParams.from].getPrivateKey(); }
      else { cb('Account not found'); }
      var tx = new Transaction(txParams);
      tx.sign(pkey);
      var rawTx = '0x' + tx.serialize().toString('hex');
      cb(null, rawTx);
    }
  }));
  this.engine.addProvider(new FiltersSubprovider());
  this.engine.addProvider(new Web3Subprovider(new Web3.providers.HttpProvider(provider_url)));
  this.engine.start(); // Required by the provider engine.
};

HDWalletProvider.prototype.sendAsync = function() {
  this.engine.sendAsync.apply(this.engine, arguments);
};

HDWalletProvider.prototype.send = function() {
  return this.engine.send.apply(this.engine, arguments);
};

// returns the address of the given address_index, first checking the cache
HDWalletProvider.prototype.getAddress = function(idx) {
  console.log('getting addresses', this.addresses[0], idx)
  if (!idx) { return this.addresses[0]; }
  else { return this.addresses[idx]; }
}

// returns the addresses cache
HDWalletProvider.prototype.getAddresses = function() {
  return this.addresses;
}

module.exports = HDWalletProvider;

使われているモジュール

主に下記モジュールがtruffle-hdwallet-providerで使われています。特にbip39とethereumjs-walletは重要な役割を担っているので理解しとくといいと思います。

bip39

Bitcoin Improvement Proposal 39をJavascriptで実装したものです。これは決定性キーを生成するプログラムです。

ethereumjs-wallet/hdkey

Bitcoin Improvement Proposal 32をJavascriptで実装したもので階層的決定性ウォレット(Hierarchical Deterministic Wallets:HD Wallets)を作成するプログラムです。

truffle-hdwallet-provider内ではbip39を使ってmnemonicからシードを作成し、そのシードから鍵を生成するHD Walletsインスタンスを作成しています。このインスタンスから秘密鍵やアドレスを生成できます。

web3-provider-engine

Web3 ProviderEngineは独自のweb3プロバイダを作成するためのツールです。

web3

EtherumブロックチェーンとJSON RPC経由でデータの読み書きができるライブラリです。

ソースコード解説

12行目でmnemonicからHD Walletsを作成しています。作成方法はbip39モジュールを使用してmnemonicからシードを作成し、ethereumjs-wallet/hdkeyを使ってシードからHD Walletsを作るという手順になっています。

engineはweb3-provider-engineから生成されています。engine.addProvider()の引数にweb3を使って任意の接続先のネットワークを指定できるようになっています。

HDWalletProviderにはsend、sendAsync、getAddress、getAddressesが追加されていますがこれがどのタイミングで実行されているかちゃんと追えてないです。たぶん、Truffleのmigrate時にこれらの関数が呼ばれていると思います。

まとめ

使っているモジュールは把握できましたが、まだまだソースコードの中身や語句の理解が足りず理解が浅いです。少しずつ理解できてる範囲は広がってきているので今後追記していきたいと思います。

おすすめ書籍

Ethereumを使ったDApps開発を学びたいなら今だとこの1冊が1番良いです!開発環境の構築から使うべきツール、フレームワーク、実装方法・注意点まで網羅的に解説されている書籍なのでおすすめです。出版も2018年1月ということでかなり新しい本で、DMM Bitcoinを作っているネクストカレンシー所属の方が書いているので信頼できます。

ビットコインとブロックチェーンの詳細をしっかりと学びたい方にはこちらの書籍が非常におすすめです。ウォレットの仕組み、楕円曲線暗号、P2Pプロトコル、公開鍵暗号などビットコインを支える技術について詳細に解説されています。また、サンプルコードを通して実際に手を動かして学べるので非常に濃い内容となっています。

The following two tabs change content below.

髙妻智一

2013年CyberAgent新卒入社 スマホゲームを作る子会社に所属し、サーバーサイドのエンジニアを担当。2年目の終わりから新規子会社の立ち上げに参加し、サーバーサイドのエンジニアリーダーとしてサービースのリリースから運用までを担当。 2018年仮想通貨のスマホウォレットを提供するGinco Incにブロックチェーンエンジニアとして入社。






よく読まれている関連記事はこちら




1 個のコメント

  • ブロックチェーンに詳しい方はきっと我々が実現できないものを探っているからすごいですね。Ethascanでいろいろアドレスを見ていると左上のアドレスと書いておらず、コントラクトと書かれているものがあるのに気が付きました。コントラクトクリエイターの欄に別のアドレスが書かれている場合、そちらが親のアドレスになり、その下の階層で作られた別のアドレスという意味なのでしょうか?たぶんスマートコントラクトの基本がわかっていない者に説明するのも至難の業かとは思いますが、、、

  • コメントを残す

    メールアドレスが公開されることはありません。 が付いている欄は必須項目です