来自:腾讯云,作者:Mr.Su
链接:https://cloud.tencent.com/developer/article/1057817

Hyperledger Composer架构
最初,这篇文章本来将是关于Hyperledger Fabric,但是在了解了Hyperledger Composer之后,很显然,首先写出这些内容是有好处的。这将使我们能够更高层次地了解可以在Hyperledger Fabric区块链上构建哪种类型的业务应用程序,并更轻松地理解Fabric本身的用途。
商业用例
让我们先从在金融行业的人工简单用例开始。以下是这个用例中的各部分:
让我们看看我们能够如何使用Hyperledger Composer来明确这个用例中的所有参与者,并使他们能够共享适当的信息。
什么是Hyperledger Composer?
Hyperledger Composer是一个更高级别的工具集和框架,用于在Hyperledger Fabric区块链之上快速构建和运行应用程序。如果Fabric是网络级别,那么Composer是应用程序级别的。我们可以使用它给那些能在Fabric通道内部署和执行的应用程序定义数据模型、业务逻辑和访问控制列表。此类应用程序的用户不必运行本地节点,并如果需要的话可通过RPC或HTTP REST与远程节点交互。
Composer配备了一个出色的网络环境,它允许用户在浏览器中创建应用程序原型而无需设置本地网络。我们将使用这个环境来实施和测试我们的用例。在未来的文章中,我们将导出“商业网络定义”并将其部署到真正的Hyperledger Fabric区块链。
解决方案
解决方案的完整代码可以在GitHub找到。我们将了解到如何使用Composer Playground逐步配置每一部分。
(GitHub地址:https://github.com/andrei-anisimov/hyperledger-composer-example?spm=a2c4e.11153940.blogcont582465.11.25ab2222E5w1ab)
1.创建网络
选择“部署新的商业网络”并填写所需的信息。在我的情况下,网络的名称是'对冲基金网络',管理卡名称是admin @ hedge-fund-network。选择'空商业网络'模板并点击部署。这将创建一个空的商业网络和一个完全控制它的管理员身份。在创建商业网络后,我们可以通过按'立即连接'连接到它。
2.配置对象模型
Composer有自己的对象建模语言,非常简单易用。有四种类型的资源可以定义:
现在,让我们创建一个名为'org.acme.mynetwork.cto'的模型文件并添加以下代码。该文件定义了3种参与者类型(交易者,客户,托管人),批次资产,交易交易和NewTrade事件。
/ **
*我的商品交易网络
* /
namespace org.acme.mynetwork
asset Lot identified by lotId {
o String lotId
o String securityName
o Double quantity
o Double price
--> Client owner
}
participant Client identified by clientId {
o String clientId
o String description
}
participant Custodian identified by custodianId {
o String custodianId
o String description
}
participant Trader identified by traderId {
o String traderId
o String name
}
transaction Trade {
--> Trader trader
--> Client client
--> Lot lot
}
event NewTradeEvent {
--> Lot lot
}
3.配置交易逻辑
接下来,我们将实现每次发送交易事务时执行的自定义逻辑。使用下面的代码创建一个名为script.js的新脚本文件。Composer知道基于注释中的@param注释为每个交易交易执行此代码。这段代码做了两件事:更改一个Lot的所有者,并在成功时发出一个NewTrade事件。
/ **
*跟踪交易
* @param {org.acme.mynetwork.Trade}交易 - 将被处理的交易
* @交易
* /
function tradeCommodity(trade) {
var factory = getFactory();
trade.lot.owner = trade.client;
var result = getAssetRegistry(‘org.acme.mynetwork.Lot’)
.then(function (assetRegistry) {
return assetRegistry.update(trade.lot);
});
if (result) {
var newTradeEvent = factory.newEvent(‘org.acme.mynetwork’, ‘NewTradeEvent’);
newTradeEvent.lot = trade.lot;
emit(newTradeEvent);
}
return result;
}
4.访问控制列表(ACL)
最后,我们需要定义一个访问控制列表来管理每个参与者类型可以执行和查看的内容。我们在这里指定交易者可以执行交易,客户可以查看他们自己的交易,而保管人可以查看所有交易。
/ *管理员* /
rule NetworkAdminUser {
description: "Grant business network administrators full access to user resources"
participant: "org.hyperledger.composer.system.NetworkAdmin"
operation: ALL
resource: "**"
action: ALLOW
}
rule NetworkAdminSystem {
description: "Grant business network administrators full access to system resources"
participant: "org.hyperledger.composer.system.NetworkAdmin"
operation: ALL
resource: "org.hyperledger.composer.system.**"
action: ALLOW
}
rule CommonReadTransactionRegistry {
description: "Allow all participants to read transaction registry"
participant: "org.hyperledger.composer.system.Participant"
operation: READ
resource: "org.hyperledger.composer.system.TransactionRegistry"
action: ALLOW
}
rule CommonReadParticipantRegistry {
description: "Allow all participants to read participant registry"
participant: "org.hyperledger.composer.system.Participant"
operation: READ
resource: "org.hyperledger.composer.system.ParticipantRegistry"
action: ALLOW
}
rule CommonReadAssetRegistry {
description: "Allow all participants to read asset registry"
participant: "org.hyperledger.composer.system.Participant"
operation: READ
resource: "org.hyperledger.composer.system.AssetRegistry"
action: ALLOW
}
rule CommonReadNetwork {
description: "Allow all participants to read network"
participant: "org.hyperledger.composer.system.Participant"
operation: READ
resource: "org.hyperledger.composer.system.Network"
action: ALLOW
}
rule TraderManageClient {
description: "Allow traders to read all clients"
participant: "org.acme.mynetwork.Trader"
operation: ALL
resource: "org.acme.mynetwork.Client"
action: ALLOW
rule TraderManageOwnTrades {
description: "Allow traders to manage their trades"
participant(t): "org.acme.mynetwork.Trader"
operation: ALL
resource(tt): "org.acme.mynetwork.Trade"
condition: (tt.trader.getIdentifier() == t.getIdentifier())
action: ALLOW
}
rule TraderManageLots {
description: "Allow traders to read and create lots"
participant: "org.acme.mynetwork.Trader"
operation: READ, CREATE
resource: "org.acme.mynetwork.Lot"
action: ALLOW
}
rule TraderUpdateLots {
description: "Allow traders to update lots via Trade transaction"
participant: "org.acme.mynetwork.Trader"
operation: UPDATE
resource: "org.acme.mynetwork.Lot"
transaction: "org.acme.mynetwork.Trade"
action: ALLOW
}
rule TraderReadOwnTrader {
description: "Allow traders to read their own info"
participant(t): "org.acme.mynetwork.Trader"
operation: READ
resource(tt): "org.acme.mynetwork.Trader"
condition: (tt.getIdentifier() == t.getIdentifier())
action: ALLOW
}
rule TraderAddAsset {
description: "Allow traders to add assets to registry"
participant: "org.acme.mynetwork.Trader"
operation: CREATE
resource: "org.hyperledger.composer.system.AddAsset"
action: ALLOW
}
rule TraderCreateHistorianRecord {
description: "Allow traders to create historian record"
participant: "org.acme.mynetwork.Trader"
operation: CREATE
resource: "org.hyperledger.composer.system.HistorianRecord"
action: ALLOW
}
rule TraderReadOwnHistorianRecord {
description: "Allow traders to read their own historian record"
participant(t): "org.acme.mynetwork.Trader"
operation: READ
resource(hr): "org.hyperledger.composer.system.HistorianRecord"
condition: (hr.transactionType == "org.acme.mynetwork.Trade" && hr.participantInvoking.getIdentifier() == t.getIdentifier())
action: ALLOW
}
/ *客户端* /
rule ClientReadOwnTrades {
description: "Allow clients to view their trades"
participant(c): "org.acme.mynetwork.Client"
operation: READ
resource(t): "org.acme.mynetwork.Trade"
condition: (t.client.getIdentifier() == c.getIdentifier())
action: ALLOW
}
rule ClientReadOwnEvents {
description: "Allow clients to subscribe to NewTrade events"
participant
(c): "org.acme.mynetwork.Client"
operation: READ
resource(e): "org.acme.mynetwork.NewTradeEvent"
condition: (e.lot.owner.getIdentifier() == c.getIdentifier())
action: ALLOW
}
rule ClientReadOwnLots {
description: "Allow clients to view lots they own"
participant(c): "org.acme.mynetwork.Client"
operation: READ
resource(s): "org.acme.mynetwork.Lot"
condition: (s.owner.getIdentifier() == c.getIdentifier())
action: ALLOW
}
rule ClientReadOwnClient {
description: "Allow clients to view their info"
participant(c): "org.acme.mynetwork.Client"
operation: READ
resource(cc): "org.acme.mynetwork.Client"
condition: (cc.getIdentifier() == c.getIdentifier())
action: ALLOW
}
rule ClientReadTraders {
description: "Allow clients to view traders"
participant: "org.acme.mynetwork.Client"
operation: READ
resource: "org.acme.mynetwork.Trader"
action: ALLOW
}
rule ClientReadHistorianRecord {
description: "Allow clients to view their historian records"
participant(c): "org.acme.mynetwork.Client"
operation: READ
resource
(hr): "org.hyperledger.composer.system.HistorianRecord"
condition: (hr.transactionType == "org.acme.mynetwork.Trade" && hr.transactionInvoked.client.getIdentifier() == c.getIdentifier())
action: ALLOW
}
/ *保管人* /
rule CustodianReadAllTrades {
description: "Allow custodian to view all trades"
participant: "org.acme.mynetwork.Custodian"
operation: READ
resource: "org.acme.mynetwork.Trade"
action: ALLOW
}
rule CustodianReadAllLots {
description: "Allow custodian to view all lots"
participant: "org.acme.mynetwork.Custodian"
operation: READ
resource: "org.acme.mynetwork.Lot"
action: ALLOW
}
rule CustodianReadAllClients {
description: "Allow custodian to view all clients"
participant: "org.acme.mynetwork.Custodian"
operation: READ
resource: "org.acme.mynetwork.Client"
action: ALLOW
}
rule CustodianReadAllEvents {
description: "Allow custodian to subscribe to NewTrade events"
participant: "org.acme.mynetwork.Custodian"
operation: READ
resource: "org.acme.mynetwork.NewTradeEvent"
action: ALLOW
}
rule CustodianReadAllTraders {
description: "Allow custodian to view all traders"
participant: "org.acme.mynetwork.Custodian"
operation: READ
resource: "org.acme.mynetwork.Trader"
action: ALLOW
}
rule CustodianReadOwnCustodian {
description: "Allow custodian to view their info"
participant(c): "org.acme.mynetwork.Custodian"
operation: READ
resource(cc): "org.acme.mynetwork.Custodian"
condition: (cc.getIdentifier() == c.getIdentifier())
action: ALLOW
}
rule CustodianReadHistorianRecord {
description: "Allow custodian to view all trade historian records"
participant(t): "org.acme.mynetwork.Custodian"
operation: READ
resource(hr): "org.hyperledger.composer.system.HistorianRecord"
condition: (hr.transactionType == "org.acme.mynetwork.Trade")
action: ALLOW
}
完成所有步骤后,我们可以通过单击左侧的更新来部署应用程序。
如何在Playground进行测试
既然我们有完整的应用程序定义,我们可以使用Composer Playground Test模块进行测试(点击顶部的测试)。
1.创建参与者
首先,让我们用一些参与者创建我们的应用程序。我们可以创建2个客户:托管人和交易人。

2.为每个参与者创建身份
为了能够与商业网络进行交互,参与者需要一个关联的身份。身份可以在ID注册表中创建(打开右上角的用户下拉列表)。我们将通过指定其名称并指向上一步中创建的参与者实例来为每个参与者创建一个身份。至少,我们需要4个身份:2个客户,1个交易员和1个托管人。

3.以交易者身份登录
我们现在可以通过点击列表中每个标识旁边的“立即使用”使用新创建的标识进行登录。首先,我们以交易者身份登录并创建一个不属于任何客户的新Lot(客户ID为空)。

然后,我们通过交易将Lot的所有权分配给客户1。

现在,我们再创建一个Lot,并通过另一个交易将其分配给客户2。


4.以客户身份登录
然后,我们将以客户端和客户2的身份登录,以检查我们是否可以看到我们的Lot。

客户1Lot

客户2Lot
正如你所看到的,每个客户只能看到他们拥有所有权的lot,他们不知道其他客户的交易。

5.以托管人身份登录
我们先以托管人身份登陆,再检查我们是否可以查看所有交易。事实上,这两种交易都是可见的,如下所示:

托管人也可以查看所有交易的历史记录:

分散化的说明
请记住,当交易广播到Hyperledger Fabric网络时,每个配置的对等方都独立执行自定义事务处理逻辑,以确保区块链更新的正确性。这是一个主要的体系结构差异,在许多情况下,这与传统的集中式客户端服务器方法相比具有优势。在传统的方法中,单个组织将负责管理数据并将数据暴露给其他参与者,迫使他人信任数据并使其成为潜在的单点故障。
在区块链方法中,每个对等方负责管理和协调他们自己的数据副本。这使整个网络更加灵活和分散。但是,配置并不是很简单。还有其他隐私问题需要考虑,因为这些数据现在托管在许多地方,从而形成潜在的更大威胁。
结论
希望这可以让你更好地理解Hyperledger Composer是什么以及它如何在多个参与者之间共享信息和跟踪资产和其他概念方面起到作用。随意导出网络的.bna文件,并按照此处的教程将应用程序部署到本地Hyperledger Fabric网络。我们很乐意听取您对Hyperledger Composer的想法。请在下面留下任何问题或意见。
●编号127,输入编号直达本文
●输入m获取文章目录
