Reality Keysと連携するiOSアプリをつくる 第4回 P2SHアドレス

f:id:yzono:20150223224712j:plain

はじめに

これまでに取得したキーを使ってP2SHアドレスを作ります。

目次

  • By My Coin Web版はどうしているか
  • iOSでどう実装するか
  • JSのデバッグ方法
  • P2SHアドレス作成のための4つのキー
  • P2SHアドレス作成

By My Coin Web版はどうしているか

詳細は上記記事に書きましたが、bitcore.jsのメソッドを呼び出しています。

function p2sh_address(data, include_user_keys) {

    if (include_user_keys == null) {
        include_user_keys = true;
    }

    var script = redeem_script(data);
    address_version = data['is_testnet'] ? 'testnet' : 'livenet';
    var addr = bitcore.Address.fromScript(script, address_version);
    return addr.toString();

}
function redeem_script(data) {

    include_user_keys = true;

    var yes_pubkeys = [ data['yes_user_pubkey'], data['yes_pubkey'] ];
    var no_pubkeys = [ data['no_user_pubkey'], data['no_pubkey'] ];
    var user_pubkeys = [ data['yes_user_pubkey'], data['no_user_pubkey'] ];

    // multisig group p2sh
    var opts = {
        nreq: include_user_keys ? [2,2,2] : [2,2],
        pubkeys: include_user_keys ? [ yes_pubkeys, no_pubkeys, user_pubkeys ] : [ yes_pubkeys, no_pubkeys ]
    };

    var address_version = data['is_testnet'] ? 'testnet' : 'livenet';
    var info = TransactionBuilder.infoForP2sh(opts, address_version);
    var p2shScript = info.scriptBufHex;
    return p2shScript;
}

iOSでどう実装するか

Mnemonic作成時と同様に、表示領域外にWebViewを置いてそこでJSを実行します。iOSからJSに以下データを渡します。

JSのデバッグ方法

iOSJavaScriptの連携が多いので以下デバッグ方法を知っておくと便利です。

app.js。console.logをオーバーライド

console = new Object();
console.log = function(log) {
    var iframe = document.createElement("IFRAME");
    iframe.setAttribute("src", "ios-log:" + log);
    document.documentElement.appendChild(iframe);
    iframe.parentNode.removeChild(iframe);
    iframe = null;
};
console.debug = console.log;
console.info = console.log;
console.warn = console.log;
console.error = console.log;

使い方。文字列"ios-log:"の場合のみ出力とかするとより便利。

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    println(request.URL.absoluteString)
    return true
}

P2SHアドレス作成のための4つのキー

(1)Mnemonicから生成したPublic Key(YESの場合のキー)

取得方法はこれです。

function pubkey_for_mnemonic(mnemonic) {
    var mne = new Mnemonic(mnemonic.split(' '));
    var seed = mne.toHex();

    var k = key_for_seed(seed);
    return k['pub'];
}
func webViewDidFinishLoad(webView: UIWebView) {
    let userDefaults = NSUserDefaults.standardUserDefaults()
    let mnemonic = userDefaults.stringForKey("mnemonic")
    println(mnemonic)
    
    let k = webView.stringByEvaluatingJavaScriptFromString("pubkey_for_mnemonic('\(mnemonic!)');")
    println(k)
}

(2)チャリティー先のPublic Key(固定)

とりあえず自分が持つ以下Pubkeyを設定。Blockchain.infoから「Show Public Key」で見れます。

03e251c3767f74a7c1ecbcf05878d029098f63c95f05cc1b7ff64363c049ed1c2f

(3) RK APIのレスポンスに含まれるキー

no_pubkey = "02c0b9fba37cfd406874d34a8b1ce133f9ff5b1915f9e27ec07dff12fefc7611ec"
yes_pubkey = "02a5d4a751923c4128332df96887e188c86418820c437b0891fa838cc4ad104a58"

P2SHアドレス作成

JavaScript

function p2sh_address(yes_user_pubkey, no_user_pubkey, yes_pubkey, no_pubkey) {
    
    var data = {
        'yes_user_pubkey': yes_user_pubkey,
        'no_user_pubkey': no_user_pubkey,
        'yes_pubkey': yes_pubkey,
        'no_pubkey': no_pubkey
    }
    
    var script = redeem_script(data);
    address_version = 'livenet';
    var addr = bitcore.Address.fromScript(script, address_version);
    return addr.toString();
}

function redeem_script(data) {
    include_user_keys = true;
        
    var yes_pubkeys = [ data['yes_user_pubkey'], data['yes_pubkey'] ];
    var no_pubkeys = [ data['no_user_pubkey'], data['no_pubkey'] ];
    var user_pubkeys = [ data['yes_user_pubkey'], data['no_user_pubkey'] ];
    
    // multisig group p2sh
    var opts = {
        nreq: include_user_keys ? [2,2,2] : [2,2],
        pubkeys: include_user_keys ? [ yes_pubkeys, no_pubkeys, user_pubkeys ] : [ yes_pubkeys, no_pubkeys ]
    };
    
    var address_version = 'livenet';
    var info = TransactionBuilder.infoForP2sh(opts, address_version);
    var p2shScript = info.scriptBufHex;
    return p2shScript;
}

Swift

func webViewDidFinishLoad(webView: UIWebView) {
    let userDefaults = NSUserDefaults.standardUserDefaults()
    let mnemonic = userDefaults.stringForKey("mnemonic")
    let k = webView.stringByEvaluatingJavaScriptFromString("pubkey_for_mnemonic('\(mnemonic!)');")
    let p2sh = webView.stringByEvaluatingJavaScriptFromString("p2sh_address('\(k!)','\(Constants.PublicKey.CharityPubKey)','\(contract.yes_pubkey)','\(contract.no_pubkey)');")
    
    label.text = "P2SHアドレス : " + p2sh!
}

Blockchain.infoで確認

アドレスのバリデーションがOKなのが分かります。

Blockchain.infoで確認

こんな感じ

f:id:yzono:20150223224607g:plain

まとめ

次回はclaimについてやります。claimはビットコインの難しいところの最後の処理です。

参考

UIWebViewのデバッグ効率を少しでもあげる方法(Log編)

Javascript console.log() in an iOS UIWebView