• Hyperledger Fabric 2.x Java区块链应用


    file

    一、说明

    在上一篇文章中 《Hyperledger Fabric 2.x 自定义智能合约》 分享了智能合约的安装并使用 cli 客户端进行合约的调用;本文将使用 Java 代码基于 fabric-gateway-java 进行区块链网络的访问与交易,并集成 SpringBoot 框架。

    Fabric Gateway SDK 实现Fabric的编程模型,提供了一系列简单的API给应用程序与Fabric区块链网络进行交互;

    网络拓扑图:

    file

    应用程序将各自的网络交互委托给其网关,每个网关都了解网络信道拓扑,包括组织的多个Peer节点和排序节点,使应用程序专注于业务逻辑;Peer节点可以使用gossip协议在组织内部和组织之间相互通信。

    二、Mavn依赖

    添加网关sdk的依赖:

    <dependency>
    		<groupId>org.hyperledger.fabric</groupId>
    		<artifactId>fabric-gateway-java</artifactId>
    		<version>2.2.3</version>
    </dependency>
    

    三、准备配置文件

    工程的目录结构如下图所示:

    file

    3.1. 准备网络证书

    创建目录 crypto-configordererpeer 节点的证书文件复制进来。

    证书文件从 fabric-samplestest-network 目录中复制 ordererOrganizationspeerOrganizations 文件夹:

    file

    3.2. 创建网络配置

    创建文件 connection.json 内容如下:

    {
        "name": "basic-network",
        "version": "1.0.0",
        "client": {
            "organization": "Org1",
            "connection": {
                "timeout": {
                    "peer": {
                        "endorser": "300"
                    },
                    "orderer": "300"
                }
            }
        },
        "channels": {
            "mychannel": {
                "orderers": [
                    "orderer.example.com"
                ],
                "peers": {
                    "peer0.org1.example.com": {
                        "endorsingPeer": true,
                        "chaincodeQuery": true,
                        "ledgerQuery": true,
                        "eventSource": true
                    },
                    "peer0.org2.example.com": {
                        "endorsingPeer": true,
                        "chaincodeQuery": true,
                        "ledgerQuery": true,
                        "eventSource": true
                    }
                }
            }
        },
        "organizations": {
            "Org1": {
                "mspid": "Org1MSP",
                "peers": [
                    "peer0.org1.example.com"
                ],
                "certificateAuthorities": [
                    "ca-org1"
                ],
                "adminPrivateKeyPEM": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk"
                },
                "signedCertPEM": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
                }
            },
            "Org2": {
                "mspid": "Org2MSP",
                "peers": [
                    "peer0.org2.example.com"
                ],
                "certificateAuthorities": [
                    "ca-org2"
                ],
                "adminPrivateKeyPEM": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/priv_sk"
                },
                "signedCertPEM": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem"
                }
            }
        },
        "orderers": {
            "orderer.example.com": {
                "url": "grpcs://192.168.28.134:7050",
                "mspid": "OrdererMSP",
                "grpcOptions": {
                    "ssl-target-name-override": "orderer.example.com",
                    "hostnameOverride": "orderer.example.com"
                },
                "tlsCACerts": {
                    "path": "src/main/resources/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt"
                },
                "adminPrivateKeyPEM": {
                    "path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp/keystore/priv_sk"
                },
                "signedCertPEM": {
                    "path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp/signcerts/Admin@example.com-cert.pem"
                }
            }
        },
        "peers": {
            "peer0.org1.example.com": {
                "url": "grpcs://192.168.28.134:7051",
                "grpcOptions": {
                    "ssl-target-name-override": "peer0.org1.example.com",
                    "hostnameOverride": "peer0.org1.example.com",
                    "request-timeout": 120001
                },
                "tlsCACerts": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
                }
            },
            "peer0.org2.example.com": {
                "url": "grpcs://192.168.28.134:9051",
                "grpcOptions": {
                    "ssl-target-name-override": "peer0.org2.example.com",
                    "hostnameOverride": "peer0.org2.example.com",
                    "request-timeout": 120001
                },
                "tlsCACerts": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
                }
            }
        },
        "certificateAuthorities": {
            "ca-org1": {
                "url": "https://192.168.28.134:7054",
                "grpcOptions": {
                    "verify": true
                },
                "tlsCACerts": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"
                },
                "registrar": [
                    {
                        "enrollId": "admin",
                        "enrollSecret": "adminpw"
                    }
                ]
            },
            "ca-org2": {
                "url": "https://192.168.28.134:8054",
                "grpcOptions": {
                    "verify": true
                },
                "tlsCACerts": {
                    "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem"
                },
                "registrar": [
                    {
                        "enrollId": "admin",
                        "enrollSecret": "adminpw"
                    }
                ]
            }
        }
    }
    

    需按实际情况修改url中的地址,内容中分别包含了 channelsorganizationsordererspeersca 的配置

    3.3. SpringBoot配置

    application.yml 中添加以下内容,用于访问网关的相关配置:

    fabric:
      # wallet文件夹路径(自动创建)
      walletDirectory: wallet
      # 网络配置文件路径
      networkConfigPath: connection.json
      # 用户证书路径
      certificatePath: crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem
      # 用户私钥路径
      privateKeyPath: crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk
      # 访问的组织名
      mspid: Org1MSP
      # 用户名
      username: user1
      # 通道名字
      channelName: mychannel
      # 链码名字
      contractName: mycc
    

    四、连接合约

    分别构建网关、通道和合约的Bean对象,代码如下:

    /**
     * 连接网关
     */
    @Bean
    public Gateway connectGateway() throws IOException, InvalidKeyException, CertificateException {
    		//使用org1中的user1初始化一个网关wallet账户用于连接网络
    		Wallet wallet = Wallets.newFileSystemWallet(Paths.get(this.walletDirectory));
    		X509Certificate certificate = readX509Certificate(Paths.get(this.certificatePath));
    		PrivateKey privateKey = getPrivateKey(Paths.get(this.privateKeyPath));
    		wallet.put(username, Identities.newX509Identity(this.mspid, certificate, privateKey));
    
    		//根据connection.json 获取Fabric网络连接对象
    		Gateway.Builder builder = Gateway.createBuilder()
    						.identity(wallet, username)
    						.networkConfig(Paths.get(this.networkConfigPath));
    
    		//连接网关
    		return builder.connect();
    }
    
    /**
     * 获取通道
     */
    @Bean
    public Network network(Gateway gateway) {
    		return gateway.getNetwork(this.channelName);
    }
    
    /**
     * 获取合约
     */
    @Bean
    public Contract contract(Network network) {
    		return network.getContract(this.contractName);
    }
    

    五、合约调用

    创建controller类,注入Contract对象调用合约方法:

    @Resource
    private Contract contract;
    
    @Resource
    private Network network;
    
    @GetMapping("/getUser")
    public String getUser(String userId) throws ContractException {
    		byte[] queryAResultBefore = contract.evaluateTransaction("getUser",userId);
    		return new String(queryAResultBefore, StandardCharsets.UTF_8);
    }
    
    @GetMapping("/addUser")
    public String addUser(String userId, String userName, String money) throws ContractException, InterruptedException, TimeoutException {
    		byte[] invokeResult = contract.createTransaction("addUser")
    						.setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)))
    						.submit(userId, userName, money);
    		String txId = new String(invokeResult, StandardCharsets.UTF_8);
    		return txId;
    }
    

    六、测试接口

    调用接口 getUser

    http://127.0.0.1:9001/getUser?userId=1
    

    返回:

    {
      "money": 300,
      "name": "zlt",
      "userId": "1"
    }
    

    调用接口 addUser

    http://127.0.0.1:9001/addUser?userId=6&userName=test6&money=600
    

    返回:

    2ae291bb6a366b5ba01ad49e4237da8def9e9828cc2c982e8c49d4b763af0157
    

    七、代码下载

    gitee:https://gitee.com/zlt2000/my-fabric-application-java

    github:https://github.com/zlt2000/my-fabric-application-java

    扫码关注有惊喜!

    file

  • 相关阅读:
    滑动窗口最大值
    uber.zap性能验证
    【spring框架】AOP的Annotation实现(下)
    Spring Boot实战:Spring Boot使用AOP的正确姿势 Spring AOP术语 通知 连接点 切点 切面 引入 织入
    Git极简教程(3)branch级别的操作,合并分支 拉取最新代码git pull 包含( git fetch origin 和 git merge origin/master )
    当使用git branch r是当分支有很多的时候出现end 使用:q可以退出
    Java异常类型及处理 Throwable在异常类层次结构的顶层,在AOP中用到
    Git极简教程(2)remote级别的操作,remote(多个分支的集合体)我们叫做origin,origin/master一般是主分支。origin/dev 开发分支,origin/zhangsan 开发者张三的分支 都应该复制master,基于master进行开发迭代
    spring aop获取方法上与类上的注解
    自定义的异常类,用instanceof判断类型错误
  • 原文地址:https://www.cnblogs.com/zlt2000/p/15921490.html
Copyright © 2020-2023  润新知