美文网首页
Derek解读Bytom源码-持久化存储LevelDB

Derek解读Bytom源码-持久化存储LevelDB

作者: 比原链Bytom | 来源:发表于2018-09-11 11:09 被阅读0次

    作者:Derek

    简介

    Github地址:https://github.com/Bytom/bytom

    Gitee地址:https://gitee.com/BytomBlockchain/bytom

    本章介绍Derek解读-Bytom源码分析-创世区块

    作者使用MacOS操作系统,其他平台也大同小异

    Golang Version: 1.8

    创世区块介绍

    区块链里的第一个区块创被称为创世区块。它是区块链里面所有区块的共同祖先。

    在比原链中创世区块被硬编码到bytomd中,每一个比原节点都始于同一个创世区块,这能确保创世区块不会被改变。每个节点都把创世区块作为区块链的首区块,从而构建了一个安全的、可信的区块链。

    获取创世区块

    ./bytomcli get-block 0
    {
      "bits": 2161727821137910500,
      "difficulty": "15154807",
      "hash": "a75483474799ea1aa6bb910a1a5025b4372bf20bef20f246a2c2dc5e12e8a053",
      "height": 0,
      "nonce": 9253507043297,
      "previous_block_hash": "0000000000000000000000000000000000000000000000000000000000000000",
      "size": 546,
      "timestamp": 1524549600,
      "transaction_merkle_root": "58e45ceb675a0b3d7ad3ab9d4288048789de8194e9766b26d8f42fdb624d4390",
      "transaction_status_hash": "c9c377e5192668bc0a367e4a4764f11e7c725ecced1d7b6a492974fab1b6d5bc",
      "transactions": [
        {
          "id": "158d7d7c6a8d2464725d508fafca76f0838d998eacaacb42ccc58cfb0c155352",
          "inputs": [
            {
              "amount": 0,
              "arbitrary": "496e666f726d6174696f6e20697320706f7765722e202d2d204a616e2f31312f323031332e20436f6d707574696e6720697320706f7765722e202d2d204170722f32342f323031382e",
              "asset_definition": {},
              "asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
              "type": "coinbase"
            }
          ],
          "outputs": [
            {
              "address": "bm1q3jwsv0lhfmndnlag3kp6avpcq6pkd3xy8e5r88",
              "amount": 140700041250000000,
              "asset_definition": {},
              "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
              "control_program": "00148c9d063ff74ee6d9ffa88d83aeb038068366c4c4",
              "id": "e3325bf07c4385af4b60ad6ecc682ee0773f9b96e1cfbbae9f0f12b86b5f1093",
              "position": 0,
              "type": "control"
            }
          ],
          "size": 151,
          "status_fail": false,
          "time_range": 0,
          "version": 1
        }
      ],
      "version": 1
    }
    

    使用bytomcli客户端查询高度为0的区块信息。我们可以看到以上输出结果。

    • bits: 目标值,挖矿时计算的hash之后要小于等于的目标值则新块构建成功
    • difficulty: 难度值,矿工找到下一个有效区块的难度。该参数并不存储在区块链上,是由bits计算得出
    • hash: 当前区块hash
    • height: 当前区块高度
    • nonce: 随机数,挖矿时反复使用不同的nonce来生成不同哈希值
    • previous_block_hash: 当前区块的父区块hash值
    • size: 当前区块的字节数
    • timestamp: 出块时间
    • transaction_merkle_root: 创世区块的merkle树根节点
    • transactions: 当前块中的utxo交易

    由于创世区块是第一个块,创世区块的父区块,也就是previous_block_hash参数,默认情况下为0000000000000000000000000000000000000000000000000000000000000000

    时间戳timestamp为1524549600,时间为2018-04-24 14:00:00也就是比原链上主网的时间。

    源码分析

    获取区块链状态

    ** protocol/protocol.go **

    func NewChain(store Store, txPool *TxPool) (*Chain, error) {
        // ...
        storeStatus := store.GetStoreStatus()
        if storeStatus == nil {
            if err := c.initChainStatus(); err != nil {
                return nil, err
            }
            storeStatus = store.GetStoreStatus()
        }
        // ...
    }
    

    当我们第一次启动比原链节点时,store.GetStoreStatus会从db中获取存储状态,获取存储状态的过程是从LevelDB中查询key为blockStore的数据,如果查询出错则认为是第一次运行比原链节点,那么就需要初始化比原主链。

    初始化主链

    ** protocol/protocol.go **

    func (c *Chain) initChainStatus() error {
        genesisBlock := config.GenesisBlock()
        txStatus := bc.NewTransactionStatus()
        for i := range genesisBlock.Transactions {
            txStatus.SetStatus(i, false)
        }
    
        if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
            return err
        }
    
        utxoView := state.NewUtxoViewpoint()
        bcBlock := types.MapBlock(genesisBlock)
        if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
            return err
        }
    
        node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
        if err != nil {
            return err
        }
        return c.store.SaveChainStatus(node, utxoView)
    }
    

    初始化主链有几步操作:

    • config.GenesisBlock()获取创世区块
    • 设置创世区块中所有交易状态
    • 存储创世区块到LevelDB
    • state.NewUtxoViewpoint()用于临时小部分utxo状态存储集合
    • 实例化BlockNode,BlockNode用于选择最佳链作为主链
    • 保存最新主链状态

    被硬编码的创世区块

    ** config/genesis.go **

    func genesisTx() *types.Tx {
        contract, err := hex.DecodeString("00148c9d063ff74ee6d9ffa88d83aeb038068366c4c4")
        if err != nil {
            log.Panicf("fail on decode genesis tx output control program")
        }
    
        txData := types.TxData{
            Version: 1,
            Inputs: []*types.TxInput{
                types.NewCoinbaseInput([]byte("Information is power. -- Jan/11/2013. Computing is power. -- Apr/24/2018.")),
            },
            Outputs: []*types.TxOutput{
                types.NewTxOutput(*consensus.BTMAssetID, consensus.InitialBlockSubsidy, contract),
            },
        }
        return types.NewTx(txData)
    }
    
    func mainNetGenesisBlock() *types.Block {
        tx := genesisTx()
        txStatus := bc.NewTransactionStatus()
        txStatus.SetStatus(0, false)
        txStatusHash, err := bc.TxStatusMerkleRoot(txStatus.VerifyStatus)
        if err != nil {
            log.Panicf("fail on calc genesis tx status merkle root")
        }
    
        merkleRoot, err := bc.TxMerkleRoot([]*bc.Tx{tx.Tx})
        if err != nil {
            log.Panicf("fail on calc genesis tx merkel root")
        }
    
        block := &types.Block{
            BlockHeader: types.BlockHeader{
                Version:   1,
                Height:    0,
                Nonce:     9253507043297,
                Timestamp: 1524549600,
                Bits:      2161727821137910632,
                BlockCommitment: types.BlockCommitment{
                    TransactionsMerkleRoot: merkleRoot,
                    TransactionStatusHash:  txStatusHash,
                },
            },
            Transactions: []*types.Tx{tx},
        }
        return block
    }
    

    mainNetGenesisBlock主要有如下操作:

    • 生成创世区块中的交易,默认就一笔交易
    • 设置块中的交易状态为false
    • 将创世区块设置为merkle树的根节点
    • 实例化Block块并返回

    genesisTx函数生成创世区块中的交易,默认就一笔交易,一笔交易中包含input输入和output输出。

    input输入:
    输入中有一句话"Information is power. -- Jan/11/2013. Computing is power. -- Apr/24/2018."这是为了纪念Aaron Swartz的精神

    output输出:
    输出中我们看到consensus.InitialBlockSubsidy创世区块的奖励。总共140700041250000000/1e8 = 1407000412。也就是14亿个BTM币。

    计算即权力

    引用比原链创始人长铗的话:

    4月24号,我们主网上线,信息即权力,2013年Jaruary11;计算即权力,2018年April24。这句话是为了纪念Aaron Swartz的精神,信息即权力可以视为互联网宣言,致力于信息自由传播,让公民隐私得到保护。计算即权力,致力于让资产自由的交易,自由的流动,让公民的财富得到保护,我觉得这是非常好的纪念。

    相关文章

      网友评论

          本文标题:Derek解读Bytom源码-持久化存储LevelDB

          本文链接:https://www.haomeiwen.com/subject/slnygftx.html