Hyperledger Fabric創世紀塊原始碼解析
阿新 • • 發佈:2019-01-26
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
}