1. 程式人生 > >Hyperledger Fabric創世紀塊原始碼解析

Hyperledger Fabric創世紀塊原始碼解析

創世紀塊程式碼流程圖1
創世紀塊程式碼流程圖2

1.serve函式中創世紀塊開始,呼叫MakeGenesis函式

makeGenesisError := genesis.MakeGenesis()
    if makeGenesisError != nil {
        return makeGenesisError
    }

2.MakeGenesis建立創世紀塊並且新增到區塊鏈上

func MakeGenesis() error {
    once.Do(func() {
        ledger, err := ledger.GetLedger()
        if err != nil {
            makeGenesisError = err
            return
        }

        if ledger.GetBlockchainSize() == 0 {
            genesisLogger.Info("Creating genesis block.")
            if makeGenesisError = ledger.BeginTxBatch(0); makeGenesisError == nil {
                makeGenesisError = ledger.CommitTxBatch(0, nil, nil, nil)
            }
        }
    })
    return makeGenesisError
}

3.GetLedger給一個引用到一個“單列模式”賬本

func GetLedger() (*Ledger, error) {
    once.Do(func() {
        ledger, ledgerError = GetNewLedger()
    })
    return ledger, ledgerError
}

3.1. GetNewLedger 給一個引用到新的賬本

func GetNewLedger() (*Ledger, error) {
    blockchain, err := newBlockchain()
    if err != nil {
        return nil, err
    }

    state := state.NewState()
    return &Ledger{blockchain, state, nil}, nil
}

a.從newBlockchain開始,是建立一個新的區塊鏈,整個過程包括獲取資料庫控制代碼,從資料庫中取東西,獲取區塊的雜湊值等等。

b.從NewState開始,構建一個狀態樹的邏輯結構,以便於以這個邏輯結構後面儲存東西

4.GetBlockchainSize返回區塊鏈上的塊的數量

func (ledger *Ledger) GetBlockchainSize() uint64 {
    return ledger.blockchain.getSize()
}

5.噹噹前的transaction-batch需要提交時獲取呼叫。如果交易詳細和狀態改變(在這交易批執行期間可能會發生)被提交到永久儲存時,這個函式返回成功,在這個過程中涉及到寫塊,將塊寫到資料庫,傳送事件等機制

func (ledger *Ledger) CommitTxBatch(id interface{}, transactions []*protos.Transaction, transactionResults []*protos.TransactionResult, metadata []byte) error {
    err := ledger.checkValidIDCommitORRollback(id)
    if err != nil {
        return err
    }

    stateHash, err := ledger.state.GetHash()
    if err != nil {
        ledger.resetForNextTxGroup(false)
        ledger.blockchain.blockPersistenceStatus(false)
        return err
    }

    writeBatch := gorocksdb.NewWriteBatch()
    defer writeBatch.Destroy()
    block := protos.NewBlock(transactions, metadata)

    ccEvents := []*protos.ChaincodeEvent{}

    if transactionResults != nil {
        ccEvents = make([]*protos.ChaincodeEvent, len(transactionResults))
        for i := 0; i < len(transactionResults); i++ {
            if transactionResults[i].ChaincodeEvent != nil {
                ccEvents[i] = transactionResults[i].ChaincodeEvent
            } else {
                ccEvents[i] = &protos.ChaincodeEvent{}
            }
        }
    }
    // 直接在NonHashData儲存chaincode事件。這可能會在新共識中改變,我們可以將其移動到交易
    block.NonHashData = &protos.NonHashData{ChaincodeEvents: ccEvents}
    newBlockNumber, err := ledger.blockchain.addPersistenceChangesForNewBlock(context.TODO(), block, stateHash, writeBatch)
    if err != nil {
        ledger.resetForNextTxGroup(false)
        ledger.blockchain.blockPersistenceStatus(false)
        return err
    }
    ledger.state.AddChangesForPersistence(newBlockNumber, writeBatch)
    opt := gorocksdb.NewDefaultWriteOptions()
    defer opt.Destroy()
    dbErr := db.GetDBHandle().DB.Write(opt, writeBatch)
    if dbErr != nil {
        ledger.resetForNextTxGroup(false)
        ledger.blockchain.blockPersistenceStatus(false)
        return dbErr
    }

    ledger.resetForNextTxGroup(true)
    ledger.blockchain.blockPersistenceStatus(true)

    sendProducerBlockEvent(block)

    //send chaincode events from transaction results
    // 從交易結果傳送鏈上程式碼事件
    sendChaincodeEvents(transactionResults)

    if len(transactionResults) != 0 {
        ledgerLogger.Debug("There were some erroneous transactions. We need to send a 'TX rejected' message here.")
    }
    return nil
}