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

Angular, Blockchain, Science とか

Angular, Blockchain, Science全般 の情報を主に書いていきます。

pybitcointools を使った鍵操作 Bitcoin

pybitcointoolsについては、

github.com

で見てください。ちなみにブテリンはEthereumの創業者です。

import pybitcointools as bitcoin # learn more: https://python.org/pypi/pybitcointools

# 秘密鍵を作成
valid_private_key = False
while not valid_private_key:
    private_key = bitcoin.random_key()
    decoded_private_key = bitcoin.decode_privkey(private_key, 'hex')
    valid_private_key = 0 < decoded_private_key < bitcoin.N

# 秘密鍵を表示    
print "Private Key (hex) is: ", private_key
print "Private Key (decimal) is: ", decoded_private_key

# Wallet Import Format (Base58形式) での表示
wif_encoded_private_key = bitcoin.encode_privkey(decoded_private_key, 'wif')
print "Private Key (WIF) is: ", wif_encoded_private_key

compressd_private_key = private_key + '01'
print "Private Key Compressed (hex) is: ", compressd_private_key

# 圧縮 WIF
wif_compressed_private_key = bitcoin.encode_privkey(
    bitcoin.decode_privkey(compressd_private_key, 'hex'), 'wif')
print "Private Key (WIF-Compressed) is: ", wif_compressed_private_key

# 公開鍵を求める
public_key = bitcoin.fast_multiply(bitcoin.G, decoded_private_key)
print "Public Key (hex) is: ", public_key

hex_encoded_public_key = bitcoin.encode_pubkey(public_key, 'hex')
print "Public Key (hex) is: ", hex_encoded_public_key

# 圧縮公開鍵
(public_key_x, public_key_y) = public_key
if(public_key_y % 2) == 0:
    compressed_prefix = '02'
else:
    compressed_prefix = '03'
hex_compressed_public_key = compressed_prefix + bitcoin.encode(public_key_x, 16)
print "Compressed Public Key (hex) is: ", hex_compressed_public_key

# ビットコインアドレスの表示
print "Bitcoin Address (b58check) is:", bitcoin.pubkey_to_address(public_key)

# 圧縮ビットコインアドレスの表示
print "Compressed Bitcoin Address (Base58Check) is :", \
    bitcoin.pubkey_to_address(hex_compressed_public_key)

C++ 計算機のサンプル

ただの計算機。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

class Calculator{
    public:
        void Run();
    private:
        bool Input();
        bool Calculate();
        void ShowResult() const;
        
        int m_a, m_b;
        char m_op;
        int m_result;
};

void Calculator::Run(){
    while(Input()){
        if(Calculate()){
            ShowResult();
        }
    }
}

bool Calculator::Input() {
    istringstream isstr;
    
    while(true) {
        string line;
        
        cout << "数式を入力してください > " << flush;
        getline(cin, line);
        if(cin.fail() || line.empty()) {
            return false;
        }
        
        isstr.clear();
        isstr.str(line);
        isstr >> m_a >> m_op >> m_b;
        if(isstr.fail()){
            continue;
        }
        
        isstr >> line;
        if(isstr.fail()){
            break;
        }
    }
    
    return true;
}

bool Calculator::Calculate() {
    switch(m_op) {
        case '+': m_result = m_a + m_b; break;
        case '-': m_result = m_a - m_b; break;
        case '*': m_result = m_a * m_b; break;
        case '/':
            if(m_b==0){
                cerr << "0では割れません。" << endl;
                return false;
            }
            m_result = m_a / m_b;
            break;
        default:
            cerr << "不正な演算子です。" << endl;
            return false;
    }
    return true;
}

void Calculator::ShowResult() const {
    cout << m_result << endl;
}

int main()
{
    Calculator calc;
    calc.Run();
}

C++ テンプレート

C++ のテンプレートの基礎。

template として T のところに、 int, double, string などなどいろいろな型として使えます。

#include <iostream>
#include <string>
using namespace std;

template <typename T>
void FillArray(T* array, size_t size, T value)
{
    for(size_t i = 0; i < size; ++i){
        array[i] = value;
    }
}

template <typename T>
void ShowArray(const T* array, size_t size)
{
    for(size_t i = 0; i < size; ++i){
        cout << array[i] << endl;
    }
}

int main()
{
    const int SIZE = 3;
    string str[SIZE];
    
    FillArray<string>(str, SIZE, "Template sample");
    ShowArray(str, SIZE);
}

ビットコイン difficulty target と retargeting 

difficulty target は係数部/指数部形式で表す。

指数部(exponent),係数部(coefficient)で

target = coefficient * 2^(8 * (exponent - 3))

^はXORです。

またDifficultyはブロックの生成期間を10分に保つように動的に変化します。

Difficultyは2016ブロックごとにretargetされます。

ActualTimespan は 最後の2016ブロックが生成されるのにかかった時間です。

式にすると

New Difficulty = Old Difficulty * (Actual Time of Last 2016 Blocks / 2016 minutes)

ソースコードは

unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
    if (params.fPowNoRetargeting)
        return pindexLast->nBits;

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
    
    // difficultyが動きすぎないように、もし調整が 4倍 or 4/1 以上動く場合
    // 最大でも4、最小でも4/1になるようになっている。
    if (nActualTimespan < params.nPowTargetTimespan/4)
        nActualTimespan = params.nPowTargetTimespan/4;
    if (nActualTimespan > params.nPowTargetTimespan*4)
        nActualTimespan = params.nPowTargetTimespan*4;
    // Retarget
    const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
    arith_uint256 bnNew;
    bnNew.SetCompact(pindexLast->nBits);
    bnNew *= nActualTimespan;
    bnNew /= params.nPowTargetTimespan;

    if (bnNew > bnPowLimit)
        bnNew = bnPowLimit;

    return bnNew.GetCompact();
}

のようになります。

ビットコイン マイニング報酬のソースコードリーディング

ビットコインのマイニング報酬のコードを見ていきます。

マイニング報酬は、トランザクション手数料の総額 + coinbase報酬

coinbase報酬(BlockSubsidy)は50bitcoinから始まって、210000ブロックごとに半減していきます。

以下のコードでcoinbase報酬を出します。

// Subsidy は 報酬という意味
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
    // nHeightは現在のブロック高.
    // nSubsidyHalvingIntervalは半減ブロック間隔 = 210000
    // ブロック高を半減ブロック間隔で割ることで半減回数を求めている.
    int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
    
    // 半減数の回数最大で64.それを超えたら報酬は0.
    if(halvings >= 64)
        return 0;
        
    // COIN定数は 100,000,000satoshi で,50 * COIN は50億satoshi
    // 初期報酬(nSubsidy) が 50億satoshi であることがわかる。
    CAmount nSubsidy = 50 * COIN;
    
    // 報酬は210000ブロックごとに半減.約4年
    // 右シフト演算子を使って報酬(nSubsidy)を割っている
    nSubsidy >>= halvings;
    return nSubsidy;
}

この後、nSubsidy と トランザクション手数料(nFees)を足したものがマイニングの報酬となります。

ビットコインの総発行量を求めるスクリプト

ビットコインの発行量は時間とともに少なくなっていきます。

新しいビットコインはマイニングの報酬という形で生成されます。

210000ブロックごと、およそ4年ごとに発行量は半減されていきます。

以下のスクリプト(Python2)で総発行量を求めてみます。

# マイニングの報酬 (BTC)
reward = 50

# 210000ブロックごとに報酬は半減
# 1*6*24*365*4=210240
# 上の計算から約4年とわかる
interval = 21000

def max_money():
    # 50 BTC = 50 * 10**8 satoshi
    current_reward = 50 * 10**8
    total = 0
    while current_reward > 0:
        total += interval * current_reward
        current_reward /= 2
    return total

# Python3の場合 print(" ")とします。    
# Python2 3 でおそらく結果が少し変わります。
print "ビットコインの総発行量は :", max_money(), " Satoshis です"

結果は、

ビットコインの総発行量は : 209999999769000 Satoshis です

となるはずです。

この計算により、ビットコインの総発行量はおよそ2100万bitcoin であることがわかります。

ビットコインは発行量が減少していくので、インフレは起こらず、デフレになるはずです。

ビットコインのデフレ的傾向について議論するには、マクロ経済の知識が必要になるので、暗号通貨に取り組むなら、経済の勉強も必須となります。

アセンブリ言語の勉強

アセンブラの勉強をさぼっていたので、一回ちゃんと勉強しなおすことにしました。

とりあえず、

アセンブリ言語スタートブック

アセンブリ言語スタートブック

をやっております。ものすごいわかりやすいし、薄い(300ページくらい)のですぐに終わると思います。まあ300が薄いかどうかはなんとも言えませんが、分厚い本を読むのに慣れてしまったので、500ページ以下の本を見るとなんか物足りなく感じるようになってしまいました。

たぶん、C/C++、Lisp、アセンブラ、データ構造、あたりを理解するとプログラミングという概念が、一気にわかるようになります。

アセンブラもちゃんと勉強しましょう。あとHaskell、Go、もね。

なんとか、今年中にBitcoinとEthereumくらいのコードを理解してかけるようになりたい。今年は勉強して、来年からDappsを作り始めようと思います。