业务网络定义是Hyperledger Composer编程模型的一个关键概念。它们由模块中BusinessNetworkDefinition
定义的类表示,composer-common
并由两者composer-admin
和composer-client
。
业务网络定义由以下部分组成:
模型文件定义了业务网络的业务领域,而JavaScript文件包含事务处理器功能。事务处理器功能在Hyperledger Fabric上运行,并可访问存储在Hyperledger Fabric区块链世界状态中的资产注册表。
模型文件通常由业务分析师创建,因为它们定义模型元素之间的结构和关系:资产,参与者和事务。
JavaScript文件通常由正在实施业务分析师提供的业务需求的开发人员创建。
访问控制文件包含一组访问控制规则,用于定义业务网络中不同参与者的权限。
一旦定义,可以使用composer
命令行界面将业务网络定义打包到归档中。然后可以使用模块中的AdminConnection
类在Fabric上部署或更新这些存档composer-admin
。
业务网络定义具有以下布局:
models/ (optional)
lib/
permissions.acl (optional)
package.json
README.md (optional)
创建新的业务网络定义的最简单方法是git clone
示例,或者使用Hyperledger Composer Yeoman生成器来创建骨架业务网络。
使用Markdown标记语言描述商业网络的用途。
业务网络定义有一个名称(仅限于基本的ASCII字母数字字符和-
),一个可读的描述和一个版本号。网络的版本号应采用Major.Minor.Micro格式,并且 在增加版本号时应使用语义版本原则。
网络的标识符由其名称,-
字符和版本号组成。因此有效的标识符(和示例)mybusinessnetwork-1.0.3
。
业务网络定义的元数据被读取package.json
,这意味着业务网络定义也可以是有效的npm
包。
业务网络定义的一组域模型定义了与外部系统(例如向网络提交事务的系统)集成时在网络内和网络外有效的类型。
域模型可以打包在业务网络定义中(通常存储在models
目录下),也可以package.json
作为外部依赖项声明。如果您希望跨业务网络定义分享它们,则可以通过npm依赖关系引用模型。
业务网络定义的脚本通常存储在lib
目录下,并打包在业务网络定义中。这些脚本使用ES 5 JavaScript编写,并参考业务网络的域模型中定义的类型。
表示的业务网络的权限用可选permissions.acl
文件表示。
示例业务网络定义存储在GitHub上https://github.com/hyperledger/composer-sample-networks
。您可以通过git clone
此存储库来下拉所有示例网络。每个示例网络都存储在该packages
目录下。
yo hyperledger-composer
? Please select the type of project: (Use arrow keys)
❯ Angular
Business Network
Model
并选择 Business Netork
Welcome to the Hyperledger Composer project generator
? Please select the type of project: Business Network
You can run this generator using: 'yo hyperledger-composer:businessnetwork'
Welcome to the business network generator
? Business network name: mynetwork
? Description: This is my test network
? Author name: Mr Conga
? Author email: [email protected]
? License: Apache-2
? Namespace: org.conga
create package.json
create permissions.acl
create README.md
create models/org.conga.cto
create .eslintrc.yml
create features/sample.feature
create features/support/index.js
create test/logic.js
create lib/logic.js
这产生了骨架业务网络与asset
,participant
和transaction
定义,以及一个mocha
单元测试。
还包括,是一个'最佳实践'eslint配置文件,它定义了JS代码的示例linting规则。
在部署业务网络定义之前,必须将其打包到业务网络存档(.bna)文件中。该composer archive create
命令用于从磁盘上的业务网络定义文件夹创建业务网络归档文件。
一旦创建了业务网络存档文件,就可以使用composer network install
命令和命令将其部署到Hyperledger Fabric composer network start
。
例如:
composer network install --archiveFile [email protected] --card PeerAdmin@fabric-network
composer network start --networkName tutorial-network --networkVersion 1.0.0 --card PeerAdmin@fabric-network --networkAdmin admin --networkAdminEnrollSecret adminpw
要升级已部署业务网络的业务网络定义,请使用composer network upgrade
CLI命令。
在Hyperledger Fabric v1.1中,同行实施管理员和成员的概念。管理员有权将新建商业网络的Hyperledger Fabric链接代码安装到同行。会员没有安装链码的权限。为了将业务网络部署到一组对等方,您必须提供对所有这些对等方具有管理权限的标识。
要使该身份及其证书可用,您必须使用与对等管理员标识关联的证书和私钥创建对等管理业务网卡。Hyperledger Composer提供了一个示例Hyperledger Fabric v1.1网络。该网络的对等管理员被调用PeerAdmin
,并且当您使用示例脚本启动网络时,会自动为您导入标识。请注意,对等管理员可能会被赋予其他Hyperledger Fabric网络的不同名称。
重要提示:在将业务网络部署到Hyperledger Fabric v1.1时,在Hyperledger Fabric认证中心(CA)配置中定义了引导注册器。Hyperledger Composer开发环境包含Hyperledger Fabric的预配置实例,其中包含特定注册ID和引导注册器的注册机密。
在部署业务网络时,按照业务网络定义中指定的访问控制规则强制实施访问控制。每个业务网络必须至少有一个参与者,并且该参与者必须具有访问业务网络的有效标识。否则,客户端应用程序无法与业务网络进行交互。
业务网络管理员是负责在部署业务网络后为其组织配置业务网络的参与者,并负责为其组织中的其他参与者加入。由于业务网络包括多个组织,因此任何特定业务网络都应有多个业务网络管理员。
org.hyperledger.composer.system.NetworkAdmin
Hyperledger Composer提供了一个内置的参与者类型,表示业务网络管理员。此内置参与者类型没有任何特殊权限; 他们仍然服从业务网络定义中指定的访问控制规则。因此,建议您从以下示例访问控制规则开始,以授予业务网络管理员对业务网络的完全访问权限:
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
}
默认情况下,Hyperledger Composer将在部署期间自动创建单个业务网络管理员参与者。用于部署业务网络的身份也将绑定到该业务网络管理员参与者,以便部署后可以使用身份与业务网络进行交互。
Hyperledger Fabric对等管理员可能没有权限使用Hyperledger Fabric证书颁发机构(CA)发布新身份。这可能会限制业务网络管理员加入其组织的其他参与者的能力。因此,最好创建一个业务网络管理员,该管理员有权使用Hyperledger Fabric认证中心(CA)发布新身份。
您可以使用composer network start
命令的其他选项来指定在部署业务网络期间应创建的业务网络管理员。
如果业务网络管理员具有注册ID和注册机密,则可以使用-A
(业务网络管理员)和-S
(业务网络管理员使用注册机密)标志。例如,以下命令将为现有admin
注册ID 创建一个业务网络管理员:
composer network start --networkName tutorial-network --networkVersion 1.0.0 --c PeerAdmin@fabric-network -A admin -S adminpw
请注意:在使用本地Playground实例将业务网络部署到Hyperledger Fabric v1.1时,作为部署过程的一部分,您必须选择如何为初始业务网络参与者提供凭据。初始参与者将是NetworkAdmin。
使用操场部署商业网络时,系统会提示您输入初始参与者的凭证。可以提供证书作为证书或作为预先定义的注册ID和注册机密。如果您使用Hyperledger Composer开发环境中设置的Hyperledger Fabric实例,则引导注册器注册ID是admin
引导注册器注册秘密adminpw
。此初始参与者使用Hyperledger Fabric认证中心(CA)中的启动注册器所设置的凭据,并将成为NetworkAdmin。
在本地部署使用Playground的业务网络时,您必须至少拥有一个具有PeerAdmin
角色的业务网卡和至少一个具有该ChannelAdmin
角色的业务网卡。每个这些业务网卡都必须包含正确的管理员证书。
事件可由Hyperledger Composer发出并由外部应用程序订阅。事件在业务网络定义的模型文件中定义,并由事务处理函数文件中的事务JavaScript发出。
在开始将事件添加到业务网络之前,您应该对业务网络的建模语言以及构成完整业务网络定义的内容有很好的理解。
事件在.cto
业务网络定义的模型文件()中定义,与资产和参与者相同。事件使用以下格式:
event BasicEvent {
}
为了发布事件,创建事件的事务必须调用三个函数,第一个getFactory
函数。在getFactory
允许作为交易的一部分被创建的事件。接下来,必须使用创建事件factory.newEvent('org.namespace', 'BasicEvent')
。这会BasicEvent
在指定的名称空间中创建一个定义。然后必须设置事件所需的属性。最后,该事件必须通过使用发射emit(BasicEvent)
。调用此事件的简单事务将如下所示:
/**
* @param {org.namespace.BasicEventTransaction} basicEventTransaction
* @transaction
*/
async function basicEventTransaction(basicEventTransaction) {
let factory = getFactory();
let basicEvent = factory.newEvent('org.namespace', 'BasicEvent');
emit(basicEvent);
}
此事务创建并发出BasicEvent
业务网络模型文件中定义的类型事件。有关getFactory函数的更多信息,请参阅Composer API文档。
Hyperledger Composer支持三种类型的测试:交互式测试,自动化单元测试和自动系统测试。三者都有不同的用途,对确保区块链项目的成功至关重要。
在部署了业务网络定义之后,通常运行一个互动的“冒烟测试”以确保部署成功。该composer
CLI公开运行这样冒烟测试的命令。
在另一端,您可以使用Docker Compose和Mocha / Chai编写完整的系统测试,这些测试启动运行时,部署您的业务网络定义,然后以编程方式创建资产,提交交易并检查资产注册状态。
单元测试专注于确保在处理交易时对世界状态进行正确的更改。
单元测试和系统测试的执行可以使用CI / CD构建流水线(例如Jenkins,Travis CI或Circle CI)或替代方法自动执行。
您可以使用Playground以交互方式测试创建参与者,资产和提交交易。
命令行可用于检查运行时的状态并提交事务。使用该composer network list
命令查看资产和参与者注册表的状态。使用该composer transaction submit
命令提交事务。
事务处理函数中的业务逻辑应该具有单元测试,理想情况下具有100%的代码覆盖率。这将确保您在业务逻辑中不存在拼写错误或逻辑错误。
您可以使用标准的JavaScript测试库(例如Mocha,Chai,Sinon和Istanbul)来单元测试事务处理器功能中的逻辑。
在embedded
运行时进行单元测试非常有用,因为它可以让你快速在一个模拟的Node.js blockchain环境中测试的业务逻辑,而不必站立一个Hyperledger面料。
Hyperledger Composer可以选择使用npm
软件包管理器来发布业务网络和模型。通过将业务网络发布到npm
需要引用业务网络的应用程序(例如对其进行反思或部署),可以在发布的npm
包上声明二进制包的依赖关系。对商业网络使用npm软件包的语义版本还允许应用程序指定他们接受对商业网络不兼容的变更的容忍度。
该npm
软件包管理器是一个功能强大的(互联网规模)机制来分发任何二进制文件,并在一个表达元数据package.json
文件。
同样,可以将一组Composer域模型(CTO文件)打包到一个npm
包中进行发布。发布模型的能力允许模型在多个商业网络中重复使用(通过声明package.json
依赖关系),并确保语义版本控制可用于控制模型本身的演变。
但是,发布到npm
不需要使用Composer。您可以在应用程序中捆绑商业网络,并使用git等版本控制软件来管理其源文件。
发布模型或业务网络定义的最简单方法,供应用程序使用它来将业务网络定义推送到npm
使用该npm publish
命令的程序包管理器。这将允许希望使用业务网络定义的应用程序(例如通过API部署它)将业务网络定义引用为其package.json
文件中的依赖项。
业务网络成功部署到区块链后,可能需要升级业务网络定义。要升级业务网络定义,请首先将希望部署到本地业务网络组件文件副本(模型,脚本,查询,访问控制和事务处理器文件)的更新进行更新,然后更新本地业务网络的版本文件。更新版本后,将新版本的版本安装.bna
到您的区块链中,并使用该composer network upgrade
命令切换为使用新版本。
在升级部署的业务网络定义之前:
package.json
在将新版商业网络安装到您的区块链之前,更新文件非常重要。
package.json
在您的商业网络目录中打开该文件。
更新版本属性。版本属性必须是.
分隔的数字,例如0.0.2
或1.16.4
。请务必记下您设置的版本号,因为它是以下步骤所需的版本号。
更新版本号后,业务网络必须打包到业务网络存档(.bna
)中。然后.bna
可以将其安装在区块链上并启动。该composer archive create
命令可以打包一个目录或一个npm模块,在这个例子中我们将使用目录命令。
从您的业务网络目录运行composer archive create
命令:
composer archive create -t dir -n .
当业务网络已经打包时,它必须安装到区块链中。它使用与原始业务网络安装时相同的过程进行安装。
使用以下命令将业务网络安装到您的区块链中:
composer network install -a NETWORK-FILENAME.bna -c peeradmin@hlfv1
该命令中使用的商业网卡必须是对等管理卡才能将商业网络安装到区块链对等方。
现在业务网络已经安装到同行,它必须启动。该composer network upgrade
命令将指示对等方停止使用旧版本的业务网络,并开始使用该命令中指定的版本。
升级到使用以下命令安装的业务网络:
composer network upgrade -c peeradmin@hlfv1 -n NETWORK-NAME -V NETWORK-VERSION
网络名称和网络版本必须与package.json
已安装的业务网络中的内容相匹配。
查询用于返回有关区块链世界状态的数据; 例如,您可以编写一个查询来返回指定时间内的所有驱动程序,或具有特定名称的所有驱动程序。该composer-rest-server
组件通过生成的REST API公开命名查询。
查询是业务网络定义的可选组件,用单个查询文件(queries.qry
)编写。
注意:使用Hyperledger Fabric v1.1时,Hyperledger Fabric必须配置为使用CouchDB持久性。
过滤器与查询类似,但使用LoopBack过滤器语法,并且只能使用Hyperledger Composer REST API进行发送。目前只WHERE
支持LoopBack过滤器。其中支持的操作符WHERE
是:=,和,或,gt,gte,lt,lte,neq。使用GET
针对资产类型,参与者类型或交易类型的调用来提交过滤器; 该过滤器将作为参数提供。筛选器将返回指定类的结果,并且不会返回扩展指定类的类的结果。
Hyperledger Composer支持两种类型的查询:命名查询和动态查询。命名查询在业务网络定义中指定,并由composer-rest-server组件公开为GET方法。动态查询可以在交易处理器功能中的运行时动态构建,也可以从客户端代码动态构建。
查询必须包含说明和声明。查询描述是一个描述查询功能的字符串。查询语句包含控制查询行为的操作符和函数。
查询描述可以是任何描述性字符串。查询语句必须包括SELECT
运营商,可以选择包括FROM
,WHERE
,AND
,ORDER BY
,SKIP
,和LIMIT
。
查询应采用以下格式:
query Q1{
description: "Select all drivers older than 65."
statement:
SELECT org.example.Driver
WHERE (age>65)
}
查询可以使用_$
语法嵌入参数。请注意,查询参数必须是基元类型(字符串,整数,双精度,长整数,布尔值,日期时间),关系或枚举。
下面的命名查询是根据3个参数定义的:
query Q18 {
description: "Select all drivers aged older than PARAM"
statement:
SELECT org.example.Driver
WHERE (_$ageParam < age)
ORDER BY [lastName DESC, firstName DESC]
LIMIT _$limitParam
SKIP _$skipParam
}
查询参数通过由composer-rest-server为命名查询创建的GET方法自动公开。
有关Hyperledger Composer查询语言的详细信息,请参阅查询语言参考文档。
查询可以通过调用buildQuery或查询 API 来调用。所述BuildQuery对于 API需要指定作为API输入的一部分的整个查询字符串。该查询 API需要你指定要运行查询的名称。
有关查询API的更多信息,请参阅API文档。
在返回查询结果时,您的访问控制规则将应用于结果。当前用户无权查看的任何内容将从结果中删除。
例如,如果当前用户发送将返回所有资产的查询,但如果他们只有权查看有限的资产选择,则查询将仅返回该有限的一组资产。
过滤器只能使用Hyperledger Composer REST API提交,并且必须使用LoopBack语法。要提交查询,必须针对资产类型,参与者类型或交易类型提交GET REST调用,并将过滤器作为参数提供。支持的要过滤参数的数据类型是数字,布尔值,日期时间和字符串。基本过滤器采用以下格式,其中op
表示操作员:
{"where": {"field1": {"op":"value1"}}}
请注意:只有顶级WHERE
操作员可以有两个以上的操作数。
目前只WHERE
支持LoopBack过滤器。其中支持的操作符WHERE
是:=,和,或,gt,gte,lt,lte,neq。过滤器可以组合多个运算符,在下面的示例中,和运算符嵌套在or运算符中。
{"where":{"or":[{"and":[{"field1":"foo"},{"field2":"bar"}]},{"field3":"foobar"}]}}
的之间操作者返回给定的范围之间的值。它接受数字,日期时间值和字符串。如果提供了字符串,则between运算符会按字母顺序返回提供的字符串之间的结果。在下面的示例中,过滤器将返回a和c之间的驱动程序属性按字母顺序排列的所有资源。
{"where":{"driver":{"between": ["a","c"]}}}
建议您使用声明性访问控制来实现业务网络定义中的访问控制规则。但是,您可以通过检索和测试当前参与者或当前身份来在事务处理器中实施编程访问控制。您可以针对当前参与者的属性或当前身份运行测试,以允许或拒绝交易处理器功能的执行。
交易处理器功能可以调用getCurrentParticipant
函数来获取当前参与者:
let currentParticipant = getCurrentParticipant();
当前参与者是来自业务网络定义的建模参与者的实例或系统类型的实例org.hyperledger.composer.system.NetworkAdmin
。
事务处理函数可以调用getCurrentIdentity
函数来获取当前标识:
let currentIdentity = getCurrentIdentity();
当前身份是系统类型的一个实例org.hyperledger.composer.system.Identity
,它表示部署的业务网络中的身份。
在您执行这些步骤之前,您必须将参与者建模为业务网络定义并将其部署为业务网络。您必须创建了这些参与者的一些实例,并向这些参与者发布了身份。
下面的过程显示了使用以下参与者模型的示例:
namespace net.biz.digitalPropertyNetwork
participant Person identified by personId {
o String personId
o String firstName
o String lastName
}
participant PrivilegedPerson extends Person {
}
getCurrentParticipant
功能验证当前参与者的类型是否符合要求: async function onPrivilegedTransaction(privilegedTransaction) {
let currentParticipant = getCurrentParticipant();
if (currentParticipant.getFullyQualifiedType() !== 'net.biz.digitalPropertyNetwork.PrivilegedPerson') {
throw new Error('Transaction can only be submitted by a privileged person');
}
// Current participant must be a privileged person to get here.
}
getCurrentParticipant
函数验证当前参与者的参与者ID : async function onPrivilegedTransaction(privilegedTransaction) {
let currentParticipant = getCurrentParticipant();
if (currentParticipant.getFullyQualifiedIdentifier() !== 'net.biz.digitalPropertyNetwork.Person#PERSON_1') {
throw new Error('Transaction can only be submitted by person 1');
}
// Current participant must be person 1 to get here.
}
可以将当前参与者的参与者ID与链接到资产的参与者(通过关系)进行比较,以验证当前参与者是否有权访问或修改资产:
async function onPrivilegedTransaction(privilegedTransaction) {
// Get the owner of the asset in the transaction.
let assetOwner = privilegedTransaction.asset.owner;
let currentParticipant = getCurrentParticipant();
if (currentParticipant.getFullyQualifiedIdentifier() !== asset.owner.getFullyQualifiedIdentifier()) {
throw new Error('Transaction can only be submitted by the owner of the asset');
}
// Current participant must be the owner of the asset to get here.
}
getCurrentIdentity
功能验证当前身份的证书是否符合要求: async function onPrivilegedTransaction(privilegedTransaction) {
let currentIdentity = getCurrentIdentity();
// Get the PEM encoded certificate from the current identity.
let certificate = currentIdentity.certificate;
// Perform testing on the PEM encoded certificate.
if (!certificate.match(/^----BEGIN CERTIFICATE----/)) {
throw new Error('Transaction can only be submitted by a person with a valid certificate');
}
// Current identity must have a valid certificate to get here.
}
Hyperledger Composer Historian是一个专门的注册机构,用于记录成功的交易,包括提交它们的参与者和身份。历史记录将事务存储为HistorianRecord
资产,这些资产在Hyperledger Composer系统名称空间中定义。
历史记录注册表是Hyperledger Composer系统级实体。要将历史记录注册表作为访问控制的资源,必须将历史记录引用为:org.hyperledger.composer.system.HistorianRecord
。
请注意:所有参与者必须有权创建HistorianRecord
资产。如果交易是由无权创建HistorianRecord
资产的参与者提交的,则交易将失败。
历史记录注册表将成功的交易存储为HistorianRecord
资产。只要事务成功完成,HistorianRecord
资产就会创建并添加到历史记录注册表中。记录资产在系统名称空间中定义,并具有以下定义:
asset HistorianRecord identified by transactionId {
o String transactionId
o String transactionType
--> Transaction transactionInvoked
--> Participant participantInvoking optional
--> Identity identityUsed optional
o Event[] eventsEmitted optional
o DateTime transactionTimestamp
}
String transactionId
导致HistorianRecord
资产被创建的交易的transactionId 。String transactionType
导致HistorianRecord
资产被创建的交易类别。Transaction transactionInvoked
与导致HistorianRecord
资产创建的交易的关系。Participant participantInvoking
与提交交易的参与者的关系。Identity identityUsed
与用于提交交易的身份的关系。Event[] eventsEmitted
包含事务发出的任何事件的可选属性。DateTime transactionTimestamp
导致HistorianRecord
资产创建的交易的时间戳。所有HistorianRecord
资产与创建它们的交易,该交易的调用参与者以及交易提交时使用的身份都有关系。希望获得这些属性的应用程序必须解决这种关系。
Hyperledger Composer运行时所做的几项操作被归类为事务。这些'系统事务'是在Hyperledger Composer系统模型中定义的。以下内容将添加HistorianRecord
资产:
作为一个注册表,可以使用访问控制规则来控制对历史数据的访问。但是,作为系统级实体,历史记录注册表的资源名称始终为org.hyperledger.composer.system.HistorianRecord
。
如果访问控制规则引用了他们提交的事务,则只允许成员查看历史数据。
rule historianAccess{
description: "Only allow members to read historian records referencing transactions they submitted."
participant(p): "org.example.member"
operation: READ
resource(r): "org.hyperledger.composer.system.HistorianRecord"
condition: (r.participantInvoking.getIdentifier() == p.getIdentifier())
action: ALLOW
}
来自历史记录注册表的数据可以使用API调用或查询进行检索。以下所有示例均使用异步/等待功能,并假定代码封装在具有该async
属性的函数中。
HistorianRecord
资产可以使用REST API system/historian
和system/historian/{id}
使用REST API的调用返回。
使用REST API时,GET调用system/historian
将返回所有历史数据。此调用应谨慎使用,返回不受限制,并可能导致返回大量数据。
system/historian/{id}
使用REST API的GET调用将返回HistorianRecord
指定的资产。
历史学家可以像其他注册机构一样进行查询。例如,返回所有HistorianRecord
资产的典型查询如下所示:
let historian = await businessNetworkConnection.getHistorian();
let historianRecords = await historian.getAll();
console.log(prettyoutput(historianRecords));
由于这是'getAll'调用,它可能会返回大量数据。因此,查询功能对于能够选择记录子集至关重要。一个典型的例子是根据时间选择记录。这使用查询功能来选择事务时间戳超过特定点的记录。返回的记录可以用相同的方式处理。
let now = new Date();
now.setMinutes(10); // set the date to be time you want to query from
let q1 = businessNetworkConnection.buildQuery('SELECT org.hyperledger.composer.system.HistorianRecord ' +
'WHERE (transactionTimestamp > _$justnow)');
await businessNetworkConnection.query(q1,{justnow:now});
可以使用更高级的查询; 例如,以下查询选择并返回“添加”,“更新”和“移除”资产系统事务。
// build the special query for historian records
let q1 = businessNetworkConnection.buildQuery(
`SELECT org.hyperledger.composer.system.HistorianRecord
WHERE (transactionType == 'AddAsset' OR transactionType == 'UpdateAsset' OR transactionType == 'RemoveAsset')`
);
await businessNetworkConnection.query(q1);
默认卡存储是/home/username/.composer
主机上的目录。对于在云环境中运行的应用程序,本地钱包可能会有问题,并且可能希望将卡存储在不同的目录位置。通过使用定制钱包,用户可以控制业务网卡以及用于Hyperledger Fabric认证的证书和私钥的存储位置。
每当一个BusinessNetworkConnection
或AdminConnection
制成,它具有关联CardStore
。每个连接都可以配置为使用特定的连接CardStore
。在Hyperledger Composer存储库中,存储有两个预先配置的选项:
composer-wallet-filesystem
composer-wallet-inmemory
自定义实现可以针对任何给定的后端数据库或对象存储区进行编写,从而可以CardStore
指定非默认文件位置,单独的Docker容器或托管在基于云的数据存储区中。商店配置可以使用配置文件或使用环境变量来完成。
可以使用全局npm安装来安装多个云钱包实施。
有关编写新的云钱包实施的更多详细信息,请参阅以下自述文件。
有两种方法可以定义自定义钱包的.json
配置:使用配置文件或定义环境变量。
请注意:任何定制的钱包实施都必须
composer-wallet
在模块名称中包含前缀。
对于生产部署,能够在应用程序之外配置卡存储更为有用,Hyperledger Composer使用标准配置模块config
。配置文件从当前工作目录的子目录中调用config
。默认配置文件被调用default.json
,配置文件名可以使用NODE_ENV
环境变量进行更改。
以下配置文件使用Redis格式作为示例:
{
"composer": {
"wallet": {
"type": "composer-wallet-redis",
"desc": "Uses a local redis instance,
"options": {
}
}
}
}
type
是这个模块的名字desc
是一些人类的文本请注意:每个连接都会指定一个新的卡存储实例。如果这些解析到相同的后端存储,卡可以共享。
可以通过设置一个包含与配置文件相同信息的环境变量来实现通过环境变量在命令行中指定定制钱包的细节。
以下环境变量示例使用与上述配置文件相同的格式和数据。
export NODE_CONFIG={"composer":{"wallet":{"type":"composer-wallet-redis","desc":"Uses a local redis instance,"options":{}}}}
任何在此shell中的应用程序都将使用云钱包。
文件系统卡存储的位置可以通过指定storePath
作为钱包选项之一的配置文件来更改。
{
"composer": {
"wallet" : {
"type": "composer-wallet-filesystem",
"options" : {
"storePath" : "/my/network/location"
}
}
}
相同的.json
片段可以作为环境变量导出。
以下GitHub存储库分别包含使用Redis和IBM Cloud Object Store的云定制钱包实现。
可以使用全局npm安装来安装多个云定制钱包实施。
有关编写基于云的新定制钱包实施的更多详细信息,请参阅以下自述文件。
要迁移到Redis或IBM Cloud Object Store云定制钱包解决方案,请参阅相关GitHub存储库的自述文件。
从一般意义上讲,迁移到云钱包实施有三个步骤。
这composer-wallet-filesystem
是默认的存储卡,并且在光盘上遵循相同的布局,并且默认情况下位于同一位置。
一些样本和测试案例显示卡片商店是以编程方式创建的。这仍然是可能的,但在初始创建卡商店方面略有不同。
使用默认位置文件系统卡存储仍然是API调用中的默认选项。例如:
adminConnection = new AdminConnection();
clientConnection = new BusinessNetworkConnection();
将在该位置使用文件系统卡存储/home/username/.composer
,或者在NODE_CONFIG
当且仅当在同一个shell实例内执行时指定在导出的自定义钱包中。
要在API中指定自定义钱包,而不使用全局导出的值,则必须将其作为传递给连接的选项包括在内:
const connectionOptions = {
wallet : {
type: 'composer-wallet-filesystem',
options : {
storePath :'/my/network/location'
}
}
};
adminConnection = new AdminConnection(connectionOptions);
clientConnection = new BusinessNetworkConnection(connectionOptions);
在上面,钱包类型可以是新文件位置或者基于云的位置。
以前要使用MemoryCardStore中的代码将被写入
cardStore = new MemoryCardStore();
const adminConnectionOptions = {
cardStore : cardStore
};
adminConnection = new AdminConnection(adminConnectionOptions);
// or more concisely
clientConnection = new BusinessNetworkConnection({cardStore});
这现在已经改变了,卡商店现在必须有不同的指定:
const connectionOptions = {
wallet : {
type: 'composer-wallet-inmemory'
}
};
adminConnection = new AdminConnection(connectionOptions);
clientConnection = new BusinessNetworkConnection(connectionOptions);