1. 程式人生 > >虛擬幣開發專題(山寨幣怎樣通過RPC命令實現區塊瀏覽器)

虛擬幣開發專題(山寨幣怎樣通過RPC命令實現區塊瀏覽器)

區塊鏈愛好者(QQ:53016353)

基本架構如下:

前端web基於或者REST實現,
後端加一層mongodb/mysql等資料庫來代替單機leveldb做資料儲存


目的應該是:
1. 加速查詢
2. 做更高層的資料分析
3.做分散式資料庫


思考:
這些online的查詢固然可以方便我們的日常用, 那如何與相關應用整合呢? 我們是否可以通過簡單的rpc命令實現同等的效果?
有幾個用處:
1 . 大家都可以做自己的qukuai.com或blockchain.info的查詢:)
2.  整合RPC命令到自己的店鋪,收款後查詢用
3.  整合到錢包應用
4.  其他應用場景


cmd分析:


根據高度height查block hash


./bitcoin-cli getblockhash 19999


00000000ba36eb929dc90170a96ee3efb76cbebee0e0e5c4da9eb0b6e74d9124


2. 然後根據block hash查block 資訊
./bitcoin-cli getblock 00000000ba36eb929dc90170a96ee3efb76cbebee0e0e5c4da9eb0b6e74d9124
{
    "hash" : "00000000ba36eb929dc90170a96ee3efb76cbebee0e0e5c4da9eb0b6e74d9124",
    "confirmations" : 263032,
    "size" : 215,
    "height" : 19999,
    "version" : 1,
    "merkleroot" : "c1b09fa6bdc0b12b15cc1400d598ffed29dd33b2e282093a48646d1b7b380c98",
    "tx" : [
        "c1b09fa6bdc0b12b15cc1400d598ffed29dd33b2e282093a48646d1b7b380c98"
    ],
    "time" : 1248291140,
    "nonce" : 1085206531,
    "bits" : "1d00ffff",
    "difficulty" : 1.00000000,
    "chainwork" : "00000000000000000000000000000000000000000000000000004e204e204e20",
    "previousblockhash" : "000000006eb5c2799b0f5fafab6435daeecef8e7f609b731c9879c3f74f28c73",
    "nextblockhash" : "00000000770ebe897270ca5f6d539d8afb4ea4f4e757761a34ca82e17207d886"
}




3. 根據tx查詢單筆交易的資訊:
沒建index時,只能查詢自己錢包的資訊,若不是錢包的交易,則返回如下:
./bitcoin-cli getrawtransaction c1b09fa6bdc0b12b15cc1400d598ffed29dd33b2e282093a48646d1b7b380c98


error: {"code":-5,"message":"Invalid or non-wallet transaction id"}


那怎麼辦呢? 直接分析程式碼找原因:
// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
{
    CBlockIndex *pindexSlow = NULL;
    {
        LOCK(cs_main);
        {
            if (mempool.lookup(hash, txOut))
            {
                return true;
            }
        }


        if (fTxIndex) {
            CDiskTxPos postx;
            if (pblocktree->ReadTxIndex(hash, postx)) {
                CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
                CBlockHeader header;
                try {
                    file >> header;
                    fseek(file, postx.nTxOffset, SEEK_CUR);
                    file >> txOut;
                } catch (std::exception &e) {
                    return error("%s : Deserialize or I/O error - %s", __func__, e.what());
                }
                hashBlock = header.GetHash();
                if (txOut.GetHash() != hash)
                    return error("%s : txid mismatch", __func__);
                return true;
            }
        }


        if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
            int nHeight = -1;
            {
                CCoinsViewCache &view = *pcoinsTip;
                CCoins coins;
                if (view.GetCoins(hash, coins))
                    nHeight = coins.nHeight;
            }
            if (nHeight > 0)
                pindexSlow = chainActive[nHeight];
        }
    }


    if (pindexSlow) {
        CBlock block;
        if (ReadBlockFromDisk(block, pindexSlow)) {
            BOOST_FOREACH(const CTransaction &tx, block.vtx) {
                if (tx.GetHash() == hash) {
                    txOut = tx;
                    hashBlock = pindexSlow->GetBlockHash();
                    return true;
                }
            }
        }
    }


    return false;
}




我們可以看出若fTxIndex為true,則可以直接搜尋index獲取block資訊
通過-reindex -txindex建立索引,呼叫:
./bitcoind -reindex -txindex
這個過程在我的mac上跑了數個小時。。。。。。
-txindex               Maintain a full transaction index (default: 0)
-reindex               Rebuild block chain index from current blk000??.dat files
再次查詢
./bitcoin-cli getrawtransaction c1b09fa6bdc0b12b15cc1400d598ffed29dd33b2e282093a48646d1b7b380c98


01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0168ffffffff0100f2052a01000000434104cab13751ae7f0e0e49f8fb345e931bc6a6349502da0cbcad98e9d95110ebde5ca7af9eb09639c022ac251b44d0fa200b54011198a405984a8ff92ea9028d6d60ac00000000


解碼交易資料
./bitcoin-cli decoderawtransaction 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0168ffffffff0100f2052a01000000434104cab13751ae7f0e0e49f8fb345e931bc6a6349502da0cbcad98e9d95110ebde5ca7af9eb09639c022ac251b44d0fa200b54011198a405984a8ff92ea9028d6d60ac00000000
{
    "txid" : "c1b09fa6bdc0b12b15cc1400d598ffed29dd33b2e282093a48646d1b7b380c98",
    "version" : 1,
    "locktime" : 0,
    "vin" : [
        {
            "coinbase" : "04ffff001d0168",
            "sequence" : 4294967295
        }
    ],
    "vout" : [
        {
            "value" : 50.00000000,
            "n" : 0,
            "scriptPubKey" : {
                "asm" : "04cab13751ae7f0e0e49f8fb345e931bc6a6349502da0cbcad98e9d95110ebde5ca7af9eb09639c022ac251b44d0fa200b54011198a405984a8ff92ea9028d6d60 OP_CHECKSIG",
                "hex" : "4104cab13751ae7f0e0e49f8fb345e931bc6a6349502da0cbcad98e9d95110ebde5ca7af9eb09639c022ac251b44d0fa200b54011198a405984a8ff92ea9028d6d60ac",
                "reqSigs" : 1,
                "type" : "pubkey",
                "addresses" : [
                    "1KWj3Jk8xvS6fDdhQBsfmerscSGsS6CMiS"
            }
        }


}


以上過程基本滿足了大部分的查詢需求:輸入交易ID、區塊高度或雜湊值(BTC)
至於通過"地址"查詢,需要通過蒐集這個地址對應的交易輸入輸出存入資料庫
部分程式碼如下:
function updateKeys($hash160,$pubkey,$blockhash)
{
        global $db;
        $address=hash160ToAddress($hash160);
        $result=pg_fetch_assoc(pg_query_params($db,"SELECT pubkey,encode(hash160,'hex') AS hash160 FROM keys WHERE hash160=decode($1,'hex')",array($hash160)));
        if(!$result && !is_null($pubkey))
        {
                pg_query_params($db, "INSERT INTO keys VALUES (decode($1,'hex'),$2,decode($3,'hex'),decode($4,'hex'));",array($hash160,$address,$pubkey,$blockhash));
        }
        else if(!$result)
        {
                pg_query_params($db, "INSERT INTO keys(hash160,address,firstseen) VALUES (decode($1,'hex'),$2,decode($3,'hex'));",array($hash160,$address,$blockhash));
        }
        else if($result && !is_null($pubkey) && is_null($result["pubkey"]))
        {
                if($result["hash160"]!=strtolower(hash160($pubkey)))
                {
                        sleep(10);
                        die("Hashes don't match");
                }
                pg_query_params($db, "UPDATE keys SET pubkey = decode($1,'hex') WHERE hash160=decode($2,'hex');",array($pubkey,$hash160));
        }
}


案例分析:如何獲取一筆交易的輸入地址?(此case可用在獲取打款地址上)
如何根據txid獲取打款地址呢?其實可以基於blockchain的鏈式結構逆向推導


首先 gettransaction  txid
    [vin] => Array
        (
            [0] => Array
                (
                    [txid] => 63876d10a13f3810a1d568c6ac7154f9b8a590cfc91cf8a17756fb099addf2b5
                    [vout] => 1
獲取到此次的tx得資訊詳細,根據vin裡的txid逆向查詢, txid二次查詢,gettransaction  vin->txid
然後根據vout索引得到輸入address
    [vout] => Array
        (
            [0] => Array
                (
                    [value] => 0.16928006
                    [n] => 0
                    [scriptPubKey] => Array
                        (
                            [asm] => OP_DUP OP_HASH160 1715447427ac1cdfb7c5ba359154c37c5e9caa2b OP_EQUALVERIFY OP_CHECKSIG
                            [hex] => 76a9141715447427ac1cdfb7c5ba359154c37c5e9caa2b88ac
                            [reqSigs] => 1
                            [type] => pubkeyhash
                            [addresses] => Array
                                (
                                    [0] => LML1HJvP8jfeiwgSVmYfNGsedYfDrzKmq3
                                )
                        )