手动搭建fabric1.1.0中first-network笔记

我是使用阿里云的服务器来进行hyperledger fabric1.1.0网络的实验,下面是学习过程中记录的部署环境的过程及手动实现my-first区块网络的记录

先附上常用词汇表,来自于这篇博客

MSP:Membership service provider 会员服务提供者
BCCSP:blockchain(前两个字母BC) cryptographic service provider 区域链加密服务提供者
ab:atomic broadcast原子(操作)广播
lscc:lifecycle(L) system(S) chaincode(CC)生命周期系统链码
Spec:Specification,规格标准,详细说明
KV:key-value 键-值
CDS:ChaincodeDeploymentSpec
CIS:ChaincodeInvocationSpec
mgmt:management
SW:software-based
AB:AtomicBroadcast
GB:genesis block,创世纪的block,也就是区域链中的第一个块
CC或cc:chaincode
SCC或scc:system chaincode
cscc:configer system chaincode
lscc:lifecycle system chaincode
escc:endorser system chaincode
vscc:validator system chaincode
qscc:querier system chaincode
alg:algorithm 算法
mcs:mspMessageCryptoService
mock:假装,学样子,模仿的意思,基本上是服务于xxx_test.go的,即用于测试的
Gossip:一种使分布结点达到状态最终一致的算法
attr:attribute
FsBlockStore:file system block store
vdb:versioned database 也就是状态数据库
RTEnv:runtime environment运行环境
pkcs11:pcks#11,一种公匙加密标准,有一套叫做Cryptoki的接口,是一组平台设备无关的API
MCS:mspMessageCryptoService,消息加密服务
sa:SecurityAdvisor
impl:implement,好多处XXX.go和XXXimpl.go是对应的,前者是用于接口或者定义的,后者是实现该接口或定义的
FSM:finite state machine 有限状态机
FS:filesystem 文件系统
blk:block
cli:command line interface 命令行界面
CFG:FABRIC_CFG_PATH中的,应该是config的意思
mgr:manager
cpinfo:checkpoint information,检查点信息
DevMode:development mode,开发模式
Reg:register,注册,登记
hdr:header
impl:implement
oid:ObjectIdentifier,对象标识符
ou或OU:organizational unit
CRL:certificate revocation list,废除证书列表
prop:proposal,申请,交易所发送的申请
ACL:Access Control List,访问控制列表
rwset:read/write set,读写集
tx,Tx:transaction,交易
CSP:cryptographic service provider,BCCSP的后三个字母,加密服务提供者
opt:option,选项
opts:options,多个选项
SKI:当前证书标识,所谓标识,一般是对公匙进行一下hash
AKI:签署方的SKI,也就是签署方的公匙标识
HSM:Hardware Security Modules
ks:KeyStore,Key存储,这个key指的是用于签名的公匙私匙
oid:OBJECT IDENTIFIER,对象身份标识

一、部署fabric1.1.0并运行first-network

1、预操作

进入新创建的Ubuntu虚拟机后,首先进行如下操作
cd ..
vi ./ect/resolv.conf
将里面的第三行注释掉

2、安装docker

使用官方脚本自动安装,下载最新版的docker ce
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
下面输入docker version对docker版本进行检测,可以看到,客户端和服务器端版本都是18.06.3-ce
版本检测

3、安装Git

最好先更新apt-get,否则可能会下载版本很旧的git,这是个好习惯,在下载任何包的时候,最好都更新一下工具
apt-get update
apt-get install git

4、安装hyperledger的工具和docker的镜像

curl -sSL https://goo.gl/6wtTN5 | bash -s 1.1.0
因为官方的sh文件存在版本号相关的问题,因此镜像的下载会缺少几个重要的文件,这个时候需要我们自己去拉取缺少的镜像,首先使用docker images看一看当前我们的镜像都是啥
最开始的镜像
观察发现,拥有不少相同ID却有着不同tag的镜像,我们使用
docker rmi hyperledger/fabric-tools:x86_64-1.1.0
来删除hyperledger文件夹下镜像名为fabric-tools,版本号为x86_64-1.1.0的镜像,其他的按此方式删除
删除结果如下
清理后的镜像列表
之后使用拉取镜像的指令拉取缺少的镜像,我们暂时拉取的镜像有zookeeper,kafka,couchdb,ca,baseimage,membersrvc,baseos
docker pull hyperledger/fabric-baseos
docker pull hyperledger/fabric-baseimage
docker pull hyperledger/fabric-membersrvc
docker pull hyperledger/fabric-ca
docker pull hyperledger/fabric-couchdb
docker pull hyperledger/fabric-kafka
docker pull hyperledger/fabric-zookeeper
这是有版本号的示例:
docker pull hyperledger/fabric-baseimage:x86_64-1.1.0
以下是下载后的镜像们
最终12个镜像
查看当前root下的文件夹,只有一个fabric-sample,我们从github上下载以方便学习(使用ls指令老铁)
https://github.com/hyperledger/fabric-samples
和服务器上的区别在于,服务器有bin文件夹,里面存着一些工具,如cryptogen(crypto generate),加密货币的生成,实际上是为每个节点办法颁发数字证书的工具;configtxgen生成区块链创世区块的
bin目录

5、安装docker-compose

# curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m`> /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose

6、运行first-network

到这里跑通first-network的条件就聚齐了,我们梳理一下:

  • 处理阿里云自带的resolv.conf文件
  • 使用apt-get安装git用来下载github上的源码
  • 安装hyperledger的工具和docker的镜像
  • 拉取缺少的镜像
  • 下载docker-compose

这之后,进入first-network文件夹,输入指令./byfn.sh -m generate来创建必要的区块和channel网络,成功后输入./byfn.sh -m up运行网络,经过漫长等待,出现END网络也就成功运行并完成规定的转账操作了
first-network网络跑通

二、手动部署运行my-network

1、建立my-network文件夹

在fabric-samples下建立mkdir my-network
创建文件夹

2、创建crypto-config.yaml

使用touch crypto-config.yaml在my-network内创建文件
使用vi指令向文件内写入内容

OrdererOrgs:
  - Name: Orderer
    Domain: example.com
    Specs:
      - Hostname: orderer
PeerOrgs:
  - Name: Org1
    Domain: org1.example.com
    Template:
      Count: 2
    Users:
      Count: 1
  - Name: Org2
    Domain: org2.example.com
    Template:
      Count: 2
    Users:
      Count: 1

简单解释一下里面的内容,OrdererOrgs和PeerOrgs分别是Orderer节点和Peer节点所在的组织,Name定义了当前结点的名字,Domain指定了当前节点的域名(实际上这里的域名需要修改成你们公司的域名,这里仅仅是测试用),Hostname指定了主机名,Template代表了当前组织拥有多少个Peer,Users则代表的当前组织拥有多少个用户,这里用户数量不包括超级用户(超级管理员),组织内默认有超级管理员

3、设置bin目录进入环境变量

为了使用bin目录里面的工具,需要将bin目录加入my-network文件夹的环境变量中
export PATH=${PWD}/../bin:${PWD}:$PATH
之后执行刚刚创立的yaml文件,就可以生成各个机构的机构信息
cryptogen generate --config=./crypto-config.yaml
可以看到,my-network下多出了名为crypto-config的文件夹
bin环境变量
我们可以安装tree来查看这个文件夹的目录结构
使用apt-get install tree安装tree,进入crypto-config文件夹,使用tree -L 3来查看最多三级目录结构
tree

4、编写创世区块

上面的crypto-config文件夹存放了用户们的私钥,我们将这些私钥信息和别的具体用户信息写入创世区块,这样后面的区块都要依附于这些私钥的哈希,保证了数据安全
因为configtx.yaml文件太长,我们直接从first-network里面拷贝进入my-network中(手动创建的文件名称和用户数量和系统给的案例是一样的,因此这里的yaml文件可以直接使用)
进入first-network中使用cp configtx.yaml ../my-network/

5、性能调优

在configtx.yaml文件中,有几个可以调整的参数,分别是:

  • OrdererType:启用的排序算法
  • BatchTimeout:提交更新的时间间隔,是orderer更新peer传入的交易信息的更新周期,有点像以太坊的出块时间,若达到时间间隔,无视最大消息数量和区块大小,直接发送
  • MaxMessageCount:最大消息数量,在orderer中积攒的更新申请数量如果超过了规定的更新申请数量,则无视间隔时间和区块大小直接发送
  • AbsoluteMaxBytes:最大区块大小,所有的消息大小若超过规定大小,则立刻发送所有的消息,无视时间和数量
    调参
6、生成创世区块和channel.tx

mkdir channel-artifacts
configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
先创立存放区块的文件夹,这里的profile后面的名称要和前面yaml文件里面profile中的名称对应,outputBlock指定了block存放的文件夹路径
创建创世区块
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
channel.tx创建

7、配置锚节点

为了使不同的Org之间能互相通信,需要配置好每个组织内的锚节点
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
锚点
同理,对Org2进行锚节点配置
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
锚点2

7、启动所有服务器

首先将first-network中需要的yaml文件拷贝进my-network
cp docker-compose-cli.yaml ../my-network/
因为这个yaml文件中使用了很多extend继承了base文件夹中的内容,需要将base文件夹拷贝进来
cp -r base ../my-network/
拷贝文件
下面,配置环境,否则启动网络后会报错,这两个分别是镜像们的TAG和当前创建网络的名称,之后就可以启动所有服务器了
在启动服务器之前,一定需要做好两件事,一个是本笔记第一步,修改配置文件,不然会出现进程exited(2)的情况,另一个是关闭first-network,在这个文件夹下使用./byfn.sh -m down进行
一切就绪就可以进行下面的步骤了
export IMAGE_TAG=latest
export COMPOSE_PROJECT_NAME=net
docker-compose -f docker-compose-cli.yaml up -d
容器启动成功
接下来,使用docker ps来查看容器内正在运行的进程
查看进程

8、创建channel

执行docker exec -it cli bash进入cli虚拟机内
执行下面的代码对channel进行配置
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
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls --cafile $ORDERER_CA
出现了困扰我已久的问题,如下图:
错误
此问题困扰我良久,终于机缘巧合,意识到了是因为终端虚拟软件的选取出现了问题,我最开始一直使用finalshell,而在创建了channel.tx之后,我曾经尝试cat channel.tx,结果出现了全屏字母乱码的情况,后来我分析是shell软件本身的问题,因此我改换了xshell,终于成功建立了channel!
channel建立

9、加入通道
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
peer channel join -b mychannel.block

export CORE_PEER_ADDRESS=peer1.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
peer channel join -b mychannel.block

export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
peer channel join -b mychannel.block

export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
peer channel join -b mychannel.block
10、安装链码

解释几个flag的意义:
-n 这个chaincode的名字
-v 这个chaincode的版本号,以后方便更改版本所设计的
-l 链码使用的编程语言,node代表nodejs
-p 智能合约代码对应的路径

export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node

export CORE_PEER_ADDRESS=peer1.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node

export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node

export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node

下面是最后一个链码安装成功后的截图
安装链码

10.5、写自己的链码

上面使用的链码是chaincode/chaincode_example02/node路径下的系统给我们现成的链码,我们如果自己定义自己的链码呢?
在fabric-sample文件夹下的chaincode文件夹里创建一个mycc,存放着我们自己写的智能合约
因为还没有安装Nodejs,因此去找到适合的方法安装之
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
apt-get install -y nodejs
安装好以后在mycc文件夹下初始化工程npm mycc,一路回车就算初始化结束
初始化
之后在mycc中出现了新的文件package.json,我们修改文件内容:

{
  "name": "mycc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node haha.js"
  },
  "author": "",
  "license": "ISC"
}

修改了scripts中的内容,也就是说这个项目运行的时候会运行haha.js文件,我们新建haha.js文件,使用touch haha.js
我们需要一个依赖库,因此使用npm install --save fabric-shim来下载依赖库,之后查看package.json就会发现多了依赖信息:

{
  "name": "mycc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node haha.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "fabric-shim": "^2.0.0"
  }
}

下面展示一个简单的nodejs链码的模板


const shim = require('fabric-shim'); //引入依赖
const Chaincode = class{ //声明一个类
    //链码初始化操作,必须执行的两个方法Init和Invoke
    async Init(stub){
        var ret = stub.getFunctionAndParameters(); //拿着sub获取当前调用的function,Parameters的名字和参数
        var args  = ret.params; 
        var a = args[0]; //这相当于函数的第0个参数,后面就是第1、2、3个参数
        var aValue = args[1];
        var b = args[2];
        var bValue = args[3];
        await  stub.putState(a,Buffer.from(aValue)); //写入账本内容
        await  stub.putState(b,Buffer.from(bValue));
        return shim.success(Buffer.from('heima chaincodinit successs'));
    }
    
    async Invoke(stub){
        let ret = stub.getFunctionAndParameters();
        let fcn = this[ret.fcn];
        return fcn(stub,ret.params);
    }
    //查询操作
    async query(stub,args){ //查询功能
        let a = args[0];
        let balance = await stub.getState(a); //取出账本内容
        return shim.success(balance);
    }

};
shim.start(new Chaincode());
11、实例化链码

运行下列指令以便实例化链码
peer chaincode instantiate -o orderer.example.com:7050 --tls $CODE_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -l node -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
上面的指令和前面的异曲同工,需要注意的是大括号内就是调用链码为之输入参数了,这里初始化了a和b的资金为100和200,后面的-P为背书策略,也就是组织1和组织2中只要有一个成员同意,就能执行的策略
实例化链码

12、查询链码

使用node中js文件里写的查询函数进行查询
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
查询链码

13、调用链码

peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem
调用链码

END

至此手动创建一个网络就算简单的完成了,重要的链码编写是接下来要研究的内容,希望一切顺利,早日编写出属于自己的区块链小应用demo吧

发布了8 篇原创文章 · 获赞 4 · 访问量 2886

猜你喜欢

转载自blog.csdn.net/legendary_idiot/article/details/104323781
今日推荐