fabric1.2研究笔记(1)-系统Chain Code了解

1、序

       fabric SDK提供了很多对channel、peer等的操作接口,这些接口实际上是调用fabric源码中预置的系统chain code,即scc,源码所在目录为 core/scc/。从之前版本代码中可看出,共有五个,但目前1.2版本源码目录中仅有三个,分别是cscc、lscc和qscc。

//see systemchaincode_test.go for an example using "sample_syscc"
var systemChaincodes = []*SystemChaincode{
	{
		Enabled:           true,
		Name:              "cscc",
		Path:              "github.com/hyperledger/fabric/core/scc/cscc",
		InitArgs:          [][]byte{[]byte("")},
		Chaincode:         &cscc.PeerConfiger{},
		InvokableExternal: true, // cscc is invoked to join a channel
	},
	{
		Enabled:           true,
		Name:              "lscc",
		Path:              "github.com/hyperledger/fabric/core/scc/lscc",
		InitArgs:          [][]byte{[]byte("")},
		Chaincode:         lscc.NewLifeCycleSysCC(),
		InvokableExternal: true, // lscc is invoked to deploy new chaincodes
		InvokableCC2CC:    true, // lscc can be invoked by other chaincodes
	},
	{
		Enabled:   true,
		Name:      "escc",
		Path:      "github.com/hyperledger/fabric/core/scc/escc",
		InitArgs:  [][]byte{[]byte("")},
		Chaincode: &escc.EndorserOneValidSignature{},
	},
	{
		Enabled:   true,
		Name:      "vscc",
		Path:      "github.com/hyperledger/fabric/core/scc/vscc",
		InitArgs:  [][]byte{[]byte("")},
		Chaincode: &vscc.ValidatorOneValidSignature{},
	},
	{
		Enabled:           true,
		Name:              "qscc",
		Path:              "github.com/hyperledger/fabric/core/chaincode/qscc",
		InitArgs:          [][]byte{[]byte("")},
		Chaincode:         &qscc.LedgerQuerier{},
		InvokableExternal: true, // qscc can be invoked to retrieve blocks
		InvokableCC2CC:    true, // qscc can be invoked to retrieve blocks also by a cc
	},
}

SDK提供了动态安装和更新chain code功能,但是源码中设定scc不允许动态安装与修改,其代码如下:

	if lscc.sccprovider.IsSysCC(cds.ChaincodeSpec.ChaincodeId.Name) {
		return errors.Errorf("cannot install: %s is the name of a system chaincode", cds.ChaincodeSpec.ChaincodeId.Name)
	}

下面分别对已有scc进行简单的介绍。

2、qscc

       Query System Chain Code,预置的一些区块查询cc。有对当前区块高度的查询以及一些通过不同参数查询Block详情的方法。block包含签名、transaction输入输出等等信息,它比在couchdb(之前开发fabric项目选用的是couchdb)所展现的数据更全面,下面通过block的查询源码来看block的存储位置以及获取方式。

// constants for indexable attributes
const (
	IndexableAttrBlockNum         = IndexableAttr("BlockNum")
	IndexableAttrBlockHash        = IndexableAttr("BlockHash")
	IndexableAttrTxID             = IndexableAttr("TxID")
	IndexableAttrBlockNumTranNum  = IndexableAttr("BlockNumTranNum")
	IndexableAttrBlockTxID        = IndexableAttr("BlockTxID")
	IndexableAttrTxValidationCode = IndexableAttr("TxValidationCode")
)
// BlockStoreProvider provides an handle to a BlockStore
type BlockStoreProvider interface {
	CreateBlockStore(ledgerid string) (BlockStore, error)
	OpenBlockStore(ledgerid string) (BlockStore, error)
	Exists(ledgerid string) (bool, error)
	List() ([]string, error)
	Close()
}
// BlockStore - an interface for persisting and retrieving blocks
// An implementation of this interface is expected to take an argument
// of type `IndexConfig` which configures the block store on what items should be indexed
type BlockStore interface {
	AddBlock(block *common.Block) error
	GetBlockchainInfo() (*common.BlockchainInfo, error)
	RetrieveBlocks(startNum uint64) (ledger.ResultsIterator, error)
	RetrieveBlockByHash(blockHash []byte) (*common.Block, error)
	RetrieveBlockByNumber(blockNum uint64) (*common.Block, error) // blockNum of  math.MaxUint64 will return last block
	RetrieveTxByID(txID string) (*common.Envelope, error)
	RetrieveTxByBlockNumTranNum(blockNum uint64, tranNum uint64) (*common.Envelope, error)
	RetrieveBlockByTxID(txID string) (*common.Block, error)
	RetrieveTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)
	Shutdown()
}

     上述代码便是查询对应的接口,主要是通过建立索引查询,由此猜测是存储于某个数据库中,但在之前项目开发时并无发现couchdb中存在类似数据,下面选取其中一个接口继续向下研究。

func (index *blockIndex) getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) {
	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockHash]; !ok {
		return nil, blkstorage.ErrAttrNotIndexed
	}
	b, err := index.db.Get(constructBlockHashKey(blockHash))
	if err != nil {
		return nil, err
	}
	if b == nil {
		return nil, blkstorage.ErrNotFoundInIndex
	}
	blkLoc := &fileLocPointer{}
	blkLoc.unmarshal(b)
	return blkLoc, nil
}

type blockIndex struct {
	indexItemsMap map[blkstorage.IndexableAttr]bool
	db            *leveldbhelper.DBHandle
}

       显然,是对某个数据库进行基于索引的查询,但是blockIndex内的db是写死的leveldb,难道说无论配置中选择哪个数据库,它都会自启一个内置的leveldb进行block的存储?从我目前所了解的信息无法得出确切的结论,下一个专题这个问题进行探讨。

3、lscc

       Life Cycle System Chaincode,主要提供chaincode的curd操作。chiancode安装分为两步,install和deploy或update。install需要管理员权限,对上传的chain code的基本信息(名称、版本等)进行简单校验后存放于特定目录,且生成的文件名格式为cc_name.cc_version,该目录及文件名设置代码如下:

// GetCCsPath returns the path where chaincodes are installed
func GetCCsPath() string {
	return config.GetPath("peer.fileSystemPath") + string(filepath.Separator) + "chaincodes"
}


path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)

deploy或update由调用方决定,其接口并不会根据已有信息来判断是否是更新。

var escc []byte
		if len(args) > 4 && len(args[4]) > 0 {
			escc = args[4]
		} else {
			escc = []byte("escc")
		}

		var vscc []byte
		if len(args) > 5 && len(args[5]) > 0 {
			vscc = args[5]
		} else {
			vscc = []byte("vscc")
		}

神秘的escc、vscc出现了,在deployOrUpdate接口内作为参数传递,显然escc和vscc被独立了出来,通过文档了解到其提供了签名(验证策略)和state相关的依赖项,可以自己实现接口,编译成so文件引用(详细信息待研究)。经过一些参数判断及cc名称(名称为key)及版本配置等,最后会将需要实例化的cc核心信息作为一个block进行存储,在数据库中collection nam为channelName_lscc(_lscc固定)。

综上所述,真正生效的cc为根据区块链上的cc信息去检索本地文件获取到的,peer节点下也保存所有上传过的不同版本的cc(不允许同名称同版本上传),后续的查询方法也是基于此。

4、cscc

Configure System Chaincode 主要是对配置区块configuration block的查询及修改等操作。

猜你喜欢

转载自blog.csdn.net/baidu_37379451/article/details/81099928