代碼html
'use strict'; var Fabric_Client = require('fabric-client'); var path = require('path'); var util = require('util'); var os = require('os'); var fabric_client = new Fabric_Client(); // 設置fabric網絡 var channel = fabric_client.newChannel('mychannel'); var peer = fabric_client.newPeer('grpc://localhost:7051'); channel.addPeer(peer); // var member_user = null; var store_path = path.join(__dirname, 'hfc-key-store'); console.log('Store path:'+store_path); var tx_id = null; var query =async (fcn,args)=>{ try { // create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting var state_store = await Fabric_Client.newDefaultKeyValueStore({path: store_path}); // assign the store to the fabric client fabric_client.setStateStore(state_store); var crypto_suite = Fabric_Client.newCryptoSuite(); // use the same location for the state store (where the users' certificate are kept) // and the crypto store (where the users' keys are kept) var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path}); crypto_suite.setCryptoKeyStore(crypto_store); fabric_client.setCryptoSuite(crypto_suite); // get the enrolled user from persistence, this user will sign all requests var user_from_store = await fabric_client.getUserContext('user1', true); if (user_from_store && user_from_store.isEnrolled()) { console.log('Successfully loaded user1 from persistence'); member_user = user_from_store; } else { throw new Error('Failed to get user1.... run registerUser.js'); } // queryCar chaincode function - requires 1 argument, ex: args: ['CAR4'], // queryAllCars chaincode function - requires no arguments , ex: args: [''], const request = { //targets : --- letting this default to the peers assigned to the channel chaincodeId: 'fabcar', fcn: fcn, args: args }; // send the query proposal to the peer var query_responses = await channel.queryByChaincode(request); console.log("Query has completed, checking results"); // query_responses could have more than one results if there multiple peers were used as targets if (query_responses && query_responses.length == 1) { if (query_responses[0] instanceof Error) { console.error("error from query = ", query_responses[0]); } else { console.log("Response is ", query_responses[0].toString()); } } else { console.log("No payloads were returned from query"); } }catch (err){ console.error('Failed to query successfully :: ' + err); } }; console.log(process.argv[2]); console.log(process.argv[3]); var args = new Array(process.argv[3]); query(process.argv[2],args);
const express = require('express') const app = express() var Fabric_Client = require('fabric-client'); var path = require('path'); var util = require('util'); var os = require('os'); var fabric_client = new Fabric_Client(); // 設置fabric網絡 var channel = fabric_client.newChannel('mychannel'); var peer = fabric_client.newPeer('grpc://localhost:7051'); channel.addPeer(peer); // var member_user = null; var store_path = path.join(__dirname, 'hfc-key-store'); console.log('Store path:'+store_path); var tx_id = null; var query =async (fcn,args)=>{ try { // create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting var state_store = await Fabric_Client.newDefaultKeyValueStore({path: store_path}); // assign the store to the fabric client fabric_client.setStateStore(state_store); var crypto_suite = Fabric_Client.newCryptoSuite(); // use the same location for the state store (where the users' certificate are kept) // and the crypto store (where the users' keys are kept) var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path}); crypto_suite.setCryptoKeyStore(crypto_store); fabric_client.setCryptoSuite(crypto_suite); // get the enrolled user from persistence, this user will sign all requests var user_from_store = await fabric_client.getUserContext('user1', true); if (user_from_store && user_from_store.isEnrolled()) { console.log('Successfully loaded user1 from persistence'); member_user = user_from_store; } else { throw new Error('Failed to get user1.... run registerUser.js'); } // queryCar chaincode function - requires 1 argument, ex: args: ['CAR4'], // queryAllCars chaincode function - requires no arguments , ex: args: [''], const request = { //targets : --- letting this default to the peers assigned to the channel chaincodeId: 'fabcar', fcn: fcn, args: args }; // send the query proposal to the peer var query_responses = await channel.queryByChaincode(request); console.log("Query has completed, checking results"); // query_responses could have more than one results if there multiple peers were used as targets if (query_responses && query_responses.length == 1) { if (query_responses[0] instanceof Error) { return ("error from query = ", query_responses[0]); } else { return("Response is ", query_responses[0].toString()); } } else { return("No payloads were returned from query"); } }catch (err){ return('Failed to query successfully :: ' + err); } }; app.get('/:fcn/:fcn1',async (req, res) =>{ console.log(req.params.fcn); console.log(req.params.fcn1); var result = await query(req.params.fcn,new Array(req.params.fcn1)); res.send('Hello World!'+ result); }); app.listen(80, () => console.log('Example app listening on port 80!'))
hyperledger fabirc的三個重要角色前端
fabirc的共識達成經過三個步驟java
三個步驟保證了區塊鏈數據的一致性和正確性node
endorsing peer其實是一些特殊的peer. 由於不是每一個節點都會參與背書. 根據背書策略指定.react
在智能合約實例化的時候,咱們指定了背書策略, 每一個peer節點模擬執行的結果會反饋給sdk, sdk收集到節點模擬執行的讀寫集後,根據背書策略來決定是不是合法請求.
不一樣的channel能夠有不一樣chaincode,不一樣的chaincode有不一樣的背書策略.ios
client提交背書後的讀寫集(RW Sets) 給orderer節點. 注意: 在同一時間可能會有不一樣的client提交背書後的讀寫集, 這個提交操做是並行的.
git
orderer節點要驗證讀寫集,排序,生成區塊,最終把區塊交給全部的peer節點,讓他們更新ledger數據
github
區塊鏈須要解決雙花問題(double speding), 解決雙花就是要把並行的事情,最終變成線性, 把可能引起不一致的並行操做進行串行化. 以賣火車票爲例, 同一張票同一個座位有可能會被兩個不一樣的代售點同時賣出. 解決思路有多種, 賣票前先打電話詢問其餘的售票點,確認不衝突才能夠賣,這就是同步鎖的方式, 或者約定了第一家售票點只能在8點-9點賣票,第二家售票點只能在9點-10點賣票.這是經過令牌方式解決, 另外一種方式就是全部出票操做交給一箇中心的機構進行出票, 中心出票以前會檢查是否還有票,沒有票了就出票失敗...
hyperledger fabirc的 orderer節點就是採用了相似中心機構出票的方式. 因此他效率很高, 沒有挖礦的概念.面試
在開發者的角度,orderer採用什麼排序方法,對開發人員來說是透明的. 代碼都是同樣的.只是修改一個配置.算法
committing peer驗證讀寫集跟當前的世界狀態是否一致. 一致的話就會更新ledger, 世界狀態會跟隨變化, 若是不一致不會更新ledger,但transaction仍是會被記錄.世界狀態不會發生變化.
最後,committing peers會異步的通知client, transaction是成功仍是失敗. 咱們監聽這個回調,就能夠知道數據是否被寫入成功.
以上流程須要理解,記憶! 面試須要能說出來.
channel至關於hyperledger fabirc的子網絡, 不一樣的channel裏面的內容彼此獨立,徹底隔離.
經過channel能夠保證區塊鏈參與者的隱私和數據隔離.
不一樣的channel,擁有不一樣的application, 不一樣的ledger,不一樣的peers
世界狀態被存儲在狀態數據庫裏面
chaincode執行後stub.putState(key, Buffer.from(value)),
這些信息都是被key,value的形式存放到狀態數據庫中
經過stub.getState(key)的方式讀出來
hyperledger fabric 支持兩種模式的狀態數據庫
hyperledger fabric的智能合約叫chaincode鏈碼, 能夠用nodejs或者是go語言編寫,
chaincode就是咱們的business logic, 任何更新ledger的操做都只能經過智能合約來完成.
hyperledger fabric是一個受權網絡, 成員管理服務提供者是一個組件,用於定義身份,驗證身份和容許訪問網絡的規則。 MSP使用CA來頒發證書,MSP的默認接口是Fabric-CA API
頒發或者召回 用戶的證書, 用戶只有持有證書才能夠加入fabirc網絡,進行轉帳操做.
#安裝docker curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun #安裝docker-compose curl -L https://github.com/docker/compose/releases/download/1.20.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose #安裝git apt-get update apt-get install git #安裝nodejs curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs
修復阿里雲超時bug
/etc/resolv.conf 註釋掉 options timeout:2 attempts:3 rotate single-request-reopen
下載二進制腳本和安裝docker鏡像
curl -sSL https://raw.githubusercontent.com/itheima1/BlockChain/master/tools/bootstrap.sh | bash -s 1.1.0
chaincode就是智能合約, 經過編寫純函數的代碼,更新ledger的狀態.
https://fabric-shim.github.io/ChaincodeInterface.html
<async> Init(stub) Called during chaincode instantiate and upgrade. This is where you will initialize any application state. 智能合約被初始化或者升級的時候調用, 通常用來初始化應用程序的狀態
<async> Invoke(stub) called throughout the life time of the chaincode to carry out business transaction logic and effect the asset states 商業邏輯, 修改資產的狀態.
const Chaincode = class { async Init(stub) { // 初始化方法 await stub.putState(key, Buffer.from(aStringValue)); //能夠初始化一些世界狀態 return shim.success(Buffer.from('Initialized Successfully!')); } async Invoke(stub) { let ret = stub.getFunctionAndParameters(); //獲取函數名和參數 console.info(ret); let method = this[ret.fcn]; //函數 let payload = await method(stub, ret.params); //調用函數 return shim.success(payload); } async xxx(stub, args) {//示例函數 return "xxx"; } }; shim.start(new Chaincode());
區塊鏈不是萬金油, 任何技術都要評估風險和收益. 區塊鏈的特色是數據的可信和不可篡改, 企業作業務應該是使用區塊鏈技術來提高自身業務的健壯程度和抗風險能力. 不該該爲了區塊鏈而區塊鏈, 若是爲了區塊鏈而修改自身業務這種作法是不可取的.
企業項目對區塊鏈的態度應該是,上鍊了有好處, 不想上鍊了,但是隨時下來.
區塊鏈技術不該該跟業務綁定在一塊兒, 數據和業務分析是咱們企業級開發的最佳實戰. 是目前主流的作法和思想.
區塊鏈的做用是,在聯盟中記錄你們都承認,有價值的數據. 經過智能合約去添加和更新數據.
雄安新區區塊鏈租房項目
目標:房主租的安心、租客住的放心
租房業務核心數據上鍊
之後能夠根據區塊鏈交易信息查詢房東或者租客的信用程度,進行信用評級.
var rentHouse = { docHash: 'bf27373a381224a19c3a2886cd896d550ad440dddbfc49f09b3c025b50c56107', orderid: '0001', houseowner: '周扒皮', renter: '楊白勞', money: 30000, beginDate:'2018-01-01', endDate:'2018-12-31', note:'年付' }; await stub.putState(args[0], Buffer.from(JSON.stringify(rentHouse)));
區塊鏈二手車交易項目
目標:安心的登記,安心的二手車交易
二手車交易核心數據上鍊
車輛交易信息上鍊
針對汽車類型,製造商,型號,顏色,全部人等交易信息作記錄。
之後能夠追蹤汽車交易的整個歷史.
var car = { docType: 'car', make: '保時捷', model: '911', color: '冰川白', owner: '李天一' }; await stub.putState(args[0], Buffer.from(JSON.stringify(car)));
區塊鏈p2p金融借款反欺詐系統
傳統p2p小貸公司, 會對客戶作背景調查,調研客戶的還款能力,收入水平, 但這種報告每每具備很大的侷限性.
區塊鏈技術共享用戶的資產和借貸報告,聯盟鏈各機構之間的溝通成本就降得很低,而且這個項目能夠做爲當前小貸公司的一個加強的外圍功能使用,不會對企業當前的核心業務進行入侵式的影響. 利用區塊鏈的零知識證實等特性, 能夠極大程度的保證用戶的隱私.
例如用戶王思聰以買房資金週轉的名義從建設銀行借款1個億. 通過建設銀行評估, 認爲王思聰在貸款期限內有1億的還款能力,
但是與此同時,王思聰以一樣的理由在工商銀行和農業銀行貸款1個億. 工商銀行和農業銀行也都對王思聰的還款能力進行了評估. 因爲銀行系統放款信息同步不及時,不對稱. 王思聰極可能同時從三個銀行分別貸出來1個億. 那麼這三家銀行極可能其中一家或者兩家會出現同時逾貸的狀況.若是有大量借款人出現上訴狀況, 甚至會致使一家銀行會倒閉破產.
hyperledger fabric 存儲全部人的借貸信息.
uid: 'bf27373a381224a19c3a2886cd896d550ad440dddbfc49f09b3c025b50c56107', var loan = { timestamp: '1504054225', loanmoney: '1000000', applydate: '2018-08-14', startdate: '2018-08-15', enddate:'2019-08-15', realenddate:'0000-00-00' }; await stub.putState(uid, Buffer.from(JSON.stringify(loan)));
注意:以上區塊鏈系統存儲的數據是脫敏後的數據, 用戶的uid是根據用戶的身份證號碼,姓名和公安部提供的指紋特徵碼生成的sha256字符串, 只有獲得借款當事人受權,才能夠拿到這些信息生成uid. 普通機構即便看到這些數據, 也不知道這些數據對應的真實人的身份是什麼.
小黃魚項目(案例背景, 你們自行補充)
var fish = { Vessel: "奮進號38A", Location: "67.0006, -70.5476", Timestamp: "1504054225", Holder: "王大壯" }; await stub.putState(id, Buffer.from(JSON.stringify(fish)));
航空公司企業積分通用項目
var credits = { userid: "bf27373a381224a19c3a2886cd896d550ad440dddbfc49f09b3c025b50c56107", shop: "南航", Timestamp: "1504054225", credits: 1668 }; await stub.putState(id, Buffer.from(JSON.stringify(fish)));
物流, 冷鏈溯源, 一帶一路, 電子發票, 跨境支付,數字資產,信息共享,簽證證實...
熟悉區塊鏈技術,熟悉Hyperledger Fabric V1.1超級帳本的實現原理、基本架構分析,鏈碼智能合約實現,共享帳本如何存儲,coachdb, 共識機制如何實現和安全隱私等相關加密算法。熟悉從架構師角度分析設計系統,及程序角度實現系統。
1)瞭解Docker容器虛擬化技術使用;
2)熟悉nodejs語言編寫Chaincode,熟悉Nodejs編寫 SDK。
3)熟悉Liunx系統,熟練Fabric V1.1環境搭建,cli容器調試等。
4)熟悉多主機Peer系統部署,熟悉單主機開發調試,如4+1+2(4個Peer + 1 Orderer+2CA);
5)熟悉分佈式超媒體分發協議-IPFS在區塊鏈中應用。
6)已經實現將業務封裝爲服務,只要調用封裝的服務,就能夠實現全部業務。
7)整理了大量文檔和部署腳本。
var fish = { vessel: "奮進號38A", location: "67.0006, -70.5476", timestamp: "1504054225", holder: "王大壯" };
'use strict'; const shim = require('fabric-shim'); const util = require('util'); let Chaincode = class { //初始化智能合約的方法 async Init(stub) { console.info('=========== Instantiated fabcar chaincode ==========='); return shim.success(); } shim.start(new Chaincode());
async Invoke(stub) { let ret = stub.getFunctionAndParameters(); //獲取函數和參數 console.info(ret); let method = this[ret.fcn]; if (!method) { console.error('找不到要調用的函數,函數名:' + ret.fcn); throw new Error('找不到要調用的函數,函數名:' + ret.fcn); } try { let payload = await method(stub, ret.params); //直接調用函數,獲取返回值 return shim.success(payload); } catch (err) { console.log(err); return shim.error(err); } }
async queryFish(stub, args) { if (args.length != 1) { throw new Error('錯誤的調用參數. 實例: FISH01'); } let fishNumber = args[0]; let fishAsBytes = await stub.getState(fishNumber); //從帳本中獲取fish的信息,帳本是二進制存儲的 if (!fishAsBytes || fishAsBytes.toString().length <= 0) { throw new Error(fishAsBytes + ' 不存在: '); } console.log(fishAsBytes.toString()); return fishAsBytes; }
// 根據官方建議,最好的初始化區塊鏈帳本的方法是單獨編寫一個intLedger的方法.
async initLedger(stub, args) { console.info('============= 開始 : 初始化帳本 ==========='); let fishes = []; fishes.push({ vessel: "奮進號38A", location: "67.0006, -70.5476", timestamp: "1504054225", holder: "王大壯" }); fishes.push({ vessel: "光明號66B", location: "57.9006, -78.3478", timestamp: "1504054666", holder: "高大壯" }); fishes.push({ vessel: "釣魚島58B", location: "77.9034, -75.3455", timestamp: "1504054888", holder: "劉胡蘭" }); for (let i = 0; i < fishes.length; i++) { await stub.putState('FISH' + i, Buffer.from(JSON.stringify(fishes[i]))); console.info('Added <--> ',fishes[i]); } console.info('============= 結束 :初始化帳本 ==========='); }
async recordFish(stub, args) { console.info('============= START : record fish ==========='); if (args.length != 5) { throw new Error('須要5個參數,第0個參數是id,後面的4個參數, vessel, location, timestamp, holder'); } var fish = { vessel: args[1], location: args[2], timestamp: args[3], holder: args[4] }; await stub.putState(args[0], Buffer.from(JSON.stringify(fish))); console.info('============= END : record fish ==========='); }
async queryAllFish(stub, args) { let startKey = 'FISH0'; let endKey = 'FISH999'; let iterator = await stub.getStateByRange(startKey, endKey); let allResults = []; while (true) { let res = await iterator.next(); if (res.value && res.value.value.toString()) { let jsonRes = {}; console.log(res.value.value.toString('utf8')); jsonRes.Key = res.value.key; try { jsonRes.Record = JSON.parse(res.value.value.toString('utf8')); } catch (err) { console.log(err); jsonRes.Record = res.value.value.toString('utf8'); } allResults.push(jsonRes); } if (res.done) { console.log('end of data'); await iterator.close(); console.info(allResults); return Buffer.from(JSON.stringify(allResults)); } } }
更改小黃魚的歸屬人
async changeFishHolder(stub, args) { console.info('============= START : changeFishHolder ==========='); if (args.length != 2) { throw new Error('參數數量錯誤,須要兩個參數'); } let fishAsBytes = await stub.getState(args[0]); let fish = JSON.parse(fishAsBytes); fish.holder = args[1]; await stub.putState(args[0], Buffer.from(JSON.stringify(fish))); console.info('============= END : changeFishHolder ==========='); }
農牧廳漁業管理的智能合約咱們寫完了, 你們要可以觸類旁通, 其餘業務需求基本上也是相似的模版代碼.
做業: 你們本身實現上面分析的其餘需求.編寫智能合約.
OrdererOrgs: - Name: Orderer Domain: example.com Specs: - Hostname: orderer PeerOrgs: - Name: Org1 Domain: org1.example.com Template: Count: 1 Users: Count: 1
Organizations: - &OrdererOrg Name: OrdererOrg ID: OrdererMSP MSPDir: crypto-config/ordererOrganizations/example.com/msp - &Org1 Name: Org1MSP ID: Org1MSP MSPDir: crypto-config/peerOrganizations/org1.example.com/msp Application: &ApplicationDefaults Organizations: Orderer: &OrdererDefaults OrdererType: solo Addresses: - orderer.example.com:7050 BatchTimeout: 2s BatchSize: MaxMessageCount: 10 AbsoluteMaxBytes: 99 MB PreferredMaxBytes: 512 KB Organizations: Profiles: OneOrgOrdererGenesis: Orderer: <<: *OrdererDefaults Organizations: - *OrdererOrg Consortiums: SampleConsortium: Organizations: - *Org1 OneOrgChannel: Consortium: SampleConsortium Application: <<: *ApplicationDefaults Organizations: - *Org1
注意ca的默認密碼是adminpw
version: '2' networks: basic: services: ca.example.com: image: hyperledger/fabric-ca environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_CA_NAME=ca.example.com - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/4239aa0dcd76daeeb8ba0cda701851d14504d31aad1b2ddddbac6a57365e497c_sk ports: - "7054:7054" command: sh -c 'fabric-ca-server start -b admin:adminpw -d' volumes: - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config container_name: ca.example.com networks: - basic orderer.example.com: container_name: orderer.example.com image: hyperledger/fabric-orderer environment: - ORDERER_GENERAL_LOGLEVEL=debug - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_GENESISMETHOD=file - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderer command: orderer ports: - 7050:7050 volumes: - ./config/:/etc/hyperledger/configtx - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/:/etc/hyperledger/msp/orderer - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/:/etc/hyperledger/msp/peerOrg1 networks: - basic peer0.org1.example.com: container_name: peer0.org1.example.com image: hyperledger/fabric-peer environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_PEER_ID=peer0.org1.example.com - CORE_LOGGING_PEER=debug - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/ - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 # # the following setting starts chaincode containers on the same # # bridge network as the peers # # https://docs.docker.com/compose/networking/ working_dir: /opt/gopath/src/github.com/hyperledger/fabric command: peer node start # command: peer node start --peer-chaincodedev=true ports: - 7051:7051 - 7053:7053 volumes: - /var/run/:/host/var/run/ - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/msp/peer - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users - ./config:/etc/hyperledger/configtx depends_on: - orderer.example.com networks: - basic cli: container_name: cli image: hyperledger/fabric-tools tty: true environment: - GOPATH=/opt/gopath - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_LOGGING_LEVEL=DEBUG - CORE_PEER_ID=cli - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp - CORE_CHAINCODE_KEEPALIVE=10 working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: /bin/bash volumes: - /var/run/:/host/var/run/ - ./../chaincode/:/opt/gopath/src/github.com/ - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ networks: - basic
#!/bin/bash set -ev # don't rewrite paths for Windows Git Bash users export MSYS_NO_PATHCONV=1 docker-compose -f docker-compose.yml down docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com export FABRIC_START_TIMEOUT=30 sleep ${FABRIC_START_TIMEOUT} # Create the channel docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c mychannel -f /etc/hyperledger/configtx/channel.tx # Join peer0.org1.example.com to the channel. docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel join -b mychannel.block
#!/bin/bash set -e # don't rewrite paths for Windows Git Bash users export MSYS_NO_PATHCONV=1 starttime=$(date +%s) LANGUAGE=node CC_SRC_PATH=/opt/gopath/src/github.com/fabcar/node # clean the keystore rm -rf ./hfc-key-store # launch network; create channel and join peer to channel cd ../basic-network ./start.sh # Now launch the CLI container in order to install, instantiate chaincode docker-compose -f ./docker-compose.yml up -d cli docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode install -n fishcc -v 1.0 -p "$CC_SRC_PATH" -l node docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n fishcc -l node -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')" sleep 20 docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fishcc -c '{"function":"initLedger","Args":[""]}' printf "\n腳本啓動時間 : $(($(date +%s) - starttime)) 秒 ...\n\n\n" printf "執行'npm install' 安裝依賴文件\n" printf "執行 'node enrollAdmin.js', 建立管理員, 而後執行 'node registerUser'建立用戶\n\n" printf "執行 'node invoke.js' 調用函數\n" printf "執行 'node query.js' 查詢記錄\n\n"
建立文件夾fabircfish npm install --save fabric-ca-client npm install --save fabirc-client npm install --save grpc
'use strict'; /* * Copyright IBM Corp All Rights Reserved * * SPDX-License-Identifier: Apache-2.0 */ /* * Enroll the admin user */ var Fabric_Client = require('fabric-client'); var Fabric_CA_Client = require('fabric-ca-client'); var path = require('path'); var util = require('util'); var os = require('os'); // var fabric_client = new Fabric_Client(); var fabric_ca_client = null; var admin_user = null; var member_user = null; var store_path = path.join(__dirname, 'hfc-key-store'); console.log(' Store path:'+store_path); // create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting Fabric_Client.newDefaultKeyValueStore({ path: store_path }).then((state_store) => { // assign the store to the fabric client fabric_client.setStateStore(state_store); var crypto_suite = Fabric_Client.newCryptoSuite(); // use the same location for the state store (where the users' certificate are kept) // and the crypto store (where the users' keys are kept) var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path}); crypto_suite.setCryptoKeyStore(crypto_store); fabric_client.setCryptoSuite(crypto_suite); var tlsOptions = { trustedRoots: [], verify: false }; // be sure to change the http to https when the CA is running TLS enabled fabric_ca_client = new Fabric_CA_Client('http://localhost:7054', tlsOptions , 'ca.example.com', crypto_suite); // first check to see if the admin is already enrolled return fabric_client.getUserContext('admin', true); }).then((user_from_store) => { if (user_from_store && user_from_store.isEnrolled()) { console.log('Successfully loaded admin from persistence'); admin_user = user_from_store; return null; } else { // need to enroll it with CA server return fabric_ca_client.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' }).then((enrollment) => { console.log('Successfully enrolled admin user "admin"'); return fabric_client.createUser( {username: 'admin', mspid: 'Org1MSP', cryptoContent: { privateKeyPEM: enrollment.key.toBytes(), signedCertPEM: enrollment.certificate } }); }).then((user) => { admin_user = user; return fabric_client.setUserContext(admin_user); }).catch((err) => { console.error('Failed to enroll and persist admin. Error: ' + err.stack ? err.stack : err); throw new Error('Failed to enroll admin'); }); } }).then(() => { console.log('Assigned the admin user to the fabric client ::' + admin_user.toString()); }).catch((err) => { console.error('Failed to enroll admin: ' + err); });
'use strict'; /* * Copyright IBM Corp All Rights Reserved * * SPDX-License-Identifier: Apache-2.0 */ /* * Register and Enroll a user */ var Fabric_Client = require('fabric-client'); var Fabric_CA_Client = require('fabric-ca-client'); var path = require('path'); var util = require('util'); var os = require('os'); // var fabric_client = new Fabric_Client(); var fabric_ca_client = null; var admin_user = null; var member_user = null; var store_path = path.join(__dirname, 'hfc-key-store'); console.log(' Store path:'+store_path); // create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting Fabric_Client.newDefaultKeyValueStore({ path: store_path }).then((state_store) => { // assign the store to the fabric client fabric_client.setStateStore(state_store); var crypto_suite = Fabric_Client.newCryptoSuite(); // use the same location for the state store (where the users' certificate are kept) // and the crypto store (where the users' keys are kept) var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path}); crypto_suite.setCryptoKeyStore(crypto_store); fabric_client.setCryptoSuite(crypto_suite); var tlsOptions = { trustedRoots: [], verify: false }; // be sure to change the http to https when the CA is running TLS enabled fabric_ca_client = new Fabric_CA_Client('http://localhost:7054', null , '', crypto_suite); // first check to see if the admin is already enrolled return fabric_client.getUserContext('admin', true); }).then((user_from_store) => { if (user_from_store && user_from_store.isEnrolled()) { console.log('Successfully loaded admin from persistence'); admin_user = user_from_store; } else { throw new Error('Failed to get admin.... run enrollAdmin.js'); } // at this point we should have the admin user // first need to register the user with the CA server return fabric_ca_client.register({enrollmentID: 'user1', affiliation: 'org1.department1',role: 'client'}, admin_user); }).then((secret) => { // next we need to enroll the user with CA server console.log('Successfully registered user1 - secret:'+ secret); return fabric_ca_client.enroll({enrollmentID: 'user1', enrollmentSecret: secret}); }).then((enrollment) => { console.log('Successfully enrolled member user "user1" '); return fabric_client.createUser( {username: 'user1', mspid: 'Org1MSP', cryptoContent: { privateKeyPEM: enrollment.key.toBytes(), signedCertPEM: enrollment.certificate } }); }).then((user) => { member_user = user; return fabric_client.setUserContext(member_user); }).then(()=>{ console.log('User1 was successfully registered and enrolled and is ready to interact with the fabric network'); }).catch((err) => { console.error('Failed to register: ' + err); if(err.toString().indexOf('Authorization') > -1) { console.error('Authorization failures may be caused by having admin credentials from a previous CA instance.\n' + 'Try again after deleting the contents of the store directory '+store_path); } });
'use strict'; var Fabric_Client = require('fabric-client'); var path = require('path'); var util = require('util'); var os = require('os'); var fabric_client = new Fabric_Client(); // 設置fabric網絡 var channel = fabric_client.newChannel('mychannel'); var peer = fabric_client.newPeer('grpc://localhost:7051'); channel.addPeer(peer); // var member_user = null; var store_path = path.join(__dirname, 'hfc-key-store'); console.log('Store path:'+store_path); var tx_id = null; var query =async (fcn,args)=>{ try { // create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting var state_store = await Fabric_Client.newDefaultKeyValueStore({path: store_path}); // assign the store to the fabric client fabric_client.setStateStore(state_store); var crypto_suite = Fabric_Client.newCryptoSuite(); // use the same location for the state store (where the users' certificate are kept) // and the crypto store (where the users' keys are kept) var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path}); crypto_suite.setCryptoKeyStore(crypto_store); fabric_client.setCryptoSuite(crypto_suite); // get the enrolled user from persistence, this user will sign all requests var user_from_store = await fabric_client.getUserContext('user1', true); if (user_from_store && user_from_store.isEnrolled()) { console.log('Successfully loaded user1 from persistence'); member_user = user_from_store; } else { throw new Error('Failed to get user1.... run registerUser.js'); } // queryCar chaincode function - requires 1 argument, ex: args: ['FISH0'], // queryAllCars chaincode function - requires no arguments , ex: args: [''], const request = { //targets : --- letting this default to the peers assigned to the channel chaincodeId: 'fishcc', fcn: fcn, args: args }; // send the query proposal to the peer var query_responses = await channel.queryByChaincode(request); console.log("Query has completed, checking results"); // query_responses could have more than one results if there multiple peers were used as targets if (query_responses && query_responses.length == 1) { if (query_responses[0] instanceof Error) { console.error("error from query = ", query_responses[0]); } else { console.log("Response is ", query_responses[0].toString()); } } else { console.log("No payloads were returned from query"); } }catch (err){ console.error('Failed to query successfully :: ' + err); } }; console.log(process.argv[2]); console.log(process.argv[3]); var args = new Array(process.argv[3]); query(process.argv[2],args);
import React, { Component } from 'react'; import axios from 'axios'; class App extends Component { state = {items: []}; async componentDidMount() { var result = await axios.get('http://47.254.69.107/queryAllFish/a'); console.log(result.data); this.setState({ items:result.data }); } render() { var htmlbody=[]; this.state.items.forEach((value)=>{ htmlbody.push(<h3>{value.Key}, {value.Record.holder}</h3>) }); return ( <div > {htmlbody} </div> ); }
'use strict'; var Fabric_Client = require('fabric-client'); var path = require('path'); var util = require('util'); var os = require('os'); // var fabric_client = new Fabric_Client(); // 設置 fabric 網絡 var channel = fabric_client.newChannel('mychannel'); var peer = fabric_client.newPeer('grpc://localhost:7051'); channel.addPeer(peer); var order = fabric_client.newOrderer('grpc://localhost:7050'); channel.addOrderer(order); // var member_user = null; var store_path = path.join(__dirname, 'hfc-key-store'); console.log('Store path:'+store_path); var tx_id = null; Fabric_Client.newDefaultKeyValueStore({ path: store_path }).then((state_store) => { // assign the store to the fabric client fabric_client.setStateStore(state_store); var crypto_suite = Fabric_Client.newCryptoSuite(); // use the same location for the state store (where the users' certificate are kept) // and the crypto store (where the users' keys are kept) var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path}); crypto_suite.setCryptoKeyStore(crypto_store); fabric_client.setCryptoSuite(crypto_suite); // get the enrolled user from persistence, this user will sign all requests return fabric_client.getUserContext('user1', true); }).then((user_from_store) => { if (user_from_store && user_from_store.isEnrolled()) { console.log('Successfully loaded user1 from persistence'); member_user = user_from_store; } else { throw new Error('Failed to get user1.... run registerUser.js'); } // get a transaction id object based on the current user assigned to fabric client tx_id = fabric_client.newTransactionID(); console.log("Assigning transaction_id: ", tx_id._transaction_id); // recordFish chaincode function - requires 5 args, ex: args: ['FISH5', "奮進號38A", "67.0006, -70.5476", "1504054225", "王大壯"], // changeFishHolder chaincode function - requires 2 args , ex: args: ['FISH5', 'Dave'], // must send the proposal to endorsing peers var request = { //targets: let default to the peer assigned to the client chaincodeId: 'fishcc', fcn: '', args: [''], chainId: 'mychannel', txId: tx_id }; //1. 發送背書請求到全部的節點 return channel.sendTransactionProposal(request); }).then((results) => { var proposalResponses = results[0]; var proposal = results[1]; let isProposalGood = false; if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status === 200) { isProposalGood = true; console.log('Transaction proposal was good'); } else { console.error('Transaction proposal was bad'); } if (isProposalGood) { console.log(util.format( 'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s"', proposalResponses[0].response.status, proposalResponses[0].response.message)); // 根據背書請求建立request對象 var request = { proposalResponses: proposalResponses, proposal: proposal }; // 設置30秒的監聽器, 看request請求是否完成 var transaction_id_string = tx_id.getTransactionID(); //Get the transaction ID string to be used by the event processing var promises = []; var sendPromise = channel.sendTransaction(request); promises.push(sendPromise); //we want the send transaction first, so that we know where to check status // get an eventhub once the fabric client has a user assigned. The user // is required bacause the event registration must be signed let event_hub = channel.newChannelEventHub(peer); // using resolve the promise so that result status may be processed // under the then clause rather than having the catch clause process // the status let txPromise = new Promise((resolve, reject) => { let handle = setTimeout(() => { event_hub.unregisterTxEvent(transaction_id_string); event_hub.disconnect(); resolve({event_status : 'TIMEOUT'}); //we could use reject(new Error('Trnasaction did not complete within 30 seconds')); }, 3000); event_hub.registerTxEvent(transaction_id_string, (tx, code) => { // this is the callback for transaction event status // first some clean up of event listener clearTimeout(handle); // now let the application know what happened var return_status = {event_status : code, tx_id : transaction_id_string}; if (code !== 'VALID') { console.error('The transaction was invalid, code = ' + code); resolve(return_status); // we could use reject(new Error('Problem with the tranaction, event status ::'+code)); } else { console.log('The transaction has been committed on peer ' + event_hub.getPeerAddr()); resolve(return_status); } }, (err) => { //this is the callback if something goes wrong with the event registration or processing reject(new Error('There was a problem with the eventhub ::'+err)); }, {disconnect: true} //disconnect when complete ); event_hub.connect(); }); promises.push(txPromise); return Promise.all(promises); } else { console.error('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'); throw new Error('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'); } }).then((results) => { console.log('Send transaction promise and event listener promise have completed'); // check the results in the order the promises were added to the promise all list if (results && results[0] && results[0].status === 'SUCCESS') { console.log('Successfully sent transaction to the orderer.'); } else { console.error('Failed to order the transaction. Error code: ' + results[0].status); } if(results && results[1] && results[1].event_status === 'VALID') { console.log('Successfully committed the change to the ledger by the peer'); } else { console.log('Transaction failed to be committed to the ledger due to ::'+results[1].event_status); } }).catch((err) => { console.error('Failed to invoke successfully :: ' + err); });