代码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); });