應用程序設計元素
本節詳細介紹了Hyperledger Fabric中的客戶端應用程序和智能合約開發的關鍵功能。對功能的深入了解將幫助您設計和實施高效的解決方案。
合約名稱
受眾:架構師,應用程序和智能合約開發人員,管理員
鏈碼是用于將代碼部署到Hyperledger Fabric區塊鏈網絡的通用容器。在一個鏈碼中定義了一個或多個相關的智能合約。每個智能合約都有一個在鏈碼中唯一標識它的名稱。應用程序使用其合同名稱在實例化的鏈碼中訪問特定的智能合同。
在本主題中,我們將介紹:
鏈碼
在“ 開發應用程序”主題中,我們可以看到Fabric SDK如何提供高級編程抽象,以幫助應用程序和智能合約開發人員專注于他們的業務問題,而不是如何與Fabric網絡交互的底層細節。
智能合約是高級編程抽象的一個示例,可以在鏈碼容器中定義智能合約。安裝并實例化一個鏈碼后,其中的所有智能合約都可用于相應的通道。
可以在一個鏈碼中定義多個智能合約。每個文件均由其鏈碼中的名稱唯一標識。
在上圖中,鏈碼A中定義了三個智能合約,而鏈碼B中包含四個智能合約。了解如何使用鏈碼名稱完全限定特定的智能合約。
分類帳結構由一組已部署的智能合約定義。這是因為分類帳包含有關網絡感興趣的業務對象(例如PaperNet中的商業票據)的事實,并且這些業務對象通過智能合約中定義的交易功能在其生命周期(例如發行,購買,贖回)中移動。 。
在大多數情況下,一個鏈碼中只會定義一個智能合約。但是,將相關智能合約保持在單個鏈碼中是有意義的。例如,在不同的貨幣計價的可能有合同的商業票據EuroPaperContract
,DollarPaperContract
, YenPaperContract
這可能需要保持在它們所部署的通道相互同步。
名稱
鏈碼中的每個智能合約均由其合約名稱唯一標識。當構造類時,智能合約可以顯式分配該名稱,或者讓Contract
該類隱式分配默認名稱。
檢查papercontract.js
chaincode 文件:
class CommercialPaperContract extends Contract {
constructor() {
// Unique name when multiple contracts per chaincode file
super('org.papernet.commercialpaper');
}
查看CommercialPaperContract
構造函數如何將合同名稱指定為 org.papernet.commercialpaper
。結果是,在papercontract
鏈碼中,此智能合約現在與合約名稱相關聯 org.papernet.commercialpaper
。
如果未指定顯式合同名稱,則將分配默認名稱-類的名稱。在我們的示例中,默認合同名稱為 CommercialPaperContract
。
仔細選擇您的名字。不僅每個智能合約都必須具有唯一的名稱,一個精心選擇的名字很有啟發性。具體來說,建議使用顯式的DNS樣式命名約定,以幫助組織清晰且有意義的名稱。org.papernet.commercialpaper
表示PaperNet網絡已經定義了標準的商業票據智能合約。
合同名稱還有助于消除給定鏈碼中具有相同名稱的不同智能合同交易功能的歧義。當智能合約緊密相關時,就會發生這種情況。它們的交易名稱將趨于相同。我們可以看到,交易是通過鏈代碼和智能合約名稱的組合在渠道內唯一定義的。
合同名稱在鏈碼文件中必須唯一。某些代碼編輯器將在部署之前檢測相同類名的多個定義。無論是否顯式或隱式指定具有相同協定名稱的多個類,鏈碼都將返回錯誤。
應用
將鏈碼安裝到對等方并在通道上實例化后,應用程序即可訪問其中的智能合約:
const network = await gateway.getNetwork(`papernet`);
const contract = await network.getContract('papercontract', 'org.papernet.commercialpaper');
const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000');
查看應用程序如何通過該contract.getContract()
方法訪問智能合約 。該papercontract
chaincode名 org.papernet.commercialpaper
返回一個contract
可用于提交交易與發行商業票據參考 contract.submitTransaction()
API。
違約合同
鏈碼中定義的第一個智能合約稱為默認 智能合約。默認值很有用,因為鏈碼通常會在其中定義一個智能合約。默認值允許應用程序直接訪問這些交易,而無需指定合同名稱。
默認智能合約是鏈碼中定義的第一個合約。
在此圖中,CommercialPaperContract
是默認的智能合約。即使我們有兩個智能合約,默認的智能合約也使我們 前面的示例更容易編寫:
const network = await gateway.getNetwork(`papernet`);
const contract = await network.getContract('papercontract');
const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', '2020-05-31', '2020-11-30', '5000000');
之所以可行,papercontract
是因為默認的智能合約是, CommercialPaperContract
并且它具有issue
交易記錄。請注意,只能通過顯式尋址來調用issue
事務中的 事務BondContract
。同樣,即使cancel
交易是獨一無二的,因為 BondContract
是不是默認的智能合同,也必須明確處理。
在大多數情況下,鏈碼將僅包含一個智能合約,因此,對鏈碼進行仔細的命名可以減少開發人員將鏈碼作為概念來考慮的需求。在上面的示例代碼中,感覺就像papercontract
是一個智能合約。
總之,合同名稱是一種簡單的機制,可以識別給定鏈碼中的各個智能合約。合同名稱使應用程序可以輕松找到特定的智能合同并使用它來訪問分類賬。
鏈碼名稱空間
受眾:架構師,應用程序和智能合約開發人員,管理員
鏈碼名稱空間允許它保持其世界狀態與其他鏈碼分離。具體來說,具有相同鏈碼的智能合約共享對同一世界狀態的直接訪問,而具有不同鏈碼的智能合約不能直接訪問彼此的世界狀態。如果智能合約需要訪問另一個鏈碼世界狀態,則可以通過執行鏈碼到鏈碼的調用來做到這一點。最后,區塊鏈可以包含與不同世界狀態相關的交易。
在本主題中,我們將介紹:
動機
命名空間是一個常見的概念。據我們了解,公園街,紐約和 公園街,西雅圖是即使它們具有相同的名稱不同的街道。這個城市形成了公園街的命名空間,同時提供了自由和清晰。
在計算機系統中是相同的。命名空間允許不同的用戶對共享系統的不同部分進行編程和操作,而不會互相干擾。許多編程語言都有名稱空間,因此程序可以自由分配唯一的標識符,例如變量名,而不必擔心其他程序會這樣做。我們將看到Hyperledger Fabric使用名稱空間來幫助智能合約將其分類帳世界狀態與其他智能合約分開。
情境
讓我們使用下圖檢查分類帳世界狀態如何組織有關業務對象的事實,這些事實對組織中的組織很重要。無論這些對象是商業票據,債券還是車輛登記證,以及它們在其生命周期中的任何位置,都將其維護為分類帳世界狀態數據庫中的狀態。智能合約通過與分類帳(世界狀態和區塊鏈)進行交互來管理這些業務對象,在大多數情況下,這將涉及查詢或更新分類帳世界狀態。
了解分類賬世界狀態是根據訪問智能賬本的智能合約的鏈碼進行分區的,這一點至關重要,而這種分區或命名間隔是架構師,管理員和程序員的重要設計考慮因素。
分類賬世界狀態根據訪問它的鏈碼分為不同的名稱空間。在給定通道內,相同鏈代碼中的智能合約共享相同的世界狀態,而不同鏈代碼中的智能合約無法直接訪問彼此的世界狀態。同樣,區塊鏈可以包含與不同鏈碼世界狀態相關的交易。
在我們的示例中,我們可以看到在兩個不同的鏈碼中定義了四個智能合約,每個合約都在自己的鏈碼容器中。該euroPaper
和yenPaper
智能合同中規定papers
chaincode。euroBond
和yenBond
智能合約的情況相似-它們在bonds
鏈碼中定義。這種設計可幫助應用程序程序員了解他們使用的是歐元還是日元定價的商業票據或債券,并且由于每種金融產品的規則對于不同的貨幣并沒有真正改變,因此有必要使用相同的鏈碼來管理其部署。
該圖還顯示了此部署選擇的后果。數據庫管理系統(DBMS)為papers
和和bonds
鏈碼以及其中包含的智能合約創建不同的世界狀態數據庫。并分別保存在不同的數據庫中;數據彼此隔離,因此單個世界狀態查詢(例如)無法訪問兩個世界狀態。據說世界狀態根據其鏈碼進行了命名。World state A``world state B
請參閱如何包含兩個商業文件清單 和。狀態和是分別由和合約管理的每份論文的實例。因為它們共享相同的鏈碼名稱空間,所以它們的鍵()在鏈碼名稱空間內必須是唯一的,有點像街道名稱在城鎮中是唯一的。注意,有可能在鏈代碼中編寫智能合約,從而對所有商業票據(無論是歐元還是日元)進行匯總計算,因為它們共享相同的名稱空間。債券的情況與此類似–它們被保存在 其中,并映射到一個單獨的數據庫,并且其鍵必須唯一。world state A``paperListEuro``paperListYen``PAP11``PAP21``euroPaper``yenPaper``PAPxyz``papers``papers``world state B``bonds
同樣重要的是,命名空間意味著euroPaper
與yenPaper
直接無法訪問,并且和不能直接訪問。這種隔離非常有用,因為商業票據和債券是非常不同的金融工具。它們具有不同的屬性,并遵循不同的規則。這也意味著和 可能具有相同的鍵,因為它們位于不同的命名空間中。這很有幫助;它為命名提供了很大的自由度。使用這種自由來有意義地命名不同的業務對象。world state B``euroBond``yenBond``world state A``papers``bonds
最重要的是,我們可以看到區塊鏈與在特定通道中運行的對等實體相關聯,并且它包含影響和的交易。那是因為區塊鏈是對等體中最基本的數據結構。可以始終從此區塊鏈重新創建世界狀態集,因為它們是區塊鏈交易的累積結果。世界國家有助于簡化智能合約并提高其效率,因為它們通常僅需要一個國家的當前值。通過名稱空間將世界狀態分開可以幫助智能合約將其邏輯與其他智能合約隔離,而不必擔心對應于不同世界狀態的交易。例如,合同無需擔心world state A``world state B``bonds``paper
交易,因為它看不到它們產生的世界狀態。
還值得注意的是,對等方,chaincode容器和DBMS在邏輯上都是不同的進程。對等方及其所有chaincode容器始終在物理上獨立的操作系統進程中,但是可以根據其類型將DBMS配置為嵌入或獨立 。對于LevelDB,DBMS完全包含在同級中,但是對于CouchDB,它是一個單獨的操作系統進程。
重要的是要記住,在此示例中,名稱空間的選擇是業務要求的結果,該業務要求共享不同貨幣的商業票據,但將它們與債券分開。考慮如何修改名稱空間結構以滿足業務需求,以使每個金融資產類別保持獨立,或共享所有商業票據和債券?
頻道
如果對等方加入了多個渠道,則會為每個渠道創建并管理一個新的區塊鏈。而且,每次在新的通道中實例化一個鏈碼時,都會為其創建一個新的世界狀態數據庫。這意味著通道還與世界狀態的鏈碼一起形成一種命名空間。
但是,相同的對等和鏈碼容器過程可以同時加入多個渠道–與區塊鏈和世界狀態數據庫不同,這些過程不會隨著加入的渠道數量而增加。
例如,如果papers
和bonds
鏈碼在新的通道上實例化,將創建一個完全獨立的區塊鏈,并創建兩個新的世界狀態數據庫。但是,對等和鏈碼容器不會增加;每個都將連接到多個通道。
用法
讓我們使用商業論文示例來說明應用程序如何使用帶有名稱空間的智能合約。值得注意的是,應用程序與對等方進行通信,并且對等方將請求路由到適當的鏈碼容器,然后容器可以訪問DBMS。該路由由圖中所示的對等核心組件完成。
這是使用商業票據和債券的應用程序代碼,以歐元和日元定價。該代碼是不言自明的:
const euroPaper = network.getContract(papers, euroPaper);
paper1 = euroPaper.submit(issue, PAP11);
const yenPaper = network.getContract(papers, yenPaper);
paper2 = yenPaper.submit(redeem, PAP21);
const euroBond = network.getContract(bonds, euroBond);
bond1 = euroBond.submit(buy, BON31);
const yenBond = network.getContract(bonds, yenBond);
bond2 = yenBond.submit(sell, BON41);
查看應用程序如何:
- 使用 指定鏈碼的API 訪問
euroPaper
和yenPaper
合同。參見交互點1a和 2a。getContract()``papers
- 使用指定鏈碼的API 訪問
euroBond
和yenBond
合同。參見交互點3a和4a。getContract()``bonds
- 使用合同將
issue
交易提交到網絡以獲取商業票據。參見相互作用點1a。結果產生了以國家為代表的商業票據; 相互作用點1b。該操作在交互點1c被捕獲為區塊鏈中的事務。PAP11``euroPaper``PAP11``world state A
- 使用合同將
redeem
交易提交到網絡以獲取商業票據。參見交互點2a。結果產生了以國家為代表的商業票據; 交互點2b。該操作在交互點2c被捕獲為區塊鏈中的交易。PAP21``yenPaper``PAP21``world state A
- 使用 合同將
buy
交易提交到網絡以進行擔保。參見相互作用點3a。這導致產生由狀態表示的鍵的在; 相互作用點3b。該操作在交互點3c被捕獲為區塊鏈中的交易。BON31``euroBond``BON31``world state B
- 使用 合同將
sell
交易提交到網絡以進行擔保。參見相互作用點4a。這導致產生由狀態表示的鍵的在; 相互作用點 4b。該操作在交互點4c被捕獲為區塊鏈中的交易。BON41``yenBond``BON41``world state B
了解智能合約如何與世界狀態交互:
-
euroPaper
和yenPaper
合同可以直接訪問,但不能直接訪問。物理地存儲在與鏈碼相對應的數據庫管理系統(DBMS)中的數據庫中。world state A``world state B``World state A``papers``papers
-
euroBond
和yenBond
合同可以直接訪問,但不能直接訪問。物理地存儲在與鏈碼相對應的數據庫管理系統(DBMS)中的數據庫中。world state B``world state A``World state B``bonds``bonds
了解區塊鏈如何捕獲世界所有州的交易:
- 互動1C和2C對應于交易創建和更新商業票據
PAP11
和PAP21
分別。這些都包含在中。world state A
- 互動3c和4c對應于更新債券
BON31
和的交易BON41
。這些都包含在中。world state B
- 如果或由于某種原因被銷毀,則可以通過重播區塊鏈中的所有交易來重新創建它們。
world state A``world state B
跨鏈碼訪問
正如我們在示例場景中看到的,euroPaper
并且yenPaper
不能直接訪問。這是因為我們已經設計了鏈代碼和智能合約,以使這些鏈代碼和世界狀態彼此分開保存。但是,讓我們假設需要訪問。world state B``euroPaper``world state B
為什么會發生這種情況?想象一下,當發行商業票據時,智能合約想要根據具有相似到期日的債券當前收益對票據定價。在這種情況下, euroPaper
合同必須能夠查詢中的債券價格。查看下圖,以了解如何構建此交互。world state B
鏈碼和智能合約如何通過其鏈碼間接訪問另一個世界國家。
注意如何:
- 該應用程序
issue
在euroPaper
智能合約中提交要發行的交易PAP11
。參見互動1a。 - 該
issue
事務中的euroPaper
智能合同要求的query
事務中的euroBond
智能合同。參見相互作用點1b。 - 在
query
中euroBond
能檢索信息。參見相互作用點1c。world state B
- 當控制權返回
issue
交易時,它可以使用響應中的信息對紙張定價并更新信息。參見相互作用點1d。world state A
- 發行以日元計價的商業票據的控制流程相同。參見交互點2a,2b,2c和2d。
使用invokeChaincode()
API在鏈代碼之間傳遞控制。該API將控制權從一個鏈碼傳遞到另一個鏈碼。
盡管在示例中我們僅討論了查詢事務,但是可以調用智能合約來更新被調用的鏈碼的世界狀態。請參閱以下注意事項。
注意事項
- 通常,每個鏈碼中都將包含一個智能合約。
- 如果多個智能合約關系密切,則僅應將它們部署在同一鏈碼中。通常,僅當它們共享相同的世界狀態時才需要這樣做。
- 鏈碼名稱空間提供了不同世界狀態之間的隔離。通常,將不相關的數據相互隔離是有意義的。請注意,您不能選擇鏈碼名稱空間。它由Hyperledger Fabric分配,并直接映射到鏈碼的名稱。
- 為了使使用
invokeChaincode()
API的鏈碼與鏈碼交互,兩個鏈碼必須安裝在同一對等體上。- 對于僅需要查詢被調用鏈碼的世界狀態的交互,調用可以在與調用方鏈碼不同的通道中進行。
- 對于需要更新被調用鏈碼的世界狀態的交互,調用必須與調用者鏈碼在同一通道中。