1. 程式人生 > >hyperledger fabric 筆記(三)-----peer原始碼

hyperledger fabric 筆記(三)-----peer原始碼

Committer的機制

commiter負責在接受交易結果前再次檢查合法性,接受合法交易對賬本的修改,並寫入區塊鏈結構

committer.go

type Committer interface {

	// CommitWithPvtData block and private data into the ledger
	// 將區塊和私有資料寫入賬本
	CommitWithPvtData(blockAndPvtData *ledger.BlockAndPvtData) error

	// GetPvtDataAndBlockByNum retrieves block with private data with given
	// sequence number  使用給定的私有資料檢索塊
	GetPvtDataAndBlockByNum(seqNum uint64) (*ledger.BlockAndPvtData, error)

	// GetPvtDataByNum returns a slice of the private data from the ledger
	// for given block and based on the filter which indicates a map of
	// collections and namespaces of private data to retrieve
	// 從給定區塊中返回私有資料切片,並根據過濾器指示要檢索的私有資料的集合和名稱空間的對映
	GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error)

	// Get recent block sequence number
	// 獲取最近的區塊序列號
	LedgerHeight() (uint64, error)

	// Gets blocks with sequence numbers provided in the slice
	// 根據引數提供的序列號獲取區塊
	GetBlocks(blockSeqs []uint64) []*common.Block

	// Closes committing service
	// 關閉提交服務
	Close()
}

committer_impl.go

// LedgerCommitter is the implementation of  Committer interface
// it keeps the reference to the ledger to commit blocks and retrieve
// chain information
// LedgerCommitter 是commiter介面的實現,它保持對賬本的引用來提交區塊和檢索鏈資訊
type LedgerCommitter struct {
	ledger.PeerLedger
	eventer ConfigBlockEventer
}

// ConfigBlockEventer callback function proto type to define action
// upon arrival on new configuaration update block
// ConfigBlockEventer 回撥函式原型在到達新配置更新塊時定義動作
type ConfigBlockEventer func(block *common.Block) error

// NewLedgerCommitter is a factory function to create an instance of the committer
// which passes incoming blocks via validation and commits them into the ledger.
// NewLedgerCommitter 是一個工廠函式,用於建立提交者的一個例項,他通過驗證傳入傳入塊,並將它們提交到分類賬中
func NewLedgerCommitter(ledger ledger.PeerLedger) *LedgerCommitter {
	return NewLedgerCommitterReactive(ledger, func(_ *common.Block) error { return nil })
}

// NewLedgerCommitterReactive is a factory function to create an instance of the committer
// same as way as NewLedgerCommitter, while also provides an option to specify callback to
// be called upon new configuration block arrival and commit event
// NewLedgerCommitterReactive 是一個工廠函式,用於建立與NewLedgerCommitter相同的提交者例項,同時還提供一個選項來指定在新的配置塊到達和提交事件時呼叫的回撥
func NewLedgerCommitterReactive(ledger ledger.PeerLedger, eventer ConfigBlockEventer) *LedgerCommitter {
	return &LedgerCommitter{PeerLedger: ledger, eventer: eventer}
}

// preCommit takes care to validate the block and update based on its
// content
// preCommit負責驗證塊並根據其內容進行更新
func (lc *LedgerCommitter) preCommit(block *common.Block) error {
	// Updating CSCC with new configuration block
	if utils.IsConfigBlock(block) {
		logger.Debug("Received configuration update, calling CSCC ConfigUpdate")
		if err := lc.eventer(block); err != nil {
			return errors.WithMessage(err, "could not update CSCC with new configuration update")
		}
	}
	return nil
}

// CommitWithPvtData commits blocks atomically with private data
// CommitWithPvtData以私有資料自動提交塊
func (lc *LedgerCommitter) CommitWithPvtData(blockAndPvtData *ledger.BlockAndPvtData) error {
	// Do validation and whatever needed before
	// committing new block
	if err := lc.preCommit(blockAndPvtData.Block); err != nil {
		return err
	}

	// Committing new block
	if err := lc.PeerLedger.CommitWithPvtData(blockAndPvtData); err != nil {
		return err
	}

	// post commit actions, such as event publishing
	lc.postCommit(blockAndPvtData.Block)

	return nil
}

// GetPvtDataAndBlockByNum retrieves private data and block for given sequence number
// GetPvtDataAndBlockByNum通過給定的私有資料檢索塊序列號
func (lc *LedgerCommitter) GetPvtDataAndBlockByNum(seqNum uint64) (*ledger.BlockAndPvtData, error) {
	return lc.PeerLedger.GetPvtDataAndBlockByNum(seqNum, nil)
}

// postCommit publish event or handle other tasks once block committed to the ledger
// postCommit 一旦提交到分類賬本,則通過postcommit釋出事件或處理其他任務
func (lc *LedgerCommitter) postCommit(block *common.Block) {
	// create/send block events *after* the block has been committed
	bevent, fbevent, channelID, err := producer.CreateBlockEvents(block)
	if err != nil {
		logger.Errorf("Channel [%s] Error processing block events for block number [%d]: %+v", channelID, block.Header.Number, err)
	} else {
		if err := producer.Send(bevent); err != nil {
			logger.Errorf("Channel [%s] Error sending block event for block number [%d]: %+v", channelID, block.Header.Number, err)
		}
		if err := producer.Send(fbevent); err != nil {
			logger.Errorf("Channel [%s] Error sending filtered block event for block number [%d]: %+v", channelID, block.Header.Number, err)
		}
	}
}

// LedgerHeight returns recently committed block sequence number
// LedgerHeight返回最近提交的塊順序號
func (lc *LedgerCommitter) LedgerHeight() (uint64, error) {
	var info *common.BlockchainInfo
	var err error
	if info, err = lc.GetBlockchainInfo(); err != nil {
		logger.Errorf("Cannot get blockchain info, %s", info)
		return uint64(0), err
	}

	return info.Height, nil
}

// GetBlocks used to retrieve blocks with sequence numbers provided in the slice
// GetBlocks 用於檢索切片中提供的序號的塊
func (lc *LedgerCommitter) GetBlocks(blockSeqs []uint64) []*common.Block {
	var blocks []*common.Block

	for _, seqNum := range blockSeqs {
		if blck, err := lc.GetBlockByNumber(seqNum); err != nil {
			logger.Errorf("Not able to acquire block num %d, from the ledger skipping...", seqNum)
			continue
		} else {
			logger.Debug("Appending next block with seqNum = ", seqNum, " to the resulting set")
			blocks = append(blocks, blck)
		}
	}

	return blocks
}

validator.go

// Support provides all of the needed to evaluate the VSCC
// 提供了評估VSCC所需的所有支援
type Support interface {
	// Acquire implements semaphore-like acquire semantics
	// Acquire 實現訊號量的獲取語義
	Acquire(ctx context.Context, n int64) error

	// Release implements semaphore-like release semantics
	// Release 實現了訊號量釋放語義
	Release(n int64)

	// Ledger returns the ledger associated with this validator
	// Ledger返回與此驗證程式相關聯的賬本
	Ledger() ledger.PeerLedger

	// MSPManager returns the MSP manager for this channel
	// MSPManager 返回此channel的MSP管理器
	MSPManager() msp.MSPManager

	// Apply attempts to apply a configtx to become the new config
	// Apply嘗試使用configtx成為新的配置
	Apply(configtx *common.ConfigEnvelope) error

	// GetMSPIDs returns the IDs for the application MSPs
	// that have been defined in the channel
	// GetMSPIDs返回已在channel中定義的應用程式MSP的ID
	GetMSPIDs(cid string) []string

	// Capabilities defines the capabilities for the application portion of this channel
	// Capabilities 定義此channel的應用程式部分的功能
	Capabilities() channelconfig.ApplicationCapabilities

	// ChaincodeByName returns the definition (and whether they exist)
	// for a chaincode in a specific channel
	// ChaincodeByName 返回指定channel的chaincode定義,並判斷是否存在
	ChaincodeByName(chainname, ccname string) (resourcesconfig.ChaincodeDefinition, bool)
}

//Validator interface which defines API to validate block transactions
// and return the bit array mask indicating invalid transactions which
// didn't pass validation.
// Validator 定義API以驗證塊事務並返回位陣列掩碼,指示未通過驗證的無效事務
type Validator interface {
	Validate(block *common.Block) error
}

// private interface to decouple tx validator
// and vscc execution, in order to increase
// testability of txValidator
// vsccValidator 用來解耦tx validator和vscc execution,以提高txValidator的可測性
type vsccValidator interface {
	VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode)
}

// vsccValidator implementation which used to call
// vscc chaincode and validate block transactions
// vsccValidatorImpl vsccValidator的實現,用於呼叫vscc chaincode並驗證塊事務
type vsccValidatorImpl struct {
	support     Support
	ccprovider  ccprovider.ChaincodeProvider
	sccprovider sysccprovider.SystemChaincodeProvider
}

// implementation of Validator interface, keeps
// reference to the ledger to enable tx simulation
// and execution of vscc
// txValidator Validator的實現,繼續參考賬本以啟用tx模擬和執行vscc
type txValidator struct {
	support Support
	vscc    vsccValidator
}

// NewTxValidator creates new transactions validator
// NewTxValidator 建立新的事務驗證器
func NewTxValidator(support Support) Validator {
	// Encapsulates interface implementation
	return &txValidator{support,
		&vsccValidatorImpl{
			support:     support,
			ccprovider:  ccprovider.GetChaincodeProvider(),
			sccprovider: sysccprovider.GetSystemChaincodeProvider()}}
}


// Validate performs the validation of a block. The validation
// of each transaction in the block is performed in parallel.
// The approach is as follows: the committer thread starts the
// tx validation function in a goroutine (using a semaphore to cap
// the number of concurrent validating goroutines). The committer
// thread then reads results of validation (in orderer of completion
// of the goroutines) from the results channel. The goroutines
// perform the validation of the txs in the block and enqueue the
// validation result in the results channel. A few note-worthy facts:
// 1) to keep the approach simple, the committer thread enqueues
//    all transactions in the block and then moves on to reading the
//    results.
// 2) for parallel validation to work, it is important that the
//    validation function does not change the state of the system.
//    Otherwise the order in which validation is perform matters
//    and we have to resort to sequential validation (or some locking).
//    This is currently true, because the only function that affects
//    state is when a config transaction is received, but they are
//    guaranteed to be alone in the block. If/when this assumption
//    is violated, this code must be changed.
/*
Validate執行塊的驗證,並執行塊中每個是事務的驗證方法如下:提交程式執行緒在goroutine中啟動tx驗證函式,
(使用訊號量來限制併發驗證goroutine的數量)。該thread然後從結果channel中讀取驗證結果(在完成goroutine的訂購者中)。
goroutine執行塊中txs的驗證並將結果排入結果channel中
1)為了保持驗證方法簡單,提交者執行緒將塊中的所有事務排入佇列,然後繼續讀取結果
2)為了使並行驗證正常工作,重要的是驗證功能不會改變系統的狀態。此處驗證執行的順序很重要,我們不得不求助於順序驗證(或者一些鎖定)
。目前就是這樣做的,因為影響狀態的函式是收到交易並驗證交易,但這必須保證交易獨立在區塊中,如果這個條件改變了,程式碼也要改變。
*/
func (v *txValidator) Validate(block *common.Block) error 


// generateCCKey generates a unique identifier for chaincode in specific channel
// generateCCKey 為特定channel中的chaincode生成唯一識別符號
func (v *txValidator) generateCCKey(ccName, chainID string) string {
	return fmt.Sprintf("%s/%s", ccName, chainID)
}

// invalidTXsForUpgradeCC invalid all txs that should be invalided because of chaincode upgrade txs
// invalidTXsForUpgradeCC 無效所有由於chaincode升級txs而應該被廢止的txs
func (v *txValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*sysccprovider.ChaincodeInstance, txsUpgradedChaincodes map[int]*sysccprovider.ChaincodeInstance, txsfltr ledgerUtil.TxValidationFlags) ledgerUtil.TxValidationFlags

// GetInfoForValidate gets the ChaincodeInstance(with latest version) of tx, vscc and policy from lscc
// GetInfoForValidate 從lscc獲取tx、vscc和policy的chaincode例項(最新版本)
func (v *vsccValidatorImpl) GetInfoForValidate(txid, chID, ccID string) (*sysccprovider.ChaincodeInstance, *sysccprovider.ChaincodeInstance, []byte, error) 

// txWritesToNamespace returns true if the supplied NsRwSet
// performs a ledger write
// txWritesToNamespace 確認提供NsRwSet執行賬本寫入
func (v *vsccValidatorImpl) txWritesToNamespace(ns *rwsetutil.NsRwSet) bool