5.Fabric v2.0 java-sdk 根据TXID查询区块并从区块解析数据

根据TXID查询数据

本文是在fabric-sdk-java 成功添加区块并自定义查询的基础上, 实现通过txid查询数据; 由于fabric-sdk-java 的示例网络上比较多, 我是根据 github上的demo 开发的,只实现了添加数据,和查询功能.
demo fabric-sdk-java-demo的下载地址:

github 下载地址
码云 下载地址
以下的解析只是符合我自己的需求,下面是官方源码的位置截图,源码过多我就不贴了
fabric-sdk-java的源码下载地址:
下载地址(github)
下载地址(码云)
在这里插入图片描述


解析时需要用的常量和方法
    static String printableString(String string) {
    
    
        if (StringUtils.isBlank(string)) {
    
    
            return null;
        }
        return string.replaceAll("[^\\p{Print}]", "?");
    }
    Map<String, Long> expectedMoveRCMap = new HashMap<>();
    private static final byte[] EXPECTED_EVENT_DATA = "!".getBytes(UTF_8);
    private static final String EXPECTED_EVENT_NAME = "event";
    private static final Map<String, String> TX_EXPECTED;
    static {
    
    
        TX_EXPECTED = new HashMap<>();
        TX_EXPECTED.put("readset1", "Missing readset for channel bar block 1");
        TX_EXPECTED.put("writeset1", "Missing writeset for channel bar block 1");
    }

正式解析区块之前, 要说明一下;
channel 需要自己获取,由于我进行了封装,所以不方便展示,另外 代码中使用的 fabricconfig是配置文件,获取的是 channel名称和 chaincode链码名称

    @Override
    public ResultJson<List<JSONObject>> queryFromBlockByTxId(String txid) throws Exception {
    
    
        // 获取通道配置
        if (this.channel == null) {
    
    
            getChannel();
        }

        /**
         * 通过txid 获取区块信息
         */
        BlockInfo blockInfo = this.channel.queryBlockByTransactionID(txid);
        if (blockInfo == null) {
    
    
            return new ResultJson<>(ResultCode.TXID_NOT_EXIST);
        }

        long blockNumber = blockInfo.getBlockNumber();
        log.info("当前区块编号:{} 数据hash ={}", blockNumber, Hex.encodeHexString(blockInfo.getDataHash()));
        log.info("当前区块编号:{} 前块hash = {}", blockNumber, Hex.encodeHexString(blockInfo.getPreviousHash()));

        // 如果一个通道内有多个链码,就不能通过索引获取了 ---  个人分析未论证
//        BlockInfo.EnvelopeInfo tmp = blockInfo.getEnvelopeInfo(0);
//        String channelId1 = tmp.getChannelId();
//        System.out.println(channelId1);

        Iterable<BlockInfo.EnvelopeInfo> envelopeInfos = blockInfo.getEnvelopeInfos();
        List<JSONObject> list = new ArrayList<>();
        for (BlockInfo.EnvelopeInfo envelopeInfo :envelopeInfos) {
    
    
            // 从区块中获取channelId = mychannel
            final String channelId = envelopeInfo.getChannelId();
            log.info("   通道 id: {}", channelId);

            /**
             * 判断不是指定通道名称,则跳过
             */
            if (!channelId.equals(fabricConfig.getChannelName())) {
    
    
                log.error("通道名称不正确跳过,配置通道id= {},获取的通道id = {}", fabricConfig.getChannelName(), channelId);
                continue;
            }

            /**
             * 获取落块时间
             */
            String time = TimeUtil.parseToyyyyMMddmmssSSS(envelopeInfo.getTimestamp());
            log.info(" 时间: {}", time);

            // 需要定位是组织内的哪个节点
            log.info("  提交事务的身份: {}", envelopeInfo.getCreator().getMspid());
            if (envelopeInfo.getType() != TRANSACTION_ENVELOPE) {
    
    
                log.error("envelopeInfo的type值不正确,常量 ={} 解析 ={}", TRANSACTION_ENVELOPE, envelopeInfo.getType());
                continue;
            }
            // 强转类型
            BlockInfo.TransactionEnvelopeInfo transactionEnvelopeInfo = (BlockInfo.TransactionEnvelopeInfo) envelopeInfo;
            log.info("   是否经过校验 {}", transactionEnvelopeInfo.isValid());

            // 获取操作事务的信息
            for (BlockInfo.TransactionEnvelopeInfo.TransactionActionInfo transactionActionInfo : transactionEnvelopeInfo.getTransactionActionInfos()) {
    
    

                // 链码名称
                String chaincodeIDName = transactionActionInfo.getChaincodeIDName();
                // 链码版本
                String chaincodeIDVersion = transactionActionInfo.getChaincodeIDVersion();
                log.info("  proposal chaincodeIDName:{}, chaincodeIDVersion: {}", chaincodeIDName, chaincodeIDVersion);

                // 操作事务的读写集
                TxReadWriteSetInfo rwsetInfo = transactionActionInfo.getTxReadWriteSet();

                if (null != rwsetInfo) {
    
    
                    //我只要了写集合的数据
                    for (TxReadWriteSetInfo.NsRwsetInfo nsRwsetInfo : rwsetInfo.getNsRwsetInfos()) {
    
    
                        // 含有默认链码 _lifecycle  和 自定义链码 mycc
                        String namespace = nsRwsetInfo.getNamespace();
                        // 只要符合要求的链码的 mycc
                        if (!namespace.equals(fabricConfig.getChainCodeName())) {
    
    
                            log.error("链码名称不正确 跳过 ,namespace ={} fabricConfig.getChainCodeName() ={}", namespace, fabricConfig.getChainCodeName());
                            continue;
                        }
                        KvRwset.KVRWSet rws = nsRwsetInfo.getRwset();
                        for (KvRwset.KVWrite writeList : rws.getWritesList()) {
    
    
                            String valAsString = printableString(new String(writeList.getValue().toByteArray(), UTF_8));
                            log.info("Namespace {}  key {} has value '{}' ", namespace, writeList.getKey(), valAsString);
                            if (StringUtils.isNotBlank(valAsString)) {
    
    
                                list.add(JSON.parseObject(valAsString, JSONObject.class));
                            }

                        }
                    }
                }
            }
        }


        return new ResultJson<List<JSONObject>>(ResultCode.OK, list);
    }

猜你喜欢

转载自blog.csdn.net/weixin_41540016/article/details/108661530