読者です 読者をやめる 読者になる 読者になる

Counterwallet ビットコイン送金時の処理の流れ

f:id:yzono:20140416102029j:plain

はじめに

以前、12-word passphrase作成〜ビットコインアドレスの残高表示までのソースコードを見ましたが、今回はビットコイン送金処理の流れを見てみます。

目次

  • MVVMライブラリKnockout.js
  • Counterwalletのデータモデル
  • プルダウンから"Send"を選択
  • 送金ボタンクリック

MVVMライブラリKnockout.js

CounterwalletはMV系フレームワークとしてKnockout.jsを採用しています。データモデルが変更される度に、UIの関連付けられた部分を更新します。参考サイトは多数ありますが、以下書籍はさらっと読めて初めての人には良いと思います。

Knockout.js: Building Dynamic Client-Side Web Applications

Knockout.js: Building Dynamic Client-Side Web Applications

Counterwalletのデータモデル

ログイン時にpages.init.js内のinitIndex()が呼ばれ、WalletViewModel初期化に伴い、紐づくアドレス(AddressViewModel)とアセット(AssetViewModel)がバインドされます。

// index.html
<script src="js/pages.init.js"></script>
// pages.init.js
function initIndex() { //main page
  window.WALLET = new WalletViewModel();

プルダウンから"Send"を選択

アセット毎にAssetViewModelがバインドされており、"Send"プルダウンをクリックすると紐づくsendメソッドが呼ばれます。SEND_MODALはSendModalViewModel(id="sendModal")と紐付いています。ViewModelは大文字の変数名にするルールにしている.. と思います。

// balances.html
<li><a data-bind="visible: !$parent.IS_WATCH_ONLY, click: send, locale: 'send'" href="#"></a></li>
// asset.js
self.send = function () {
  if(self.availableBalance()<=0) { 
    bootbox.alert(i18n.t("not_available_asset_to_send", self.ASSET, getAddressLabel(self.ADDRESS))); 
    return; 
  }
  if(!WALLET.canDoTransaction(self.ADDRESS)) return false;
  SEND_MODAL.show(self.ADDRESS, self.ASSET, self.rawAvailableBalance(), self.DIVISIBLE); 
};
// balances.html
<div data-bind="showModal: shown, validationOptions: { insertMessages: false }" id="sendModal" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-labelledby="sendModal" aria-hidden="true">
..
<button type="button" data-bind="click: submitForm, locale: 'send'" class="btn btn-primary"></button>
..
</div>

送金ボタンクリック

送金アドレスと金額を入力した後、送金ボタンクリック

// balances.js
function SendModalViewModel() {

  self.submitForm = function() {
    if (!self.validationModel.isValid()) {
      self.validationModel.errors.showAllMessages();
      return false;
    }    
    //data entry is valid...submit to the server
    $('#sendModal form').submit();
  }
// balances.html
<form class="smart-form" data-bind="submit: doAction"><fieldset>

create_send API呼び出し

SendModalViewModelからWalletViewModelのトランザクション送信処理を呼び出す。WalletViewModelのdoTransactionメソッドで、"create_send"リクエスト、tx_sign、ブロードキャストを実行する。

// balances.js
function SendModalViewModel() {

  self.doAction = function() {
    WALLET.doTransaction(self.address(), "create_send",
      { source: self.address(),
        destination: self.destAddress(),
        quantity: denormalizeQuantity(parseFloat(self.quantity()), self.divisible()),
        asset: self.asset(),
        _divisible: self.divisible()
      },
      function(txHash, data, endpoint, addressType, armoryUTx) {
        var message = "<b>" + (armoryUTx ? i18n.t("will_be_sent") : i18n.t("were_sent")) + " </b>";
        WALLET.showTransactionCompleteDialog(message + " " + i18n.t(ACTION_PENDING_NOTICE), message, armoryUTx);
      }
    );
    self.shown(false);
    trackEvent('Balances', 'Send', self.asset()); // Google Analytics
  }
// wallet.js
self.doTransaction = function(address, action, data, onSuccess, onError) {

まとめ

次回はCounterwalletが使用しているフロントエンド用パッケージ管理ツール"Bower"について書きます。

参考

Knockout日本語ドキュメント

angular・backbone・knockoutの比較/印象まとめ

MVVMフレームワーク「Knockout.js」が超絶便利!!その概要と使いどころなどについて