美文网首页
Fabric-sdk-java调试跑通

Fabric-sdk-java调试跑通

作者: Tan_Cc | 来源:发表于2019-03-12 20:43 被阅读0次
    环境准备
    1. JDK 1.8+
    2. Apache Maven
    3. IDEA / eclipse
    下载项目
    git clone https://github.com/hyperledger/fabric-sdk-java
    
    运行Fabric环境
    cd fabric-sdk-java/src/test/fixture/sdkintegration
    ./fabric.sh up
    

    运行结果


    fabric-up.png
    导入项目

    由于选择的是eclipse,所以一直无法配置好依赖,使得一直没有能够成功导入项目,最后放弃选择使用IDEA,IDEA导入maven项目后,只需安装protobuf support,再进行complie即可,这里就不详述了。

    运行测试Demo——End2endIT.java

    运行结果分析

    1. 先构建通道foo,把org1加入该通道,运行该通道

    run-channel.png
    1. 初始化a为100,b为200,并把此交易送至orderer中

    set-a-b.png
    1. a转账100给b,背书后,把交易送至orderer

    a-100to-b.png
    1. 查询b的值

    query-b.png
    1. 后面就是创建调用另一个通道bar,进行相同的操作,这里也不详细罗列了
    End2endIT源码分析(注释都在代码中)
    1. 先执行checkConfig()方法检查配置项
        @Before
        public void checkConfig() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, MalformedURLException, org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException {
            out("\n\n\nRUNNING: %s.\n", testName);
            resetConfig();//先重置配置文件org.hyperledger.fabric.sdk.helper.Config,config主要是fabric需要的配置项
            configHelper.customizeConfig();//调用命令行输入的指定变量,覆盖掉上面的Config配置
    
            testSampleOrgs = testConfig.getIntegrationTestsSampleOrgs();//获取testConfig配置的组织,TestConfig在End2endIT已经被new出来,里面也有大量的测试配置项
            for (SampleOrg sampleOrg : testSampleOrgs) {//设置颁发证书的CA证书机构
                String caName = sampleOrg.getCAName(); 
                if (caName != null && !caName.isEmpty()) {
                    sampleOrg.setCAClient(HFCAClient.createNewInstance(caName, sampleOrg.getCALocation(), sampleOrg.getCAProperties()));
                } else {
                    sampleOrg.setCAClient(HFCAClient.createNewInstance(sampleOrg.getCALocation(), sampleOrg.getCAProperties()));
                }
            }
        }
    
    1. 执行setup()方法
        @Test
        public void setup() throws Exception {
            if (sampleStoreFile.exists()) {
                sampleStoreFile.delete();//模拟数据库存储使用了HFCSampletest.properties
            }
            sampleStore = new SampleStore(sampleStoreFile);//初始化存储
            enrollUsersSetup(sampleStore);// 利用ca做初始化
            runFabricTest(sampleStore);//核心方法
    
        }
    
    1. 分析enrollUsersSetup()方法
        for (SampleOrg sampleOrg : testSampleOrgs) {
    
                HFCAClient ca = sampleOrg.getCAClient();//获得ca客户端
    
                final String orgName = sampleOrg.getName();//组织名称
                final String mspid = sampleOrg.getMSPID();//组织证书ID
                ca.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());//设置CA客户端证书套件
    
                if (testConfig.isRunningFabricTLS()) {
                    //从CA客户端获取TLS证书
                    final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();
                    enrollmentRequestTLS.addHost("localhost");
                    enrollmentRequestTLS.setProfile("tls");
                    final Enrollment enroll = ca.enroll("admin", "adminpw", enrollmentRequestTLS);
                    final String tlsCertPEM = enroll.getCert();
                    final String tlsKeyPEM = getPEMStringFromPrivateKey(enroll.getKey());
    
                    final Properties tlsProperties = new Properties();
    
                    tlsProperties.put("clientKeyBytes", tlsKeyPEM.getBytes(UTF_8));
                    tlsProperties.put("clientCertBytes", tlsCertPEM.getBytes(UTF_8));
                    clientTLSProperties.put(sampleOrg.getName(), tlsProperties);
    
                    sampleStore.storeClientPEMTLCertificate(sampleOrg, tlsCertPEM);
                    sampleStore.storeClientPEMTLSKey(sampleOrg, tlsKeyPEM);
                }
                //检查是否连接成功
                HFCAInfo info = ca.info();
                assertNotNull(info);
                String infoName = info.getCAName();
                if (infoName != null && !infoName.isEmpty()) {
                    assertEquals(ca.getCAName(), infoName);
                }
                //获取组织管理员(admin)
                SampleUser admin = sampleStore.getMember(TEST_ADMIN_NAME, orgName);
                if (!admin.isEnrolled()) { 
                    //管理员只需在CA客户端进行登记
                    admin.setEnrollment(ca.enroll(admin.getName(), "adminpw"));
                    admin.setMspId(mspid);
                }
                //获取普通用户
                SampleUser user = sampleStore.getMember(testUser1, sampleOrg.getName());
                if (!user.isRegistered()) { 
                    //如果未注册则生成注册请求
                    RegistrationRequest rr = new RegistrationRequest(user.getName(), "org1.department1");
                    //设置密码(注册请求发出去后,CA会返回一个密码)
                    user.setEnrollmentSecret(ca.register(rr, admin));
                }
                if (!user.isEnrolled()) {
                    //如果未登记则登记
                    user.setEnrollment(ca.enroll(user.getName(), user.getEnrollmentSecret()));
                    user.setMspId(mspid);
                }
    
                final String sampleOrgName = sampleOrg.getName();
                final String sampleOrgDomainName = sampleOrg.getDomainName();//获取组织的命名域
                //使用证书文件生成用户信息
                SampleUser peerOrgAdmin = sampleStore.getMember(sampleOrgName + "Admin", sampleOrgName, sampleOrg.getMSPID(),
                        Util.findFileSk(Paths.get(testConfig.getTestChannelPath(), "crypto-config/peerOrganizations/",
                                sampleOrgDomainName, format("/users/Admin@%s/msp/keystore", sampleOrgDomainName)).toFile()),
                        Paths.get(testConfig.getTestChannelPath(), "crypto-config/peerOrganizations/", sampleOrgDomainName,
                                format("/users/Admin@%s/msp/signcerts/Admin@%s-cert.pem", sampleOrgDomainName, sampleOrgDomainName)).toFile());
              
                sampleOrg.setPeerAdmin(peerOrgAdmin);//设置节点管理员(一个特殊的用户,可以创建通道,加入节点以及安装链码)
    
                sampleOrg.addUser(user);//组织内添加用户
                sampleOrg.setAdmin(admin); //设置管理员身份
            }
    
    1. 分析 runFabricTest()方法
            ////////////////////////////
            // Setup client
    
            //Create instance of client.
            HFClient client = HFClient.createNewInstance();//初始化一个客户端,类似cli
    
            client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());//设置加密算法
    
            ////////////////////////////
            //Construct and run the channels
            // 获取peerOrg1组织1
            SampleOrg sampleOrg = testConfig.getIntegrationTestsSampleOrg("peerOrg1");
            // 构建一个channel通道,Org1加入到该通道中
            Channel fooChannel = constructChannel(FOO_CHANNEL_NAME, client, sampleOrg);
            // 保存通道名称到数据库中(这里是存储到上面方法文件)
            sampleStore.saveChannel(fooChannel);
            // 安装链码、实例化链码、执行一个查询测试
            runChannel(client, fooChannel, true, sampleOrg, 0);
    
            assertFalse(fooChannel.isShutdown());
            fooChannel.shutdown(true); // Force foo channel to shutdown clean up resources.
            assertTrue(fooChannel.isShutdown());
    
            assertNull(client.getChannel(FOO_CHANNEL_NAME));
            out("\n");
            // 下面是组织2的过程,跟组织1是类似的
            sampleOrg = testConfig.getIntegrationTestsSampleOrg("peerOrg2");
            Channel barChannel = constructChannel(BAR_CHANNEL_NAME, client, sampleOrg);
            assertTrue(barChannel.isInitialized());
            /**
             * sampleStore.saveChannel uses {@link Channel#serializeChannel()}
             */
            sampleStore.saveChannel(barChannel);
            assertFalse(barChannel.isShutdown());
            runChannel(client, barChannel, true, sampleOrg, 100); //run a newly constructed bar channel with different b value!
            //let bar channel just shutdown so we have both scenarios.
    
            out("\nTraverse the blocks for chain %s ", barChannel.getName());
            // 对区块进行各种查询,包括区块读写集、区块数量高度等
            blockWalker(client, barChannel);
    
            assertFalse(barChannel.isShutdown());
            assertTrue(barChannel.isInitialized());
            out("That's all folks!");
    
    
    1. 分析constructChannel()方法(重点1)

    a. 获取peer的admin用户,实际上是crytogen根据crypto-config.yaml配置的默认admin账户

            SampleUser peerAdmin = sampleOrg.getPeerAdmin();
            client.setUserContext(peerAdmin);
    

    b. 接着是初始化orderer排序节点对象

            Collection<Orderer> orderers = new LinkedList<>();
    
            for (String orderName : sampleOrg.getOrdererNames()) {
    
                Properties ordererProperties = testConfig.getOrdererProperties(orderName);
    
                //example of setting keepAlive to avoid timeouts on inactive http2 connections.
                // Under 5 minutes would require changes to server side to accept faster ping rates.
                ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] {5L, TimeUnit.MINUTES});
                ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});
                ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveWithoutCalls", new Object[] {true});
    
                orderers.add(client.newOrderer(orderName, sampleOrg.getOrdererLocation(orderName),
                        ordererProperties));
            }
    

    c. 创建一个channel,这里使用的是Configtxgen 生成的“通道配置”文件

    //Just pick the first orderer in the list to create the channel. 
      Orderer anOrderer = orderers.iterator().next();//选择第一个排序节点进行创建通道 
      orderers.remove(anOrderer); //从排序节点集合中移除已经在使用的节点
    
    //通过读取channel.tx文件,生成信道配置对象 
      ChannelConfiguration channelConfiguration = new ChannelConfiguration(new File(TEST_FIXTURES_PATH + "/sdkintegration/e2e-2Orgs/channel/" + name + ".tx")); 
    
    //创建信道对象,只有一个签名,就是组织节点管理员。如果创建信道策略需要更多的签名,那么他们必须添加
      Channel newChannel = client.newChannel(name, anOrderer, channelConfiguration, client.getChannelConfigurationSignature(channelConfiguration, sampleOrg.getPeerAdmin()));
      out("Created channel %s", name);
    

    d. client.newPeer创建peer节点,然后joinPeer加入通道channel中

        boolean everyother = true; //test with both cases when doing peer eventing.
            for (String peerName : sampleOrg.getPeerNames()) {
                String peerLocation = sampleOrg.getPeerLocation(peerName);//获取节点位置
    
                Properties peerProperties = testConfig.getPeerProperties(peerName); //获取节点属性
                if (peerProperties == null) {
                    peerProperties = new Properties();
                }
    
                //Example of setting specific options on grpc's NettyChannelBuilder
                peerProperties.put("grpc.NettyChannelBuilderOption.maxInboundMessageSize", 9000000);
    
                Peer peer = client.newPeer(peerName, peerLocation, peerProperties);//通过客户端生成节点对象
                if (testConfig.isFabricVersionAtOrAfter("1.3")) {
                    //加入生成的节点
                    newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.ENDORSING_PEER, PeerRole.LEDGER_QUERY, PeerRole.CHAINCODE_QUERY, PeerRole.EVENT_SOURCE))); //Default is all roles.
    
                } else {
                    if (doPeerEventing && everyother) {
                        newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.ENDORSING_PEER, PeerRole.LEDGER_QUERY, PeerRole.CHAINCODE_QUERY, PeerRole.EVENT_SOURCE))); //Default is all roles.
                    } else {
                        // Set peer to not be all roles but eventing.
                        newChannel.joinPeer(peer, createPeerOptions().setPeerRoles(EnumSet.of(PeerRole.ENDORSING_PEER, PeerRole.LEDGER_QUERY, PeerRole.CHAINCODE_QUERY)));
                    }
                }
                out("Peer %s joined channel %s", peerName, name);
                everyother = !everyother;
            }
    

    e. 给channel设置监听事件的grpc接口,最后进行初始化

        //获取组织内事件记录节点集合
        for (String eventHubName : sampleOrg.getEventHubNames()) {
                //获取事件记录属性
                final Properties eventHubProperties = testConfig.getEventHubProperties(eventHubName);
    
                eventHubProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] {5L, TimeUnit.MINUTES});
                eventHubProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});
    
                EventHub eventHub = client.newEventHub(eventHubName, sampleOrg.getEventHubLocation(eventHubName),
                        eventHubProperties);
                newChannel.addEventHub(eventHub);
            }
            //信道实例化
            newChannel.initialize();
    
            out("Finished initialization channel %s", name);
    
    1. 分析runChannel()方法(重点2

    a. 安装链码

            if (installChaincode) {
    
                   //一大段设置安装的链码信息
                   // .......
                   //发送安装链码的交易提案
                    responses = client.sendInstallProposal(installProposalRequest, peers);
    
                   //检查返回的结果,并输出相应的信息
                   //.......
    

    b. 实例化链码,设置背书策略

                //实例化链码
                InstantiateProposalRequest instantiateProposalRequest = client.newInstantiationProposalRequest();
                instantiateProposalRequest.setProposalWaitTime(DEPLOYWAITTIME);
                instantiateProposalRequest.setChaincodeID(chaincodeID);
                instantiateProposalRequest.setChaincodeLanguage(CHAIN_CODE_LANG);
                instantiateProposalRequest.setFcn("init");
                instantiateProposalRequest.setArgs(new String[] {"a", "500", "b", "" + (200 + delta)});
                Map<String, byte[]> tm = new HashMap<>();
                tm.put("HyperLedgerFabric", "InstantiateProposalRequest:JavaSDK".getBytes(UTF_8));
                tm.put("method", "InstantiateProposalRequest".getBytes(UTF_8));
                instantiateProposalRequest.setTransientMap(tm);
    
                /*
                  policy OR(Org1MSP.member, Org2MSP.member) meaning 1 signature from someone in either Org1 or Org2
                  See README.md Chaincode endorsement policies section for more details.
                */
                //设置背书策略
                ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy();
                chaincodeEndorsementPolicy.fromYamlFile(new File(TEST_FIXTURES_PATH + "/sdkintegration/chaincodeendorsementpolicy.yaml"));
                instantiateProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy);
    
                out("Sending instantiateProposalRequest to all peers with arguments: a and b set to 100 and %s respectively", "" + (200 + delta));
                successful.clear();
                failed.clear();
    
                //检查结果,并输出相应信息
    

    c. 转账,查询,异常处理

    channel.sendTransaction(successful, createTransactionOptions()
                        .userContext(client.getUserContext())
                        .shuffleOrders(false)
                        .orderers(channel.getOrderers())
                        .nOfEvents(nOfEvents)
                ).thenApply(transactionEvent -> {
                //.......
                // 调用example_cc.go里面的move方法,a给b转账
    
    }.thenApply(transactionEvent -> {
                        //........
                        // query查询b的余额
    
                    try {
    }).exceptionally(e -> {
                        //........
                        // 异常处理
    }
    

    d. 查询区块高度,信息之类的

    总结

    因时间有限,还并没有开始搭建自己的调用逻辑,之后会开始尝试。

    相关文章

      网友评论

          本文标题:Fabric-sdk-java调试跑通

          本文链接:https://www.haomeiwen.com/subject/cheizftx.html