Hyperledger Fabric 2.x Java區(qū)塊鏈應用

file

一、說明

在上一篇文章中 《Hyperledger Fabric 2.x 自定義智能合約》 分享了智能合約的安裝并使用 cli 客戶端進行合約的調(diào)用淘菩;本文將使用 Java 代碼基于 fabric-gateway-java 進行區(qū)塊鏈網(wǎng)絡的訪問與交易,并集成 SpringBoot 框架忧换。

Fabric Gateway SDK 實現(xiàn)Fabric的編程模型,提供了一系列簡單的API給應用程序與Fabric區(qū)塊鏈網(wǎng)絡進行交互向拆;

網(wǎng)絡拓撲圖:

file

應用程序?qū)⒏髯缘木W(wǎng)絡交互委托給其網(wǎng)關(guān)亚茬,每個網(wǎng)關(guān)都了解網(wǎng)絡信道拓撲,包括組織的多個Peer節(jié)點和排序節(jié)點浓恳,使應用程序?qū)W⒂跇I(yè)務邏輯刹缝;Peer節(jié)點可以使用gossip協(xié)議在組織內(nèi)部和組織之間相互通信。

?

二奖蔓、Mavn依賴

添加網(wǎng)關(guān)sdk的依賴:

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

?

三赞草、準備配置文件

工程的目錄結(jié)構(gòu)如下圖所示:

file

?

3.1. 準備網(wǎng)絡證書

創(chuàng)建目錄 crypto-configordererpeer 節(jié)點的證書文件復制進來。

證書文件從 fabric-samplestest-network 目錄中復制 ordererOrganizationspeerOrganizations 文件夾:

file

?

3.2. 創(chuàng)建網(wǎng)絡配置

創(chuàng)建文件 connection.json 內(nèi)容如下:

{
    "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中的地址吆鹤,內(nèi)容中分別包含了 channels厨疙、organizationsorderers疑务、peers沾凄、ca 的配置

?

3.3. SpringBoot配置

application.yml 中添加以下內(nèi)容,用于訪問網(wǎng)關(guān)的相關(guān)配置:

fabric:
  # wallet文件夾路徑(自動創(chuàng)建)
  walletDirectory: wallet
  # 網(wǎng)絡配置文件路徑
  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

?

四知允、連接合約

分別構(gòu)建網(wǎng)關(guān)撒蟀、通道和合約的Bean對象,代碼如下:

/**
 * 連接網(wǎng)關(guān)
 */
@Bean
public Gateway connectGateway() throws IOException, InvalidKeyException, CertificateException {
        //使用org1中的user1初始化一個網(wǎng)關(guān)wallet賬戶用于連接網(wǎng)絡
        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));

        //根據(jù)connection.json 獲取Fabric網(wǎng)絡連接對象
        Gateway.Builder builder = Gateway.createBuilder()
                        .identity(wallet, username)
                        .networkConfig(Paths.get(this.networkConfigPath));

        //連接網(wǎng)關(guān)
        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);
}

?

五温鸽、合約調(diào)用

創(chuàng)建controller類保屯,注入Contract對象調(diào)用合約方法:

@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;
}

?

六、測試接口

調(diào)用接口 getUser

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

返回:

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

?

調(diào)用接口 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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末姑尺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蝠猬,更是在濱河造成了極大的恐慌切蟋,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榆芦,死亡現(xiàn)場離奇詭異柄粹,居然都是意外死亡,警方通過查閱死者的電腦和手機匆绣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門驻右,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人崎淳,你說我怎么就攤上這事旺入。” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵茵瘾,是天一觀的道長礼华。 經(jīng)常有香客問我,道長拗秘,這世上最難降的妖魔是什么圣絮? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮雕旨,結(jié)果婚禮上扮匠,老公的妹妹穿的比我還像新娘。我一直安慰自己凡涩,他們只是感情好棒搜,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著活箕,像睡著了一般力麸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上育韩,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天克蚂,我揣著相機與錄音,去河邊找鬼筋讨。 笑死埃叭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的悉罕。 我是一名探鬼主播赤屋,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼壁袄!你這毒婦竟也來了益缎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤然想,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后欣范,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體变泄,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年恼琼,在試婚紗的時候發(fā)現(xiàn)自己被綠了妨蛹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡晴竞,死狀恐怖蛙卤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤颤难,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布神年,位于F島的核電站,受9級特大地震影響行嗤,放射性物質(zhì)發(fā)生泄漏已日。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一栅屏、第九天 我趴在偏房一處隱蔽的房頂上張望飘千。 院中可真熱鬧,春花似錦栈雳、人聲如沸护奈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霉旗。三九已至,卻和暖如春磺箕,著一層夾襖步出監(jiān)牢的瞬間奖慌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工松靡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留简僧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓雕欺,卻偏偏與公主長得像岛马,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子屠列,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容