什麼是Chaincode(智能合約)?html
chaincode是一個程序,它是使用Go語言編寫的,最終在Java等其餘編程語言中實現了指定的接口。chaincode運行在一個被背書peer進程獨立出來的安全的Docker容器中。chaincode經過應用程序提交的事務初始化和管理帳本狀態。git
chaincode一般處理被網絡成員承認的業務邏輯,所以它被認爲是一種「智能合約」。由chaincode建立的狀態只做用於該chaincode,而不能經過另外一個chaincode直接訪問。可是,在同一個網絡中,給定適當的權限,chaincode能夠調用另外一個chaincode來訪問它的狀態。github
在下面的部分中,咱們將經過區塊鏈通訊產品應用方案供應商諾亞的視角來探索chaincode。咱們的興趣將更加關注諾亞對於chaincode生命週期的操做;在區塊鏈網絡中,打包、安裝、實例化和升級chaincode的過程,是chaincode的操做生命週期的一個功能。docker
智能合約生命週期編程
Hyperledger Fabric的API支持與區塊鏈網絡中的各個節點進行交互——peers、orderers和MSPs——它還容許其中一個在支持的背書節點上打包、安裝、實例化和升級chaincode。儘管Hyperledger Fabric能夠用來管理chaincode的生命週期,但它仍是提供了特定語言的sdk抽象了Hyperledger Fabric API的細節,以促進應用程序的開發。另外,能夠經過CLI直接訪問Hyperledger Fabric API,咱們將在此文檔中使用它。api
官方提供了四個命令來管理一個chaincode的生命週期: package、install、instantiate和upgrade。在將來的版本中,官方也正在考慮添加stop和start命令操做事務來禁用和從新啓用chaincode,而沒必要實際卸載它。在成功安裝並實例化了一個chaincode以後,chaincode就處於活躍中(正在運行),而且能夠經過調用事務處理事務。在安裝完畢後,也能夠在任什麼時候間都對chaincode進行升級。安全
chaincode包由3部分組成:bash
這些簽名有如下目的:網絡
一個channel上的chaincode實例化事務的建立者是經過chaincode的實例化策略來驗證的。併發
建立package(包)
打包chaincode有兩種方法。一種是當想要一個chaincode擁有多個全部者時,須要使用多個身份標識爲該chaincode簽名。這個工做流程須要咱們首先建立一個已簽名的chaincode(一個簽署的CDS),而後經過序列的方式將其傳遞給其餘全部者來簽署。
更簡單的工做流程是正在發行安裝事務的節點的身份簽名時部署已簽署的CDS。
首先將處理更復雜的狀況。可是,若是不須要擔憂多個全部者,那麼能夠跳過下面的安裝chaincode部分。
要建立一個已簽名的chaincode包,請使用如下命令:
peer chaincode package -n mycc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -v 0 -s -S -i "AND('OrgA.admin')" ccpack.out
-s參數是指能夠建立一個由多個全部者簽署的包,而不是簡單地建立一個未處理/修飾過的CDS。當指定了-s時,若是其餘全部者須要簽名,也必須指定-s參數。不然,這個進程會建立一個除了CDS實例化策略以外的已簽署CDS。
-S參數使用在core.yaml中由localMspid屬性值標識的MSP來指示該程序的簽名。
-S參數是可選的。可是,若是一個包是在沒有簽名的狀況下建立的,那麼它就不能由任何其餘全部者使用signpackage命令來簽署。
-i參數是可選的,即指定chaincode實例化策略。實例化策略與背書策略具備相同的格式,並指定哪些id能夠實例化chaincode。在上面的示例中,只容許使用OrgA的admin實例化鏈代碼。若是沒有提供策略,則使用默認策略,這將只容許peer中MSP的admin身份來實例化chaincode。
包簽名(Package signing)
一個已經被簽名的chaincode包在被建立時候能夠交由其它全部者檢查並簽名,這個工做流程支持chaincode包帶外簽署。
ChaincodeDeploymentSpec視須要也許會有共同的所有全部者簽名去建立一個SignedChaincodeDeploymentSpec(或SignedCDS),SignedCDS包含了3個元素:
注意:當chaincode在某些channel上實例化時,此背書策略是由帶外決定的,以提供適當的MSP原則。若是沒有指定實例化策略,則默認策略是channel的任何MSP的admin。
每一個全部者經過將其與全部者的身份(例如證書)相結合,並簽署結合後的結果來爲ChaincodeDeploymentSpec背書。
一個chaincode全部者可使用下面的命令來簽署一個之前建立的簽名包:
peer chaincode signpackage ccpack.out signedccpack.out
ccpack.out和signedccpack.out分別是輸入和輸出包。signedccpack.out包含了使用本地MSP簽名的包的附加簽名。
安裝chaincode
安裝事務將chaincode的源代碼打包成一種指定的格式,稱爲ChaincodeDeploymentSpec(chaincode部署規範或CDS),並將其安裝到運行該chaincode的peer節點上。
注意:必須在channel中的每一個背書節點上安裝chaincode,以運行chaincode。
當安裝API被簡單地給出一個ChaincodeDeploymentSpec時,它將默認實例化策略,幷包含一個空的全部者列表。
注意:chaincode只應該安裝在對chaincode擁有的成員的背書peer節點上,以保護網絡中其餘成員的chaincode邏輯的機密性。那些沒有chaincode的成員,不能成爲chaincode交易的背書人;也就是說,它們不能執行chaincode。可是,它們仍然能夠驗證並將事務提交到帳本上。
要安裝一個chaincode,請將一個簽署的提案發送到system chaincode(系統智能合約)其中被描述爲生命週期系統智能合約( lifecycle system chaincode —— LSCC)的部分。例如,要安裝使用CLI的簡單資產chaincode中描述的sacc示例chaincode,該命令將以下所示:
peer chaincode install -n asset_mgmt -v 1.0 -p sacc
CLI容器內執行建立的SignedChaincodeDeploymentSpec sacc,並將其發送給本地peer,本地peer會調用LSCC上的安裝方法。對-p選項的參數指定了chaincode的路徑,它必須位於用戶的GOPATH的源碼樹中,例如$GOPATH/src/sacc。有關命令選項的完整描述,後面將會講到。
要注意一點,爲了在peer上安裝,簽署的提案的簽名必須來自peer的本地MSP管理員的一個簽名。
chaincode實例化
實例化事務調用生命週期系統chaincode(LSCC)來建立和初始化一個channel上的chaincode。這是一個chaincode-channel綁定過程:chaincode能夠綁定到任意數量的channel,並分別在每一個channel上獨立操做。換句話說,無論chaincode安裝和實例化了多少個其餘channel,狀態都被隔離到一個事務提交的channel上。
實例化事務的建立者必須知足在SignedCDS中包含的chaincode的實例化策略,而且該建立者做爲建立該channel配置信息的一部分,也必須是channel上的一個寫入者。這對於channel的安全性來講是很是重要的,它能夠防止惡意實體部署chaincode或欺騙成員在一個未綁定的channel上執行chaincode。
例如,默認的實例化策略是任何channel上的MSP管理員,所以一個chaincode實例化事務的建立者必須是channel管理員的成員。當事務提案到達背書人(節點)的時候,它將驗證建立者的簽名與實例化策略。而且在將其提交給帳本以前,在事務驗證期間再次執行此操做。
實例化事務還爲channel上的chaincode設置了背書策略。背書策略描述了交易結果的認證要求,被該channel的全部成員所接受。
例如,使用CLI實例化sacc chaincode,並使用john和0初始化狀態,命令將以下所示:
peer chaincode instantiate -n sacc -v 1.0 -c '{"Args":["john","0"]}' -P "OR ('Org1.member','Org2.member')"
注意:簽註策略(CLI使用波蘭表示法),它須要來自Org1或Org2的任意成員的支持,以支持全部的事務到sacc。也就是說,不管是Org1或Org2都必須簽署在sacc上執行調用的結果,以使事務是有效的。
【波蘭表示法(Polish notation,或波蘭記法),是一種邏輯、算術和代數表示方法,其特色是操做符置於操做數的前面,所以也稱作前綴表示法。若是操做符的元數(arity)是固定的,則語法上不須要括號仍然能被無歧義地解析。波蘭記法是波蘭數學家揚·武卡謝維奇1920年代引入的,用於簡化命題邏輯。】
在chaincode成功實例化以後,chaincode在channel上進入活躍狀態,並準備處理任何背書事務類型支持的事務協議。這些事務是併發處理的,由於它們到達了背書peer。
chaincode升級
任什麼時候候,chaincode均可以經過更改其版原本進行升級,這是SignedCDS的一部分。其餘部分,例如全部者和實例化策略是可選的。可是,chaincode的名稱必須是相同的,不然,它將被視爲徹底不一樣的chaincode。
在升級以前,必須將chaincode的新版本安裝在須要的背書peer上。升級是一個相似於實例化事務的事務,它將chaincode的新版本綁定到channel。其餘channels所綁定的舊版本chaincode將會繼續運行舊版本chaincode。換句話說,升級事務只會一次影響一個channel,即提交事務的channel。
注意:因爲chaincode的多個版本可能同時處於活躍狀態,因此升級過程不會自動刪除舊版本,所以用戶必須暫時管理這個版本。
與實例化事務有一個微妙的區別:升級事務是根據當前的chaincode實例化策略檢查的,而不是新策略(若是指定的話)。這是爲了確保在當前的實例化策略中指定的現有成員能夠升級chaincode。
注意:在升級過程當中,調用chaincode Init函數來執行任何與數據相關的更新或從新初始化它,所以在升級chaincode時必須注意避免從新設置狀態。
中止和啓動chaincode
注意,中止和啓動生命週期事務尚未實現。可是,能夠經過從每一個背書人中刪除chaincode容器和SignedCDS包來手動中止chaincode。這是經過在背書peer節點運行的每一個主機或虛擬機上刪除chaincode的容器來完成的,而後從每一個背書peer節點上刪除SignedCDS。
TODO-爲了從peer節點刪除CDS,首先須要進入peer節點的容器。咱們確實須要提供一個可以執行此功能的實用程序腳本。
docker rm -f <container id> rm /var/hyperledger/production/chaincodes/<ccname>:<ccversion>
Stop在工做流程中是有用的,能夠在控制方式上進行升級,在進行升級以前,能夠在全部peer上中止一個chaincode。
CLI(客戶端)
官方正在評估爲Hyperledger Fabric peer二進制文件分發特定平臺的二進制文件的需求。目前,能夠簡單地從運行的docker容器中調用命令。
要查看當前可用的CLI命令,請在運行的fabric-peer Docker容器中執行如下命令:
docker run -it hyperledger/fabric-peer bash
# peer chaincode --help
注意:可以使用docker exec -it cli(容器名) bash命令進入cli
這顯示了與下面示例類似的輸出:
Usage: peer chaincode [command] Available Commands: install Package the specified chaincode into a deployment spec and save it on the peer's path. instantiate Deploy the specified chaincode to the network. invoke Invoke the specified chaincode. list Get the instantiated chaincodes on a channel or installed chaincodes on a peer. package Package the specified chaincode into a deployment spec. query Query using the specified chaincode. signpackage Sign the specified chaincode package upgrade Upgrade chaincode. Flags: --cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint -h, --help help for chaincode -o, --orderer string Ordering service endpoint --tls Use TLS when communicating with the orderer endpoint --transient string Transient map of arguments in JSON encoding
全局flags:--logging-level string
默認的日誌記錄level和overrides,參見core.yaml的完整語法。
–test.coverprofile string Done (default 「coverage.cov」)
-v, –version
使用「peer chaincode [command] –help」獲取更多關於命令的信息。
爲了方便在腳本化的應用程序中使用,peer命令老是在發生命令失敗時生成非零返回代碼。
chaincode命令的例子:
peer chaincode install -n mycc -v 0 -p path/to/my/chaincode/v0 peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a", "b", "c"]}' -C mychannel peer chaincode install -n mycc -v 1 -p path/to/my/chaincode/v1 peer chaincode upgrade -n mycc -v 1 -c '{"Args":["d", "e", "f"]}' -C mychannel peer chaincode query -C mychannel -n mycc -c '{"Args":["query","e"]}' peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'
系統智能合約(System chaincode)
系統chaincode具備相同的編程模型,除了它在peer進程中運行,而不是像普通的chaincode那樣在一個單獨的容器中運行。所以,系統chaincode被構建到peer的可執行文件中,而且不遵循上面描述的相同的生命週期。特別是安裝、實例化和升級並不適用於系統chaincode。
系統chaincode的目的是爲了在peer和chaincode之間減小gRPC的通訊成本,並權衡管理的靈活性。例如,系統chaincode只能用peer二進制進行升級。它還必須註冊一個固定的參數集,而且沒有背書策略或背書策略功能。
系統chaincode用於Hyperledger Fabric以實現許多系統行爲,使它們能夠被系統集成商所取代或修改。
當前的系統chaincode列表:
在修改或替換這些系統chaincode時必須注意,特別是LSCC、ESCC和VSCC,由於它們在主事務執行路徑中。值得注意的是,當VSCC在將其提交到帳本以前驗證一個塊,重要的是,channel中的全部peer節點都要計算相同的驗證,以免帳本差別(非肯定性)。所以,若是VSCC被修改或替換,就須要特別的處理和維護。