问题描述
我在 IBM 云上部署了一个区块链。我实现了一个 Node.js 客户端应用程序,它为 MyOrg 注册管理员用户并在文件系统本地导入钱包。导入钱包后,我可以在链码上提交交易以上传分类帐中的数据并评估交易以查询分类帐。一切都在 Node.js 客户端上运行。
我现在想用 Java 实现一个类似的 Hyperledger 客户端。 https://hyperledger.github.io/fabric-gateway-java/ 处的结构网关示例与用于上传和查询分类帐的 Node.js 代码非常相似。将下面的基本 Node.js 代码与 Java 网关示例代码进行比较,Node.js 和所使用的 Java 类之间有明显的对应关系(两者都有类似网关、网络、合同方法的类):
// Node.js code
// Create a new gateway,and connect to the gateway peer node(s).
gateway = new Gateway();
await gateway.connect(ccp,{ wallet: wallet,identity: OrgAdmin,discovery: {"enabled": true,"asLocalhost":false }});
// Get the network channel that the smart contract is deployed to.
let network = await gateway.getNetwork('mychannel');
// Get the smart contract from the network channel.
let contract = network.getContract('mycontract');
// submit transaction to add data in the ledger
await contract.submitTransaction('txName',txParam1,txParam2);
// query the ledger
let queryResult = await contract.evaluateTransaction('queryTx',queryStr);
问题是Java网关示例假设本地已经有钱包可用,并没有展示如何创建钱包。我尝试将 Node.js 客户端导入的 wallet 目录与 Java gateway 示例一起使用,但它不起作用。调用下面的 .identity() 方法时抛出异常(说指定的身份“MyOrg_Admin”不存在):
// 配置用于访问网络的网关连接。 Gateway.Builder 构建器 = Gateway.createBuilder() .identity(钱包,“MyOrg_Admin”) .networkConfig(networkConfigFile);
我尝试使用较低级别的 fabric-sdk-java 类来创建钱包。下面是用于为 MyOrg 注册管理员用户并在本地导入钱包的 Node.js 代码:
async function enrollOrgAdmin(aOrgName,aOrgCAUrl,aWalletFilePath)
{
try
{
// Create a new CA client for interacting with the CA.
const ca = new FabricCAServices(aOrgCAUrl);
// Create a new file system based wallet for managing identities.
const wallet = new FileSystemWallet(aWalletFilePath);
// Enroll the admin user,and import the new identity into the wallet.
const enrollment = await ca.enroll({ enrollmentID: OrgAdmin,enrollmentSecret: OrgAdminPasswd });
const identity = X509WalletMixin.createIdentity(aOrgName,enrollment.certificate,enrollment.key.toBytes());
await wallet.import(OrgAdmin,identity);
}
catch(error)
{
console.error(`Failed to enroll "${OrgAdmin}": ${error}`);
process.exit(1);
}
}
所需的唯一信息是 OrgCA URL 和组织名称(均可通过解析 connection.json 文件获得)以及组织管理员用户名和密码(您只需要知道)。 FabricCAServices对应的java类好像是HFCAClient。使用此类搜索代码示例,最有用的链接是以下链接(除了fabric-sdk-java 源代码的单元测试): https://developer.ibm.com/technologies/blockchain/tutorials/hyperledger-fabric-java-sdk-for-tls-enabled-fabric-network/
我用于注册管理员用户的 Java 代码(导入钱包的第一步):
String pemStr = "copy-pasted from connection.json['certificateAuthorities'][adr]['tlsCACerts']['pem']";
Properties caProperties = new Properties();
caProperties.put("pemBytes",pemStr.getBytes());
try
{
// caName and caUrl copy-pasted from connection.json['certificateAuthorities'][adr]['caName'] and ['url']
HFCAClient ca = HFCAClient.createNewInstance(caName,caUrl,caProperties);
CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
ca.setCryptoSuite(cryptoSuite);
Enrollment adminenrollment = ca.enroll("MyOrg_Admin","password");
}
catch (Exception e) {
e.printstacktrace();
}
ca.enroll() 调用抛出这个异常:ERROR org.hyperledger.fabric_ca.sdk.HFCAClient - org.hyperledger.fabric.sdk.exception.CryptoException:无法将 CA 证书添加到信任存储。错误:java.io.IOException:数据不完整
谢谢, 离子
解决方法
问题来自 Eclipse IDE:当从 connection.json["certificateAuthorities"][adr]["tlsCACerts"]["pem"] 复制粘贴 PEM 证书时,Eclipse 转义了换行符,所以 "\n" 变成“\n”。因此,总结 Java 注册使用来自 connection.json["certificateAuthorities"][adr]["tlsCACerts"]["pem"]; 的 PEM 证书。示例文件 EnrollAdmin.java ( https://github.com/hyperledger/fabric-samples/blob/1cd71fd26a867efcb0577e02fa42a48a3203ec51/asset-transfer-basic/application-java/src/main/java/application/java/EnrollAdmin.java ) 显示了成功注册 Admin 用户后如何导入钱包。