一.架构设计
sdk在fabric中扮演的角色:
- 通过节点的gRPC协议访问安装在peer节点上的链码
- 将peer返回的背书,封装成交易,发送给orderer,作排序
分为以下三大模块: - fabric-ca-client
- fabric-client
- fabric-network
fabric-ca-client
与fabric-ca 模块交互,主要负责证书管理,如向ca申请证书
fabric-client
负责与fabric网络交互,如发送提案,发送交易监听区块等,试用场景偏向与特殊业务定制
fabric-network
负责与fabric网络交互,如发送交易,监听区块等,是fabric-client的封装,适用场景偏向普通业务直接集成.
二.怎么使用?
2. 1 环境搭建
- 依赖环境 node 8.9-9.0
- 包管理 yarn 1.6.0 or npm 5.5+
- 部署fabric网络
2.2 fabric-ca-client的使用
- admin登录
// 创建ca
let ca = new FabricCAServices('https://localhost:7054', tlsOptions , 'ca-org1', crypto_suite);
// 登录
let enrollment= await ca.enroll({enrollmentID: 'admin',enrollmentSecret: 'adminpw'})
- 注册用户并登录
// 创建ca
let ca = new FabricCAServices('https://localhost:7054', tlsOptions , 'ca-org1', crypto_suite);
// 注册用户
let secret = awit fabric_ca_client.register({enrollmentID: 'user1', affiliation: 'org1.department1',role: 'client'}, admin_user);
// 用户登录
let enrollment = await fabric_ca_client.enroll({enrollmentID: 'user1', enrollmentSecret: secret});
2.3 fabric-client的简单使用(invoke交易)
- 创建身份标识
let client = new Client
let keyPem = fs.readFileSync('.msp/keystore/user-key.pem','utf-8')
let certPem = fs.readFileSync('./msp/signcerts/user-cert.pem','utf-8')
let user = await client.createUser({ //创建User对象
username: 'user', //用户名称
mspid: 'Org1MSP', //所属MSP的ID
cryptoContent: {
privateKeyPEM: keyPem, //用户私钥
signedCertPEM: certPem //用户证书
},
skipPersistence: true //不计入缓存
})
client.setUserContext(user,true) //设置为client的当前身份
- 创建通道对象,并添加peer与orderer
let channel = client.newChannel('mychannel')
channel.addPeer(client.newPeer('grpc://127.0.0.1:7051'))
channel.addOrderer(client.newOrderer('grpc://127.0.0.1:7050'))
- 发送invoke交易
// 构建请求参数
let req = {
chaincodeId: 'mycc',
fcn: 'invoke',
args: ['10'],
txId: client.newTransactionID() // 创建交易id
}
// 获取背书
let prsp = await channel.sendTransactionProposal(req)
// 提交交易
let rsp = await channel.sendTransaction({
proposalResponses: prsp[0],
proposal: prsp[1]
})
2.4 fabric-network 使用(invoke交易)
- 创建wallet(存着身份标识)
const wallet = new FileSystemWallet(walletPath);
- 创建 Gateway 并连接fabric网络
const gateway = new Gateway();
// 启用了发现服务
await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: false } });
- 获取智能合约部署的channel网络
const network = await gateway.getNetwork('mychannel');
- 获取智能合约对象
const contract = network.getContract('fabcar');
- 发送invoke交易
await contract.submitTransaction('changeCarOwner', 'CAR10', 'Honda')
- 发送privatedata交易
const result = await contract.createTransaction(transactionName)
.setTransient(privateData)
.submit(arg1, arg2);
2.5 具体详细案例
hyperledger/fabric-samples/fabcar
三.常用接口说明
fabric-ca-client模块
FabricCAServices
- enroll(req) 登记用户
- register(req, registrar) 注册用户
fabric-client模块
User
- getName() 获取成员名称
- getRolse() 获取角色
- setRolse() 设置角色
- getIdentity() 获取身份对象,身份对被用用于验签
- getSigningIdentity() 获取SigningIdentity对象,SigningIdentity被用于生成签名
- getCryptoSuite() 获取加密套件
- setCryptoSuite(cryptoSuite) 设置加密套件
- setEnrollment(privateKey, certificate, mspId, skipPersistence) 设置登记内容
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
privateKey | api.Key | 私钥对象 |
certificate | string | 证书内容 PEM-encoded |
mspId | string | 成员服务,提供的身份id |
skipPersistence | boolean | 是否缓存 |
- isEnrolled() 是否已经登录了
TransactionID
- getTransactionID 获取交易id(string类型)
- getNonce 获取随机数
- isAdmin 是否被admin生成
Peer
- sendProposal(proposal, timeout) 发送提案
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
proposal | Proposal | 提案 |
timeout | Number | 超时时间 |
- sendDiscovery(request,timeout) 发送服务发现请求
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
request | SignedRequest | 请求 |
timeout | Number | 超时时间 |
Orderer
- sendBroadcast(envelope, timeout) 向oderder服务发送广播消息
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
envelope | byte[] | 数据(common.Envelope protobuf数据) |
timeout | Number | 超时时间 |
- sendDeliver(envelope) 向oderder服务发送传递消息
Channel
- initialize(request) 初始化
- close() 关闭所有连接
- getName() 获取通道名称
- getDiscoveryResults() 获取发现服务结果
- getEndorsementPlan() 获取背书计划
- getOrganizations() 从通道中获取组织id
- addPeer(peer, mspid, roles, replace) 添加peer节点
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
peer | Peer | peer节点对象 |
mspid | string | 组织id |
roles | ChannelPeerRoles | 角色 |
replace | Boolean | 如果存在相同名称的peer,替换 |
- removePeer(peer) 移除peer节点对象
- getPeer(name) 获取peer节点对象
- addOrderer(orderer,replace) 添加orderer节点对象
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
orderer | Orderer | peer节点对象 |
replace | Boolean | 如果存在相同名称的orderer,替换 |
- removeOrderer(orderer) 移除orderer 对象
- getOrderer(name) 获取oderder对象
- newChannelEventHub(peer) 创建ChannelEventHub对象
- getGenesisBlock(request) 获取创世快
- joinChannel(request, timeout) 加入channel
- queryBlockByTxID(tx_id, target, useAdmin, skipDecode) 查询区块
- queryBlockByHash(blockHash, target, useAdmin, skipDecode) 查询区块
- queryTransaction() 查询交易
- queryInstantiatedChaincodes(target, useAdmin) 查询这个通道实例化的链码
- sendInstantiateProposal(request, timeout) 发送实例化chaincode的提案
- sendUpgradeProposal(request, timeout) 发送升级chaincode提案
- sendTransactionProposal(request, timeout) 发送交易提案
- sendTransaction(request, timeout) 发送交易
- generateUnsignedProposal(request, mspId, certificate, admin) 生成没有签名的proposal
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
request | ProposalRequest | 交易请求 |
mspId | string | 成员身份 |
certificate | string | 证书 |
admin | boolean | 是否使用admin |
- sendSignedProposal(request, timeout) 发送签名的提案
- generateUnsignedTransaction(request) 生成没有签名交易
- sendSignedTransaction(request, timeout) 发送签名的交易
- queryByChaincode(request, useAdmin) 查询
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
request | ChaincodeQueryRequest | 交易请求 |
admin | boolean | 是否使用admin |
eg:
const responsePayloads = await channel.queryByChaincode(request);
for (let i = 0; i < responsePayloads.length; i++) {
console.log(util.format('Query result from peer [%s]: %s', i, responsePayloads[i].toString('utf8')));
Client
- createChannel(request) 创建channel对象
- createUser(opts) 创建user对象
- getClientCertHash(create) 获取客户端证书hash
- getMspid() 获取成员id
- newTransactionID(admin) 创建TransactionID对象
- createChannel(request) 发送创建channel交易
- installChaincode(request, timeout) 发送安装chaincode交易
- newChannel(name) 新建channel对象
- newOrderer(url, opts) 创建oderer对象
- newPeer(url, opts) 创建peer对象
- queryChannels(peer, useAdmin) 查询peer节点上的所有通道
- queryInstalledChaincodes(peer, useAdmin) 查询peer上安装的所有链码
- setUserContext(user, skipPersistence) 设置当前所有user
- updateChannel(request) 更新通道交易
fabric-network模块
Gateway
- connect(config, options) 使用连接配置文件或预构建的客户端实例连接到Gateway
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
config | string,object,Client | 配置 |
options | GatewayOptions | 选项 |
eg:
const gateway = new Gateway();
const wallet = new FileSystemWallet('./WALLETS/wallet');
const ccpFile = fs.readFileSync('./network.json');
const ccp = JSON.parse(ccpFile.toString());
await gateway.connect(ccp, {
identity: 'admin',
wallet: wallet
});
- disconnect() 清理并关闭连接
- getCurrentIdentity() 获取当前身份
- getClient() 获取Client
- getNetwork(networkName) 获取network对象
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
networkName | string | channel名称 |
Network
- getChannel() 获取network的底层通道对象
- getContract(chaincodeId, name = '') 获取合约对象
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
chaincodeId | string | 链码的标识 |
name | string | 合约的名称 |
- getEventHubManager() 获取eventhub管理器
- getEventHubSelectionStrategy() 获取eventhub选择策略
- addBlockListener(listenerName, callback, options)创建一个区块监听者
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
name | string | 名称 |
callback | function | 回调函数 (error,block) |
options | object | 选项 |
- addCommitListener(transactionId, callback, options, eventHub) 创建一个交易提交事件监听
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
transactionId | string | 交易id |
callback | function | 回调函数 (parameters) |
options | RegistrationOptions | 选项 ,可选 |
eventHub | ChannelEventHub | 事件,可以选 |
Contract
- createTransactionID 创建交易id对象
- getChaincodeId() 获取链码id
- submitTransaction(name, ...args) 提交交易
输入参数:
参数名称 | 参数类型 | 描述 |
---|---|---|
name | string | 函数名称 |
args | ...string | 函数的参数 |
eg:
contract.submitTransaction('changeCarOwner', 'CAR10', 'Honda')
- evaluateTransaction(name, ...args) 查询交易
- createTransaction(name) 创建Transaction对象
Transaction
- getName() 获取交易名称
- getTransactionID() 获取交易id(fabric-client.TransactionID)对象
- setTransient(transientMap) 设置将传递交易函的,数据但不会记在分类帐上。
- submit(...args) 提交交易
- evaluate(...args) 查询交易