Hyperledger Fabric架构及Java SDK实现

Hyperledger Fabric 整理体系:

运行时架构

运行时架构

各项解释如下:

  • APP:代表一个客户端或者SDK,作用是创建交易并获取到足够的背书之后向Orderer排序服务节点提交交易请求。(peer和orderer提供了gRPC远程访问接口,供客户端调用)
  • CA:负责对网络中所有证书进行管理,提供标准的KPI服务
  • MSP:为客户端和peer提供证书的系统抽象组件
  • Channel:通道提供了一种通讯机制,将peers和orderer连接在一起,形成一个具有保密性的通讯链路;将一个大网络分割成不同私有子网,进行数据隔离
  • Orderer:对客户端提交的交易请求进行排序,之后生成区块广播给通道内所有peer节点
  • Org1:代表联盟中的某-组织
  • Peer:表示组织中的节点;peer节点以区块的形式从orderer排序服务节点接收有序状态更新,维护状态和账本。fabric中Peer节点可划分如下:
    1. Endorsing Peer:根据指定的策略调用智能合约,对结果进行背书,返回提案相应到客户端
    2. Committing Peer:验证数据并保存到账本中
    3. Anchor Peer:跨组织通讯
    4. Leading Peer:做为组织内所有节点的代表连接到Orderer排序服务节点,将从排序服务节点接收到的批量区块广播给组织内的其他节点
  • Chaincode:链码,部署在fabric的网络节点中,独立运行在具有安全特性的受保护容器中,以gRPC协议与相应Peer节点进行通讯,提供相应的API与账本数据进行交互
  • Ledger:有排序服务构建的一个全部有序的交易哈希链块,保存在所有的Peer节点中。

 Java SDK提供了一种执行用户链码,查询块数据,在通道进行交易及模拟事件的方式。
 此模式下,区块链网络由两个组织,每个组织包含两个结点,和一个order服务;将展示怎样创建和初始化通道,安装和部署链码,和执行调用和查询操作。


fabric network
基本原理

 在fabric区块链中,应用通过结点RPC协议接口访问链码。


基本流程

 类似于Shim API对链码通讯协议的封装,JavaSDK提供了对结点RPC协议接口封装,其入口类为HFClient;对链码的交易和查询操作则封装在channel类中。


基本流程 - 类说明
简单实例
  • 实现User接口
     HFClient访问fabric网络身份使用User接口实现。
     一个用户的身份由它的证书来标识的,同时交易还需要证书对应的私钥,因此LocalUser的核心逻辑就是利用指定的证书和私钥PEM文件满足User接口的要求。

    User类实现

  • 访问链码
     创建HFClient实例,然后获取通道对象,就可以查询链码或者提交链码交易。

命令行操作: hyperledger fabric byfn up详解
代码具体实现
  • 运行fabric-samples中fabcar,创建区块链网络
  • 新建Java工程,引入fabric-gateway-java,实现具体实现
    pom.xml
    <repositories>
        <repository>
            <id>oss-sonatype</id>
            <name>OSS Sonatype</name>
            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.hyperledger.fabric</groupId>
            <artifactId>fabric-gateway-java</artifactId>
            <version>1.4.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

加入Admins角色:

public class EnrollAdmin {

    static {
        System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
    }

    public static void main(String[] args) throws Exception {

        // Create a CA client for interacting with the CA.
        Properties props = new Properties();
        props.put("pemFile",
            "/Users/macserver/Documents/BlockChain/src/github.com/hyperledger/fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem");
        props.put("allowAllHostNames", "true");
        HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props);
        CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
        caClient.setCryptoSuite(cryptoSuite);

        // Create a wallet for managing identities
        Wallet wallet = Wallet.createFileSystemWallet(Paths.get("wallet"));

        // Check to see if we've already enrolled the admin user.
        boolean adminExists = wallet.exists("admin");
        if (adminExists) {
            System.out.println("An identity for the admin user \"admin\" already exists in the wallet");
            return;
        }

        // Enroll the admin user, and import the new identity into the wallet.
        final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();
        enrollmentRequestTLS.addHost("localhost");
        enrollmentRequestTLS.setProfile("tls");
        Enrollment enrollment = caClient.enroll("admin", "adminpw", enrollmentRequestTLS);
        Identity user = Identity.createIdentity("Org1MSP", enrollment.getCert(), enrollment.getKey());
        wallet.put("admin", user);
        System.out.println("Successfully enrolled user \"admin\" and imported it into the wallet");
    }
}

加入user1角色:

public class RegisterUser {

    static {
        System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
    }

    public static void main(String[] args) throws Exception {

        // Create a CA client for interacting with the CA.
        Properties props = new Properties();
        props.put("pemFile",
            "/Users/macserver/Documents/BlockChain/src/github.com/hyperledger/fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem");
        props.put("allowAllHostNames", "true");
        HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props);
        CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
        caClient.setCryptoSuite(cryptoSuite);

        // Create a wallet for managing identities
        Wallet wallet = Wallet.createFileSystemWallet(Paths.get("wallet"));

        // Check to see if we've already enrolled the user.
        boolean userExists = wallet.exists("user1");
        if (userExists) {
            System.out.println("An identity for the user \"user1\" already exists in the wallet");
            return;
        }

        userExists = wallet.exists("admin");
        if (!userExists) {
            System.out.println("\"admin\" needs to be enrolled and added to the wallet first");
            return;
        }

        Identity adminIdentity = wallet.get("admin");
        User admin = new User() {

            @Override
            public String getName() {
                return "admin";
            }

            @Override
            public Set<String> getRoles() {
                return null;
            }

            @Override
            public String getAccount() {
                return null;
            }

            @Override
            public String getAffiliation() {
                return "org1.department1";
            }

            @Override
            public Enrollment getEnrollment() {
                return new Enrollment() {

                    @Override
                    public PrivateKey getKey() {
                        return adminIdentity.getPrivateKey();
                    }

                    @Override
                    public String getCert() {
                        return adminIdentity.getCertificate();
                    }
                };
            }

            @Override
            public String getMspId() {
                return "Org1MSP";
            }

        };

        // Register the user, enroll the user, and import the new identity into the wallet.
        RegistrationRequest registrationRequest = new RegistrationRequest("user1");
        registrationRequest.setAffiliation("org1.department1");
        registrationRequest.setEnrollmentID("user1");
        String enrollmentSecret = caClient.register(registrationRequest, admin);
        Enrollment enrollment = caClient.enroll("user1", enrollmentSecret);
        Identity user = Identity.createIdentity("Org1MSP", enrollment.getCert(), enrollment.getKey());
        wallet.put("user1", user);
        System.out.println("Successfully enrolled user \"user1\" and imported it into the wallet");
    }

}

客户端:查询及添加新数据

public class ClientApp {

    static {
        System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
    }

    public static void main(String[] args) throws Exception {
        // Load a file system based wallet for managing identities.
        Path walletPath = Paths.get("wallet");
        Wallet wallet = Wallet.createFileSystemWallet(walletPath);

        // load a CCP
        Path networkConfigPath = Paths.get("/Users/macserver/Documents/BlockChain/src/github.com/hyperledger/fabric-samples/fabcar", "..", "first-network", "connection-org1.yaml");

        Gateway.Builder builder = Gateway.createBuilder();
        builder.identity(wallet, "user1").networkConfig(networkConfigPath).discovery(true);

        // create a gateway connection
        try (Gateway gateway = builder.connect()) {

            // get the network and contract
            Network network = gateway.getNetwork("mychannel");
            Contract contract = network.getContract("fabcar");

            byte[] result;

            result = contract.evaluateTransaction("queryAllCars");
            System.out.println(new String(result));

            contract.submitTransaction("createCar", "CAR10", "VW", "Polo", "Grey", "Mary");

            result = contract.evaluateTransaction("queryCar", "CAR10");
            System.out.println(new String(result));

            contract.submitTransaction("changeCarOwner", "CAR10", "Archie");

            result = contract.evaluateTransaction("queryCar", "CAR10");
            System.out.println(new String(result));
        }
    }

}
实现方式 二

 如果跳过gateway,直接使用fabric-sdk-java,数据查询-实现代码如下:

private static void queryAllCars() throws Exception {
        HFClient hfClient = HFClient.createNewInstance();

        CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
        hfClient.setCryptoSuite(cryptoSuite);

        Enrollment enrollment = new X509Enrollment(getPrivateKey(Paths.get("wallet/user1/user1-priv")), getCertificate(certificate_user1));
        User user = new User() {
            @Override
            public String getName() {
                return "gateway";
            }

            @Override
            public Set<String> getRoles() {
                return Collections.emptySet();
            }

            @Override
            public String getAccount() {
                return "";
            }

            @Override
            public String getAffiliation() {
                return "";
            }

            @Override
            public Enrollment getEnrollment() {
                return enrollment;
            }

            @Override
            public String getMspId() {
                return "Org1MSP";
            }
        };

        hfClient.setUserContext(user);

        NetworkConfig networkConfig = NetworkConfig.fromYamlFile(new File(path + "first-network/connection-org1.yaml"));

        Channel channel = hfClient.newChannel("mychannel");

        List<String> peerNames = networkConfig.getClientOrganization().getPeerNames();
        for (String name : peerNames) {
            String url = networkConfig.getPeerUrl(name);
            Properties props = networkConfig.getPeerProperties(name);
            System.err.println("xxxxxxxxx:" + name + "..." + url);
            Peer peer = hfClient.newPeer(name, url, props);

            Channel.PeerOptions peerOptions = Channel.PeerOptions.createPeerOptions().setPeerRoles(EnumSet.allOf(Peer.PeerRole.class));
            channel.addPeer(peer, peerOptions);
        }

        channel.initialize();


        QueryByChaincodeRequest request = QueryByChaincodeRequest.newInstance(user);

        request.setChaincodeID(getChaincodeId("fabcar"));
        request.setFcn("queryAllCars");
        request.setArgs("");

        Collection<ProposalResponse> responses = channel.queryByChaincode(request, Collections.singletonList(channel.getPeers().iterator().next()));
        ProposalResponse response = responses.iterator().next();
        byte[] bytes = response.getChaincodeActionResponsePayload();

        System.err.println("xxxxxxx:" + new String(bytes));
    }
    private static String getCertificate(String certificate) {
        BufferedReader certReader = new BufferedReader(new StringReader(certificate));
        return certReader.lines().collect(Collectors.joining("\n", "", "\n"));
    }

    private static PrivateKey getPrivateKey(Path pemFile) {
        try {
            PEMParser parser = new PEMParser(Files.newBufferedReader(pemFile));
            Object key = parser.readObject();
            JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
            return converter.getPrivateKey((PrivateKeyInfo) key);
        } catch (IOException e) {
            System.err.println("private key 获取失败");
            return null;
        }
    }

    private static ChaincodeID getChaincodeId(String chaincodeId) {
        return ChaincodeID.newBuilder()
                .setName(chaincodeId)
                .build();
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容