本文接上一節是測試部分
搭建一個模擬測試環境
作者將
fabric release1.2
工程中的
example-e2e
進行了改造來進行本次實驗:
(
1
)首先我們將examples/e2e_cli/
scripts/script.sh
中的安裝智能合約部分注釋掉,或者從此處下載替換原有的腳本
(
2
)然后再寫一個用於安裝
signcd
的腳本 script_chaincode.sh ,放在
examples/e2e_cli/
scripts/
目錄下面
(3)啟動測試網絡:
cd examples/e2e_cli/
bash network_setup.sh up
ps: 注意,要保證當前docker image中fabric相關的鏡像里lastest版本是1.2.0,否則可能以其他版本的鏡像啟動,導致執行無法成功
(
3
)執行以下命令進入
cli
容器
docker exec -it cli bash
整個網絡的組織架構:
OrgOrderer Org1 peer: Peer0 : peer0.org1 Peer1 : Peer1.org1 User: Org1Msp.admin Org2 peer: Peer2: peer0.org2 Peer3: peer1.org2 User: Org2Msp.admin
如果以上四步都沒有報錯說明環境正常。
測試場景
(
1
)缺省策略測試,即不指定
實例化
策略
預期結果:任意一個
Org Admin
都能實例化。
<1.1>
無簽名
setup0:
啟動本地測試環境
cd $GOPATH/github.com/hyperledger/fabric/examples/e2e_cli
bash network_setup.sh restart
#
等服務完全啟動后再進入
cli
容器內
docker exec -it cli bash
ps:
如果服務已經啟動過了就無需再啟動了
ps1
:以下幾步都是在
cli
容器內執行的
setup1:
由
Org1 admin
對
chaincode
打包
ORG_NUM=1 PEER_NUM=0 bash ./scripts/script_chaincode.sh chaincode package -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd -s ccpack.out
ps:
我們此時沒有調用
-i
指令去指定背書策略,
-S
沒有指定所以沒有
owner
簽名。
setup2:
由
Org2 admin
去向
Peer3
安裝智能合約並實例化
ORG_NUM=2 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode install signedccpack.out ORG_NUM=2 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode instantiate -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')"
此時會拋出以下錯誤:
Error: could not assemble transaction, err Proposal response was not successful, error code 500, msg instantiation policy violation: signature set did not satisfy policy
而這不符合我們的預期
;
setup3:
由
Org1 admin
去向
Peer3
發送實例化請求
執行如下命令:
ORG_NUM=1 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode instantiate -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')"
查看本地
docker
容器
docker ps 此時我們能看到新創建了一個容器: dev-peer1.org2.example.com-mycc-1.0-26c2ef32838554aac4f7ad6f100aca865e87959c9a126e86d764c8d01f8346ab
這表示實例化成功,但是有一點
peer
命令比較麻煩,它只會向指定的
CORE_PEER_ADDRESS
去發送命令,無法同時向多個節點發送初始化請求,所以其他節點再去實例化的時候會報錯:
xxxchaincode
已經存在了。
<1.2>
多組織簽名
setup0:
重啟本地環境
cd $GOPATH/github.com/hyperledger/fabric/examples/e2e_cli
bash network_setup.sh restart
docker exec -it cli bash
××
在
cli
容器中執行以下步驟
setup1 :
由
Org1 Admin
和
Org2 Admin
同時簽名
ORG_NUM=1 PEER_NUM=0 bash ./scripts/script_chaincode.sh chaincode package -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd -s -S ccpack.out ORG_NUM=2 PEER_NUM=2 bash ./scripts/script_chaincode.sh chaincode signpackage ccpack.out signedccpack.out ps: peer cli 中指定 -S 就會默認的用localMsp對chaincode進行簽名。
setup2:
由
Org2 admin
去向
Peer3
安裝智能合約並實例化
重復
<1.1>
中的
setup2
步驟
仍然會拋出不符合實例化策略的錯誤。
setup3:
由
Org1 admin
去向
Peer3
發送實例化請求
重復
<1.1>
中的
setup3
步驟
執行成功
總結:
目前來看不符合預期的結果!
從以上兩種情況來看,即便是
instantiation proposal
的
creator
在
own list
中(對
chaincode
進行了簽名),如果不符合策略仍然不會成功。
另外,我們發現是無論是否對
CDS
進行簽名,
Policy
都會生效,校驗
Creator
的時候用
packge
時的
LocalMsp admin
發起實例化都會成功。
分析源碼找到了原因:
Peercli
在打包時不指定
policy
的情況下,默認會添進去的
"AND('" + mspid + ".admin')"
策略。
peer/chaincode/package.go getChaincodeInstallPackage(){ … … ip := instantiationPolicy if ip == "" { //if an instantiation policy is not given, default //to "admin must sign chaincode instantiation proposals" mspid, err := mspmgmt.GetLocalMSP().GetIdentifier() if err != nil { return nil, err } ip = "AND('" + mspid + ".admin')" } … … }
(
2
)指定實例化策略策略
預期:實例化成功
setup 0
重啟測試環境
略
setup 1
打包智能合約並設置背書策略
ORG_NUM=1 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode package -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd -s -i "OR('Org1MSP.admin','Org2MSP.admin')" ccpack.out ps: cli 中默認設置的localMsp是Org1MSP
setup2:
由
Org2 admin
去向
Peer3
安裝智能合約並實例化
參照
<1.1>
中
setup2
結果:符合預期,測試成功。
總結
:
我們這里只能測試
OR
策略,因為
peer-cli
只會讀取本地的
localMSP
作為
creator
進行背書發送實例化請求,
AND
請求需要兩個組織的
admin
的證明。另外我們可以看到
Org2
的
admin
並沒有對
ccpack.out
進行簽名也安裝成功了,是否包含
ownerlist
看來並不影響實例化過程。
(
3
)不指定實例化策略打包直接安裝
預期:任何一個組織的
Admin
都能初始化
setup 0
: 重啟測試環境
略
setup 1
:直接安裝
ORG_NUM=2 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd ORG_NUM=1 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode instantiate -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')"
結果執行成功:與預期相互符合。
(
4
)升級
chaincode
<4.1>
已安裝的
chaincode
未指定
instantiate policy
預期:任意一個
OrgAdmin
可以更新,因為在官方文檔中說法是按照當前已經存在的chaincode的實例化策略進行判別,目前狀態下的chaincode是沒有指定策略,也就是任意一個org.admin身份都可以。
setup1:
安裝新版本鏈碼並指定
instantiate policy
策略,版本設置為
1.1
#
指定實例化策略為只有
Org1MSP.admin
ORG_NUM=1 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode package -n mycc -v 1.1 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd -s -i "AND('Org1MSP.admin')" ccpack.out ORG_NUM=2 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode install ccpack.out
setup2:
更新
chaincode
#
使用不符合新合約策略的
Org2MSP.admin
去更新智能合約
ORG_NUM=2 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode upgrade -C mychannel -n mycc -v 1.1 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')"
執行失敗
setup3:
#
使用
Org1MSP.admin
去更新智能合約
ORG_NUM=1 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode upgrade -o orderer.example.com:7050 -n mycc -v 1.1 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')" -C mychannel
執行成功
結果
:
不符合預期
<4.2>
已安裝的
chaincode
指定
instantiate policy
預期:只有符合當前安裝的
chaincode
的
instantiate
策略的身份才可以去更新
此時我們剛執行完
4.2
測試,所以正好符合測試場景
setup1:
安裝新版本鏈碼並指定
instantiate policy
策略,版本設置為
1.2
#
指定實例化策略為只有
Org1MSP.admin
ORG_NUM=2 PEER_NUM=3 bash ./scripts/script_chaincode.sh package -n mycc -v 1.2 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd -s -i "AND('Org2MSP.admin')" ccpack.out ORG_NUM=2 PEER_NUM=3 ./scripts/script_chaincode.sh chaincode install ccpack.out
setup2:
更新
chaincode
#
使用不符合新合約策略的
Org2MSP.admin
去更新智能合約
ORG_NUM=2 PEER_NUM=3 ./scripts/script_chaincode.sh chaincode upgrade -C mychannel -n mycc -v 1.2 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')"
不能實例化成功:
msg instantiation policy violation: signature set did not satisfy policy
符合預期
Setup3:
ORG_NUM=1 PEER_NUM=3 bash ./scripts/script_chaincode.sh chaincode upgrade -o orderer.example.com:7050 -n mycc -v 1.2 -c '{"Args":["init","a","100","b","200"]}' -P "OR('Org1MSP.peer','Org2MSP.peer')" -C mychannel
不能實例化成功:
msg instantiation policy violation: signature set did not satisfy policy
執行失敗
結果: 不符合預期
總結:根據我們對源碼的研究,更新智能合約的時候不僅僅會校驗當前已經實例化合約的
instantiate_policy
還會去校驗新安裝合約的
instantiate_policy
,必須二者全部符合才能生效!
// executeUpgrade implements the "upgrade" Invoke transaction. func (lscc *lifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, chainName string, cds *pb.ChaincodeDeploymentSpec, policy []byte, escc []byte, vscc []byte, cdfs *ccprovider.ChaincodeData, ccpackfs ccprovider.CCPackage, collectionConfigBytes []byte) (*ccprovider.ChaincodeData, error) { //獲取當前版本的chaincode cds //we need the cd to compare the version cdLedger, err := lscc.getChaincodeData(chaincodeName, cdbytes) if err != nil { return nil, err } //do not upgrade if same version if cdLedger.Version == cds.ChaincodeSpec.ChaincodeId.Version { return nil, IdenticalVersionErr(chaincodeName) } //do not upgrade if instantiation policy is violated if cdLedger.InstantiationPolicy == nil { return nil, InstantiationPolicyMissing("") } // get the signed instantiation proposal //校驗是否符合當前版本的InstantiationPolicy signedProp, err := stub.GetSignedProposal() if err != nil { return nil, err } err = lscc.support.CheckInstantiationPolicy(signedProp, chainName, cdLedger.InstantiationPolicy) if err != nil { return nil, err } //校驗是否符合請求中實例化的chaincode所指定的 Instantiation Policy //retain chaincode specific data and fill channel specific ones cdfs.Escc = string(escc) //用於背書的系統級智能合約名稱 默認為escc cdfs.Vscc = string(vscc) //用於校驗的系統級智能合約名稱 默認為cscc cdfs.Policy = policy //從client端傳入 // retrieve and evaluate new instantiation policy cdfs.InstantiationPolicy, err = lscc.support.GetInstantiationPolicy(chainName, ccpackfs) if err != nil { return nil, err } err = lscc.support.CheckInstantiationPolicy(signedProp, chainName, cdfs.InstantiationPolicy) if err != nil { return nil, err } …… …… return cdfs, nil }
官方的文檔有很多隱藏的坑,所以當遇到問題時最好的方法是閱讀源碼為准。