本系列目录:超级账本源码(V1.3)解析目录
Cryptogen
为了更好的理解Fabric中MSP是如何工作的,我们先通过源码来看一下Fabric提供的Cryptogen
这个命令行工具到底做了什么。
核心代码在common/tools/cryptogen
这个目录下,目录树如下:
cryptogen
├── ca
│ ├── ca_test.go
│ └── generator.go
├── csp
│ ├── csp.go
│ └── csp_test.go
├── main.go
├── metadata
│ ├── metadata.go
│ └── metadata_test.go
└── msp
├── generator.go
├── msp_internal_test.go
└── msp_test.go
该命令需要指定一个配置文件作为输入,我们使用了first-network中默认的配置文件crypto-config.yaml
,运行该命令后,生成了crypto-config
目录,里面包含了生成的相关证书和秘钥等文件。
crypto-config.yaml
文件如下:
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
- Name: Orderer
Domain: example.com
Specs:
- Hostname: orderer
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
- Name: Org1
Domain: org1.example.com
EnableNodeOUs: true
Template:
Count: 2 # peer数量
Users:
Count: 1 # user数量
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 2
Users:
Count: 1
执行cryptogen generate --config=crypto-config.yaml
后,对每一个Org(Orderer、Org1 、Org2)依次生成了
- 签名CA的私钥和自签名证书
- TLS CA的私钥和自签名证书
- 该Org的msp,其中包含签名CA和TLS CA的证书(cacerts和tlscacerts),以及一个管理员证书(admincerts,临时的),如果支持nodeOU还会成成一个config.yaml
- 生成该Org的peer的证书相关的材料:包含一对公私钥(以及签名CA签名的证书)和另一对公私钥(以及tls CA签名的证书),同时将两个CA的证书复制到该peer的msp目录下,将签名公钥对应的证书作为临时的管理员证书(admincerts)
- 生成该Org的user的证书相关的材料:除了
crypto-config.yaml
中Count
指定的user数量外,还生成了一个管理员用户admin
,都是两对公私钥以及对应CA为其签名的证书,将签名CA颁发的证书同时作为该user的管理员证书,同时将admin
用户的管理员证书复制到该Org的msp以及peer的msp下的管理员证书目录(替换掉临时的证书)
总之,每个组织都有自己的CA(一个签名CA、一个TLS CA),该组织的成员(peer或者user)下的msp目录都含有这两个CA的证书和该成员自身的公私钥及证书(由签名CA颁发),每个组织默认生成一个管理员用户(admin
),该admin的证书被复制到该组织的msp目录以及各peer的msp目录下。
MSP初始化
在peer启动时,调用了peer/common/common.go
中的InitCmd
函数,然后调用了InitCrypto
函数,其中设置了该peer的加密参数,并调用了msp/mgmt/mgmt.go
中的LoadLocalMspWithType
函数初始化该peer的msp。
LoadLocalMspWithType
函数读取了该peer对应的msp目录下的相关文件生成了msp config,并最终调用了msp/mspimpl.go
下的Setup
根据该config初始化了MSP。
func (msp *bccspmsp) preSetupV1(conf *m.FabricMSPConfig) error {
// setup crypto config
if err := msp.setupCrypto(conf); err != nil {
return err
}
// Setup CAs
if err := msp.setupCAs(conf); err != nil {
return err
}
// Setup Admins
if err := msp.setupAdmins(conf); err != nil {
return err
}
// Setup CRLs
if err := msp.setupCRLs(conf); err != nil {
return err
}
// Finalize setup of the CAs
if err := msp.finalizeSetupCAs(conf); err != nil {
return err
}
// setup the signer (if present)
if err := msp.setupSigningIdentity(conf); err != nil {
return err
}
// setup TLS CAs
if err := msp.setupTLSCAs(conf); err != nil {
return err
}
// setup the OUs
if err := msp.setupOUs(conf); err != nil {
return err
}
return nil
}
MSP如何参与到Fabric中的各方面
接下来我们通过解析一个交易的完整生命周期来说明MSP的作用。
发起一个交易,从peer/chaincode/invoke.go
的chaincodeInvoke
函数开始;
- 在
InitCmdFactory
中通过signer, err := common.GetDefaultSignerFnc()
获取了该peer的私钥(signer
)用来后续签名使用。 - 在
peer/chaincode/common.go
的peer/chaincode/common.go
函数中完成交易流程- 创建了proposal(包含了creator,也就是签名者(的公钥和mspid)),调用
signedProp, err := putils.GetSignedProposal(prop, signer)
对proposal签名 - 通过grpc调用了
core/endorser/endorser.go
中的ProcessProposal
来为该交易背书,其中在preProcess
函数中,调用了core/common/validation/msgvalidation.go
中的ValidateProposalMessage
函数 - 在
ValidateProposalMessage
函数中,err = checkSignatureFromCreator(shdr.Creator, signedProp.Signature, signedProp.ProposalBytes, chdr.ChannelId)
检查了该proposal的签名的有效性 - 而
core/endorser/endorser.go
中的endorseProposal
函数最终调用core/handlers/endorsement/builtin/default_endorsement.go
中的Endorse
创建了endorsement,使用该peer的私钥为该交易签名背书 - 当client收集到足够的endorsement后,使用
env, err := putils.CreateSignedTx(prop, signer, responses...)
创建了该交易的envelop(包含了endorsement)并为其签名,发给orderer。 - orderer将envelop打包成block,最终发给fabric网络中的其他peer。
- 其他peer启动【VSCC】、【MVCC】、【Commit】过程,交易结束。其中在VSCC过程中验证了该tx的envelop签名,并检查该envelop中携带的的endorsements是否满足该chaincode的endorsement policy(TODO)。
- 创建了proposal(包含了creator,也就是签名者(的公钥和mspid)),调用