分类 技术前沿 下的文章 - 六币之门
首页
视频教程
网站导航
活动日历
关于我们
用户投稿
推荐
新闻动态
搜 索
1
融资周报 | 公开融资事件11起;加密技术公司Toposware完成500万美元融资,Polygon联创参投
107 阅读
2
六币日报 | 九只比特币ETF在6天内积累了9.5万枚BTC;贝莱德决定停止推出XRP现货ETF计划
73 阅读
3
六币日报 | 美国SEC再次推迟对灰度以太坊期货ETF做出决定;Do Kwon已出黑山监狱等待引渡
68 阅读
4
融资周报 | 公开融资事件27起;L1区块链Monad Labs完成2.25亿美元融资,Paradigm领投
68 阅读
5
【ETH钱包开发06】查询某个地址的交易记录
43 阅读
新闻动态
每日快报
一周精选
融资情况
项目投研
自治组织
数字藏品
去中心化应用
去中心化游戏
去中心化社交
去中心化金融
区块链交易所
科普知识
小白入门
用户手册
开发文档
行业报告
技术前沿
登录
搜 索
标签搜索
新闻
日报
元歌Eden
累计撰写
1,087
篇文章
累计收到
0
条评论
首页
栏目
新闻动态
每日快报
一周精选
融资情况
项目投研
自治组织
数字藏品
去中心化应用
去中心化游戏
去中心化社交
去中心化金融
区块链交易所
科普知识
小白入门
用户手册
开发文档
行业报告
技术前沿
页面
视频教程
网站导航
活动日历
关于我们
用户投稿
推荐
新闻动态
用户登录
登录
找到
109
篇与
技术前沿
相关的结果
2023-03-22
Hyperledger Fabric 部署在多个主机上
前言在实验Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务、TLS组织运行维护Orderer服务中,我们已经完成了使用提供 TLS-CA 服务的 council 组织运行维护 Raft 协议的三个 orderer 节点。但目前我们都是在单个主机上启动 Fabric 网络,本文将尝试将 Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务、TLS组织运行维护Orderer服务 中的网络结构部署在多个主机上。工作准备本文工作将 Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务、TLS组织运行维护Orderer服务 中网络部署至两台主机上—— DebianA 和 DebianB,其中 DebianA 维护 council 和 soft 组织及相关节点, DebianB 维护 web 和 hard 组织及相关节点,网络结构为(实验代码已上传至:github.com/wefantasy/F… 的 5_FabricNetworkByMultiHost 下):项所属主机运行端口说明council.ifantasy.netDebianA7050council 组织的 CA 服务, 为联盟链网络提供 TLS-CA 服务orderer1.council.ifantasy.netDebianA7051orderer1 的排序服务orderer1.council.ifantasy.netDebianA7052orderer1 的 admin 服务orderer2.council.ifantasy.netDebianA7054orderer2 的排序服务orderer2.council.ifantasy.netDebianA7055orderer2 的 admin 服务orderer3.council.ifantasy.netDebianB7057orderer3 的排序服务orderer3.council.ifantasy.netDebianB7058orderer3 的 admin 服务soft.ifantasy.netDebianA7250soft 组织的 CA 服务, 包含成员: peer1 、 admin1peer1.soft.ifantasy.netDebianA7251soft 组织的 peer1 成员节点web.ifantasy.netDebianB7350web 组织的 CA 服务, 包含成员: peer1 、 admin1peer1.web.ifantasy.netDebianB7351web 组织的 peer1 成员节点hard.ifantasy.netDebianB7450hard 组织的 CA 服务, 包含成员: peer1 、 admin1peer1.hard.ifantasy.netDebianB7451hard 组织的 peer1 成员节点两个主机的相关信息为:主机名别名网络地址说明DebianAhost1172.25.1.250运行 council 和 softDebianBhost2172.25.1.251运行 web 和 hard实验准备本文网络结构直接将 Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务、TLS组织运行维护Orderer服务 中创建的 4-2_RunOrdererByCouncil 复制为 5_FabricNetworkByMultiHost 并修改(建议直接将本案例仓库 FabricLearn 下的 5_FabricNetworkByMultiHost 目录拷贝到本地运行),文中大部分命令在 Hyperledger Fabric定制联盟链网络工程实践 中已有介绍因此不会详细说明。默认情况下,所有命令皆在 5_FabricNetworkByMultiHost 根目录下执行。本系列所有实验都是在 VM ware 的 Debian 虚拟机(DebianA)下完成,本文会将 DebianA 虚拟机直接拷贝一份为 DebianB ,之后将会在 DebianA 下生成所有证书文件及通道文件,然后将文件复制一份到 DebianB 中再分别启动对应的网络。配置文件通过 docker 运行 fabric 网络总是需要解决不同节点间的通信问题(不能仅配置 DNS),目前主要有三种解决方案:在 docker-compose.yaml 中设置 extra_hosts 字段 通过容器编排工具 docker swarm 实现 通过容器编排工具 Kubernetes(K8S) 实现(后期尝试) 大规模容器编排管理目前最流行的就是 K8S ,后期本人也会朝此方向尝试,为了简便本文使用第一种方式实现不同主机的 docker 容器通信。具体实现方面,只需要在 compose/docker-compose.yaml 中的 orderer 服务和 peer 服务中添加下列代码,如 orderer1.council.ifantasy.net : orderer1.council.ifantasy.net: container_name: orderer1.council.ifantasy.net extends: file: docker-base.yaml service: orderer-base environment: - ORDERER_HOST=orderer1.council.ifantasy.net - ORDERER_GENERAL_LOCALMSPID=councilMSP - ORDERER_GENERAL_LISTENPORT=7051 volumes: - $/council.ifantasy.net/registers/orderer1:$/orderer - $/data/genesis.block:$/orderer/genesis.block ports: - 7051:7051 - 7052:8888 - 7053:9999 extra_hosts: - "orderer1.council.ifantasy.net:172.25.1.250" - "orderer2.council.ifantasy.net:172.25.1.250" - "orderer3.council.ifantasy.net:172.25.1.251" 复制代码如果不进行上述配置,则会因无法通信而出现下列错误:Error: failed to send transaction: got unexpected status: SERVICE_UNAVAILABLE -- no Raft leader 复制代码证书和通道文件生成网上很多相关教程都说明了将 Fabric 网络部署至多主机的方法12,大部分教程都是在同一台主机上生成全部的组织证书文件再进行证书分发部署(包括本文),但必须说明的是这种方式必然不能用于生产环境,因为生成组织证书的那台主机将会拥有全部组织的访问权限。在生产环境中,应该每个组织通过自身的 CA 服务生成自身的组织证书,并由单个组织创建通道后使用 Hyperledger Fabric组织的动态添加和删除 中的方法将其它组织加入通道中。 此外,毫无疑问使用 cryptogen 的方式一次性生成所有证书比本文所使用的 fabric-ca 的方式简单很多(不必考虑 DNS 问题)。启动 CA 服务由于要通过 DebainA 生成所有证书文件,所以得先将本地 DNS 指向 DebianA (setDNSTemp.sh):echo "127.0.0.1 council.ifantasy.net" >> /etc/hosts echo "127.0.0.1 soft.ifantasy.net" >> /etc/hosts echo "127.0.0.1 web.ifantasy.net" >> /etc/hosts echo "127.0.0.1 hard.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer1.council.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer2.council.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer3.council.ifantasy.net" >> /etc/hosts echo "127.0.0.1 peer1.soft.ifantasy.net" >> /etc/hosts echo "127.0.0.1 peer1.web.ifantasy.net" >> /etc/hosts echo "127.0.0.1 peer1.hard.ifantasy.net" >> /etc/hosts 复制代码直接运行根目录下的 0_Restart.sh 即可完成本实验所需 CA 服务的启动。docker stop $(docker ps -aq) docker rm $(docker ps -aq) docker rmi $(docker images dev-* -q) # rm -rf orgs data docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d council.ifantasy.net soft.ifantasy.net web.ifantasy.net hard.ifantasy.net 复制代码在前面的实验中,我们每次重启都删除所有的证书文件,但考虑到多机生成证书的复杂性,在这里只清除 docker 镜像而不删除证书文件。注册账户注册账户跟之前没什么不同,直接运行根目录下的 1_RegisterUser.sh 即可完成本实验所需用户的注册。council 用户注册: echo "Working on council" export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@council.ifantasy.net:7050 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name orderer1 --id.secret orderer1 --id.type orderer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name orderer2 --id.secret orderer2 --id.type orderer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name orderer3 --id.secret orderer3 --id.type orderer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name peer1soft --id.secret peer1soft --id.type peer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name peer1web --id.secret peer1web --id.type peer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name peer1hard --id.secret peer1hard --id.type peer -u https://council.ifantasy.net:7050 复制代码soft 用户注册: echo "Working on soft" export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@soft.ifantasy.net:7250 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://soft.ifantasy.net:7250 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://soft.ifantasy.net:7250 复制代码web 用户注册: echo "Working on web" export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@web.ifantasy.net:7350 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://web.ifantasy.net:7350 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://web.ifantasy.net:7350 复制代码hard 用户注册: echo "Working on hard" export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/hard.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/hard.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@hard.ifantasy.net:7450 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://hard.ifantasy.net:7450 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://hard.ifantasy.net:7450 复制代码组织证书构建组织证书构建跟之前的实验一样,直接运行根目录下的 2_EnrollUser.sh 即可完成本实验所需证书的构建。直接运行根目录下的 2_EnrollUser.sh 即可完成本实验所需证书的构建。组织资产预处理: echo "Preparation=============================" mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/assets cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/council.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/council.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/assets cp $LOCAL_CA_PATH/soft.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/assets cp $LOCAL_CA_PATH/web.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/assets cp $LOCAL_CA_PATH/hard.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/assets/tls-ca-cert.pem echo "Preparation end==========================" 复制代码council 证书构建: echo "Start Council=============================" echo "Enroll Admin" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@council.ifantasy.net:7050 # 加入通道时会用到admin/msp,其下必须要有admincers mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/admincerts/cert.pem echo "Enroll Orderer1" # for identity export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://orderer1:orderer1@council.ifantasy.net:7050 mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1/msp/admincerts cp $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1/msp/admincerts/cert.pem # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://orderer1:orderer1@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts orderer1.council.ifantasy.net cp $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1/tls-msp/keystore/key.pem echo "Enroll Orderer2" # for identity export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://orderer2:orderer2@council.ifantasy.net:7050 mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2/msp/admincerts cp $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2/msp/admincerts/cert.pem # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://orderer2:orderer2@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts orderer2.council.ifantasy.net cp $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2/tls-msp/keystore/*_sk $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2/tls-msp/keystore/key.pem echo "Enroll Orderer3" # for identity export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://orderer3:orderer3@council.ifantasy.net:7050 mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3/msp/admincerts cp $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3/msp/admincerts/cert.pem # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://orderer3:orderer3@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts orderer3.council.ifantasy.net cp $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3/tls-msp/keystore/*_sk $LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3/tls-msp/keystore/key.pem mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/council.ifantasy.net/msp/users cp $LOCAL_CA_PATH/council.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/council.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/council.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/council.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/council.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/council.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/council.ifantasy.net/msp/config.yaml echo "End council=============================" 复制代码soft 证书构建: echo "Start Soft=============================" echo "Enroll Admin" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@soft.ifantasy.net:7250 mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/admincerts/cert.pem echo "Enroll Peer1" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://peer1:peer1@soft.ifantasy.net:7250 # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://peer1soft:peer1soft@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.soft.ifantasy.net cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/msp/admincerts cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/msp/admincerts/cert.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/users cp $LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/soft.ifantasy.net/msp/config.yaml echo "End Soft=============================" 复制代码web 证书构建: echo "Start Web=============================" echo "Enroll Admin" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@web.ifantasy.net:7350 mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/admincerts/cert.pem echo "Enroll Peer1" # for identity export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/registers/peer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://peer1:peer1@web.ifantasy.net:7350 # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://peer1web:peer1web@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.web.ifantasy.net cp $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/msp/admincerts cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/msp/admincerts/cert.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/users cp $LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/web.ifantasy.net/msp/config.yaml echo "End Web=============================" 复制代码hard 证书构建: echo "Start Hard=============================" echo "Enroll Admin" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/hard.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/hard.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@hard.ifantasy.net:7450 mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/hard.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/registers/admin1/msp/admincerts/cert.pem echo "Enroll Peer1" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/hard.ifantasy.net/registers/peer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/hard.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://peer1:peer1@hard.ifantasy.net:7450 # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/hard.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://peer1hard:peer1hard@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.hard.ifantasy.net cp $LOCAL_CA_PATH/hard.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/hard.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/registers/peer1/msp/admincerts cp $LOCAL_CA_PATH/hard.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/registers/peer1/msp/admincerts/cert.pem mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/hard.ifantasy.net/msp/users cp $LOCAL_CA_PATH/hard.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/hard.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/hard.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/hard.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/hard.ifantasy.net/msp/config.yaml echo "End Hard=============================" 复制代码在上面操作完成后,已经暂时不需要 CA 服务了,因此先使用 docker stop $(docker ps -aq) 命令关闭正在运行的四个 CA 容器。配置通道配置通道的方法跟单机略有区别,由于我们预期将 peer 和 orderer 服务部署在不同的主机上,因此并不需要使用 docker-compose 启动其它容器,只需要生成通道文件就好。运行根目录下的 3_Configtxgen.sh 即可完成本实验所需通道配置。configtxgen -profile OrgsChannel -outputCreateChannelTx $LOCAL_ROOT_PATH/data/testchannel.tx -channelID testchannel configtxgen -profile OrgsChannel -outputBlock $LOCAL_ROOT_PATH/data/testchannel.block -channelID testchannel cp $LOCAL_ROOT_PATH/data/testchannel.block $LOCAL_CA_PATH/soft.ifantasy.net/assets/ cp $LOCAL_ROOT_PATH/data/testchannel.block $LOCAL_CA_PATH/web.ifantasy.net/assets/ cp $LOCAL_ROOT_PATH/data/testchannel.block $LOCAL_CA_PATH/hard.ifantasy.net/assets/ 复制代码在以上步骤完成后,在 5_FabricNetworkByMultiHost 文件夹下的 data 和 orgs 目录中已经生成了全部网络所需的通道文件和组织证书文件,现在我们将 5_FabricNetworkByMultiHost 文件夹复制一份到 DebianB 主机上开始接下来的实验。以后每次重启网络只需要在每个主机上运行 0_Restart.sh 、 4_JoinChannel_host1.sh 、 4_JoinChannel_host2.sh 、 5_TestChaincode_host1.sh 、 5_TestChaincode_host2.sh 。启动多机网络配置 DNS在上节中,我们为了方便在 DebianA 上生成证书,将所有域名映射都指向了 DebianA 自身,现在需要手动修改 /etc/hosts 文件并删除上节设置的 DNS 映射,然后设置新的 DNS 内容:echo "172.25.1.250 council.ifantasy.net" >> /etc/hosts echo "172.25.1.250 soft.ifantasy.net" >> /etc/hosts echo "172.25.1.251 web.ifantasy.net" >> /etc/hosts echo "172.25.1.251 hard.ifantasy.net" >> /etc/hosts echo "172.25.1.250 orderer1.council.ifantasy.net" >> /etc/hosts echo "172.25.1.250 orderer2.council.ifantasy.net" >> /etc/hosts echo "172.25.1.251 orderer3.council.ifantasy.net" >> /etc/hosts echo "172.25.1.250 peer1.soft.ifantasy.net" >> /etc/hosts echo "172.25.1.251 peer1.web.ifantasy.net" >> /etc/hosts echo "172.25.1.251 peer1.hard.ifantasy.net" >> /etc/hosts 复制代码同样,我们需要在 DebianB 上设置类似的 DNS 映射:echo "172.25.1.250 council.ifantasy.net" >> /etc/hosts echo "172.25.1.250 soft.ifantasy.net" >> /etc/hosts echo "172.25.1.251 web.ifantasy.net" >> /etc/hosts echo "172.25.1.251 hard.ifantasy.net" >> /etc/hosts echo "172.25.1.250 orderer1.council.ifantasy.net" >> /etc/hosts echo "172.25.1.250 orderer2.council.ifantasy.net" >> /etc/hosts echo "172.25.1.251 orderer3.council.ifantasy.net" >> /etc/hosts echo "172.25.1.250 peer1.soft.ifantasy.net" >> /etc/hosts echo "172.25.1.251 peer1.web.ifantasy.net" >> /etc/hosts echo "172.25.1.251 peer1.hard.ifantasy.net" >> /etc/hosts 复制代码启动容器并加入通道DebainA可以直接运行根目录下的 4_JoinChannel_host1.sh 脚本以使 DebianA 执行下列命令启动容器并加入通道:启动本主机容器: source envpeer1soft docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d council.ifantasy.net soft.ifantasy.net peer1.soft.ifantasy.net docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d orderer1.council.ifantasy.net orderer2.council.ifantasy.net 复制代码此时 DebianA 运行的容器网络为: 2. 本主机排序服务加入通道:source envpeer1soft export ORDERER_ADMIN_TLS_SIGN_CERT=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1/tls-msp/signcerts/cert.pem export ORDERER_ADMIN_TLS_PRIVATE_KEY=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer1/tls-msp/keystore/key.pem osnadmin channel join -o orderer1.council.ifantasy.net:7052 --channelID testchannel --config-block $LOCAL_ROOT_PATH/data/testchannel.block --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY" osnadmin channel list -o orderer1.council.ifantasy.net:7052 --ca-file $ORDERER_CA --client-cert $ORDERER_ADMIN_TLS_SIGN_CERT --client-key $ORDERER_ADMIN_TLS_PRIVATE_KEY export ORDERER_ADMIN_TLS_SIGN_CERT=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2/tls-msp/signcerts/cert.pem export ORDERER_ADMIN_TLS_PRIVATE_KEY=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer2/tls-msp/keystore/key.pem osnadmin channel join -o orderer2.council.ifantasy.net:7055 --channelID testchannel --config-block $LOCAL_ROOT_PATH/data/testchannel.block --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY" osnadmin channel list -o orderer2.council.ifantasy.net:7055 --ca-file $ORDERER_CA --client-cert $ORDERER_ADMIN_TLS_SIGN_CERT --client-key $ORDERER_ADMIN_TLS_PRIVATE_KEY 复制代码本主机组织加入通道: source envpeer1soft peer channel join -b $LOCAL_CA_PATH/soft.ifantasy.net/assets/testchannel.block peer channel list 复制代码DebianB可以直接运行根目录下的 4_JoinChannel_host2.sh 脚本以使 DebianB 执行下列命令启动容器并加入通道:启动本主机容器: source envpeer1web docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d web.ifantasy.net peer1.web.ifantasy.net hard.ifantasy.net peer1.hard.ifantasy.net docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d orderer3.council.ifantasy.net 复制代码此时 DebianB 运行的容器网络为: 2. 本主机排序服务加入通道:source envpeer1web export ORDERER_ADMIN_TLS_SIGN_CERT=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3/tls-msp/signcerts/cert.pem export ORDERER_ADMIN_TLS_PRIVATE_KEY=$LOCAL_CA_PATH/council.ifantasy.net/registers/orderer3/tls-msp/keystore/key.pem osnadmin channel join -o orderer3.council.ifantasy.net:7058 --channelID testchannel --config-block $LOCAL_ROOT_PATH/data/testchannel.block --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY" osnadmin channel list -o orderer3.council.ifantasy.net:7058 --ca-file $ORDERER_CA --client-cert $ORDERER_ADMIN_TLS_SIGN_CERT --client-key $ORDERER_ADMIN_TLS_PRIVATE_KEY 复制代码本主机组织加入通道: source envpeer1web peer channel join -b $LOCAL_CA_PATH/web.ifantasy.net/assets/testchannel.block peer channel list source envpeer1hard peer channel join -b $LOCAL_CA_PATH/hard.ifantasy.net/assets/testchannel.block peer channel list 复制代码安装并测试链码由于通道更新需要根据策略进行顺序操作,所以不可以直接运行根目录下的 5_TestChaincode_host1.sh 脚本,而是在不同主机中分别按链码周期运行对应的脚本内容:DebianA 安装链码: source envpeer1soft # peer lifecycle chaincode package basic.tar.gz --path asset-transfer-basic/chaincode-go --label basic_1 peer lifecycle chaincode install basic.tar.gz peer lifecycle chaincode queryinstalled 复制代码DebianB 安装链码: source envpeer1web peer lifecycle chaincode install basic.tar.gz peer lifecycle chaincode queryinstalled source envpeer1hard peer lifecycle chaincode install basic.tar.gz peer lifecycle chaincode queryinstalled 复制代码DebianA 批准链码: export CHAINCODE_ID=basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718 source envpeer1soft peer lifecycle chaincode approveformyorg -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID peer lifecycle chaincode queryapproved -C testchannel -n basic --sequence 1 复制代码此时使用以下命令查看链码批准情况:peer lifecycle chaincode checkcommitreadiness -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --version 1.0 --sequence 1 --init-required 复制代码4. DebainB 批准链码:export CHAINCODE_ID=basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718 source envpeer1web peer lifecycle chaincode approveformyorg -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID peer lifecycle chaincode queryapproved -C testchannel -n basic --sequence 1 source envpeer1hard peer lifecycle chaincode approveformyorg -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID peer lifecycle chaincode queryapproved -C testchannel -n basic --sequence 1 复制代码此时再回到 DebianA 查看链码批准情况发现已同步: 5. DebainB 提交链码:source envpeer1web peer lifecycle chaincode commit -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --init-required --version 1.0 --sequence 1 --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE 复制代码DebainB 初始化链码: source envpeer1web peer chaincode invoke --isInit -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE -c '' 复制代码DebainA 调用链码: peer chaincode invoke -o orderer1.council.ifantasy.net:7051 --tls --cafile $ORDERER_CA --channelID testchannel --name basic --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE -c '' 复制代码参考FootnotesKC Tam. Multi-Host Deployment for First Network (Hyperledger Fabric v2). CSDN. [2020-08-11] ↩ 余府. Hyperledger Fabric 2.x 多机部署/分布式集群部署流程. CSDN. [2020-11-28] ↩
2023年03月22日
9 阅读
0 评论
0 点赞
2023-03-22
Hyperledger Fabric定制联盟链网络工程实践
前言总体来看,网络上成体系的可用的 Fabric 教程极少——不是直接在 Fabric 官网复制内容大谈基础理论就是在描述一个几乎无法复现的项目实践,以至于学习 Fabric 的效率极低,印象最深刻的就是我曾经花费几天时间尝试按照官方教程 CA Deployment steps 搭建自己的 CA 服务,却始终无法成功也找不到原因。因此,为了提高生产效率,本项目虚拟了一个工作室联盟链需求并将逐步实现,致力于提供一个易理解、可复现的Fabric学习项目,其中项目部署步骤的各个环节都清晰可见,并且将所有过程打包为脚本使之能够被快速复现在任何一台主机上。工程介绍组织架构有一启明星工作室,其中包含三大组织:软件组、WEB组、硬件组、理事会,不同组织间相互独立,偶尔有业务往来。现理事会决定搭建一个启明星工作室的联盟链网络,使不同组织间加强合作,期望最终实现以下工程架构:组织说明 council:理事会,负责工作室各组间协调管理,由三组抽调人员共同组成 soft:软件组,专注软件开发 hard:硬件组,专注硬件开发 web:WEB组,专注网站开发 orderer:过渡排序组织,为联盟链网络提供排序服务,后期会舍弃 成员说明 council:一个Orderer节点、三个Admin账号,每组拥有一个Admin账号权限 soft:一个Orderer节点、一个Peer节点、一个Admin账号、一个User账号 hard:一个Orderer节点、一个Peer节点、一个Admin账号、一个User账号 web:一个Orderer节点、一个Peer节点、一个Admin账号、一个User账号 orderer:一个Orderer节点、一个Admin账号 根CA服务器(域名) council.fantasy.com:提供/管理组织间的TLS证书,又叫TLS CA服务器 soft.fantasy.com:提供/管理组织内TLS证书 hard.fantasy.com:提供/管理组织内TLS证书 web.fantasy.com:提供/管理组织内TLS证书 orderer.fantasy.com:提供/管理组织内TLS证书 实验准备在开始前,如果你对 Fabric 命令知之甚少,可以先学习fabric的test-network启动过程Bash源码详解;此外应准备好 Fabric 的开发环境,具体环境搭建和软件版本可参考基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例。为了方便区分各组织和节点,本工程使用域名的方式进行各节点间的通信,以 web 组织为例,域名分配规范如下:域名说明peer1.web.ifantasy.net web组第一个 peer 节点地址peer2.web.ifantasy.netweb组第二个 peer 节点地址orderer1.web.ifantasy.netweb组第一个 orderer 节点地址此外,还需要在 \etc\hosts 文件添加 DNS 地址:echo "127.0.0.1 council.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer.ifantasy.net" >> /etc/hosts echo "127.0.0.1 soft.ifantasy.net" >> /etc/hosts echo "127.0.0.1 web.ifantasy.net" >> /etc/hosts echo "127.0.0.1 hard.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer1.soft.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer1.web.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer1.hard.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer1.orderer.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer2.orderer.ifantasy.net" >> /etc/hosts echo "127.0.0.1 orderer3.orderer.ifantasy.net" >> /etc/hosts echo "127.0.0.1 peer1.soft.ifantasy.net" >> /etc/hosts echo "127.0.0.1 peer1.web.ifantasy.net" >> /etc/hosts echo "127.0.0.1 peer1.hard.ifantasy.net" >> /etc/hosts 复制代码本文工作本项目主要以学习为主,所以并未期望一次实现所有架构和功能。本文所实现的具体内容为,搭建一个简单的工作室联盟链网络,包含 council 、 orderer 、 soft 、 web 四个组织,并将测试链码部署在通道 mychannel ,网络结构为(实验代码已上传至:github.com/wefantasy/F… 的 1_3Org2Peer1Orderer1TLS 目录下):项运行端口说明council.ifantasy.net7050council 组织的 CA 服务, 为联盟链网络提供 TLS-CA 服务orderer.ifantasy.net7150orderer 组织的 CA 服务, 为联盟链网络提供排序服务orderer1.orderer.ifantasy.net7151orderer 组织的 orderer1 成员节点soft.ifantasy.net7250soft 组织的 CA 服务, 包含成员: peer1 、 admin1peer1.soft.ifantasy.net7251soft 组织的 peer1 成员节点web.ifantasy.net7350web 组织的 CA 服务, 包含成员: peer1 、 admin1peer1.web.ifantasy.net7351web 组织的 peer1 成员节点其它说明个人觉得 Fabric 官方示例的证书结构过于冗余,为了便于自己理解,本工程证书结构跟一般 Fabric 有所出入,先将本工程各文件目录说明如下:1_3Org2Peer1Orderer1TLS ├── 0_Restart.sh # 启动基本 CA 网络脚本 ├── 1_RegisterUser.sh # 注册账户脚本 ├── 2_EnrollUser.sh # 登录账户脚本 ├── 3_Configtxgen.sh # 生成创世区块脚本 ├── 4_TestChaincode.sh # 链码测试脚本 ├── asset-transfer-basic # 测试链码目录 ├── basic.tar.gz # 打包后的链码包 ├── compose # Docker配置目录 │ ├── docker-base.yaml # 基础通用配置 │ └── docker-compose.yaml # 具体 Docker 配置 ├── config # Fabric 公共配置目录 │ ├── config-msp.yaml # 节点组织单元配置文件 │ ├── configtx.yaml # 初始通道配置 │ ├── orderer.yaml # orderer 节点配置,osnadmin 的配置文件 │ └── core.yaml # peer 配置 ├── data # 临时数据目录 ├── envpeer1soft # soft 组织的 peer1 cli环境变量 ├── envpeer1web # web 组织的peer1 cli环境变量 ├── orgs # 组织成员证书目录 │ ├── council.ifantasy.net # council 组织目录 │ ├── orderer.ifantasy.net # orderer 组织目录 │ ├── web.ifantasy.net # web组织目录 │ └── soft.ifantasy.net # soft 组织目录 │ ├── assets # 组织公共材料目录 │ │ ├── ca-cert.pem # 本组织根证书 │ │ ├── mychannel.block # mychannel 通道创世区块 │ │ └── tls-ca-cert.pem # TLS-CA 服务根证书 │ ├── ca # 本组织 CA 服务目录 │ │ ├── admin # 本组织 CA 服务引导管理员 msp 目录 │ │ └── crypto # 本组织 CA 服务默认证书目录 │ ├── msp # 组织 MSP 目录 │ │ ├── admincerts # 组织管理员签名证书目录 │ │ ├── cacerts # 组织 CA 服务根证书目录 │ │ ├── config.yaml # 组织节点单元配置文件 │ │ ├── tlscacerts # TLS-CA 服务根证书目录 │ │ └── users # 空目录,msp 规范所需 │ └── registers # 本组织注册的账户目录 │ ├── admin1 # 管理员账户 │ └── peer1 # 节点账户 └── README.md 复制代码实验步骤实验准备首先将基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中的/usr/local/fabric/config目录复制到根目录下。如无特殊说明,环境变量FABRIC_CFG_PATH总是默认指向根目录的config目录(建议直接将本案例仓库 FabricLearn 下的 1_3Org2Peer1Orderer1TLS 目录拷贝到本地运行)。fabric 提供一个 fabric-tools 镜像用于提供操作 peer 节点的命令行,其实现方式是在启动 fabric-tools 时指定 peer 节点的身份证书等环境变量,此外我们也可以直接将这些环境变量写入一个文件中然后通过 source 命令激活。在根目录下创建 envpeer1soft 文件,用于保存 soft 组织的环境变量,写入以下内容:export LOCAL_ROOT_PATH=$PWD export LOCAL_CA_PATH=$LOCAL_ROOT_PATH/orgs export DOCKER_CA_PATH=/tmp export COMPOSE_PROJECT_NAME=fabriclearn export DOCKER_NETWORKS=network export FABRIC_BASE_VERSION=2.4 export FABRIC_CA_VERSION=1.5 复制代码配置TLS服务在根目录下创建 compose 文件夹,用于储存 docker-compose 配置文件。 在 compose 下创建 docker-base.yaml 文件,用于写入公共服务配置,先写入以下内容: version: "2" services: ca-base: image: hyperledger/fabric-ca:$ environment: - FABRIC_CA_SERVER_HOME=$/ca/crypto - FABRIC_CA_SERVER_TLS_ENABLED=true - FABRIC_CA_SERVER_DEBUG=true networks: - $ 复制代码在 compose 下创建 docker-compose.yaml 文件,用于配置工程 docker 容器,写入 council 、 orderer 、 soft 、 web 的 TLS 服务配置: version: '2' networks: network: services: council.ifantasy.net: container_name: council.ifantasy.net extends: file: docker-base.yaml service: ca-base command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050' environment: - FABRIC_CA_SERVER_CSR_CN=council.ifantasy.net - FABRIC_CA_SERVER_CSR_HOSTS=council.ifantasy.net volumes: - $/council.ifantasy.net/ca:$/ca ports: - 7050:7050 orderer.ifantasy.net: container_name: orderer.ifantasy.net extends: file: docker-base.yaml service: ca-base command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050' environment: - FABRIC_CA_SERVER_CSR_CN=orderer.ifantasy.net - FABRIC_CA_SERVER_CSR_HOSTS=orderer.ifantasy.net volumes: - $/orderer.ifantasy.net/ca:$/ca ports: - 7150:7050 soft.ifantasy.net: container_name: soft.ifantasy.net extends: file: docker-base.yaml service: ca-base command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050' environment: - FABRIC_CA_SERVER_CSR_CN=soft.ifantasy.net - FABRIC_CA_SERVER_CSR_HOSTS=soft.ifantasy.net volumes: - $/soft.ifantasy.net/ca:$/ca ports: - 7250:7050 web.ifantasy.net: container_name: web.ifantasy.net extends: file: docker-base.yaml service: ca-base command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050' environment: - FABRIC_CA_SERVER_CSR_CN=web.ifantasy.net - FABRIC_CA_SERVER_CSR_HOSTS=web.ifantasy.net volumes: - $/web.ifantasy.net/ca:$/ca ports: - 7350:7050 复制代码启动各组织的 TLS 服务: source envpeer1soft docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d council.ifantasy.net orderer.ifantasy.net soft.ifantasy.net web.ifantasy.net 复制代码注册账户注册 council 组织账户。首先设置 council 的环境变量:export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/ca/admin 复制代码 然后使用 enroll 登录引导账户, 它会以 FABRIC_CA_CLIENT_TLS_CERTFILES 指向的 CA 服务器根证书加密通信,并将生成的身份证书保存在 FABRIC_CA_CLIENT_HOME 指向的工作目录下1:fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@council.ifantasy.net:7050 复制代码 注意: enroll 操作结果是保存账号的身份证书至指定目录下,以后就可以直接根据该目录下的证书来使用对应身份,跟传统 web 系统的登录操作类似所以被我称为登录,但实际上有所区别。 然后便可以 ca-admin 身份进行注册其它用户的操作:fabric-ca-client register -d --id.name orderer1 --id.secret orderer1 --id.type orderer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name peer1soft --id.secret peer1soft --id.type peer -u https://council.ifantasy.net:7050 fabric-ca-client register -d --id.name peer1web --id.secret peer1web --id.type peer -u https://council.ifantasy.net:7050 复制代码 council 为其它组织提供 TLS-CA 服务的具体实现就是为其它组织提供 council 可验证的合法账户,其他组织使用这些账户进行通信就是可信的。后面注册步骤与上面类似,故不再赘述。 注册 orderer 组织账户:export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/orderer.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@orderer.ifantasy.net:7150 fabric-ca-client register -d --id.name orderer1 --id.secret orderer1 --id.type orderer -u https://orderer.ifantasy.net:7150 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://orderer.ifantasy.net:7150 复制代码 注册 soft 组织账户:export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@soft.ifantasy.net:7250 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://soft.ifantasy.net:7250 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://soft.ifantasy.net:7250 复制代码 注册 web 组织账户:export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/ca/crypto/ca-cert.pem export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/ca/admin fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@web.ifantasy.net:7350 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://web.ifantasy.net:7350 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://web.ifantasy.net:7350 复制代码 构造组织成员证书在各组织下创建 assets 目录,用于储存本组织根证书和用于组间通信的 LTS-CA 根证书:mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/assets cp $LOCAL_CA_PATH/orderer.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/assets cp $LOCAL_CA_PATH/soft.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/assets cp $LOCAL_CA_PATH/web.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem 复制代码 构造 orderer 组织成员证书。登录 orderer 管理员账户 admin1 :export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@orderer.ifantasy.net:7150 复制代码 注意:这里是登录上节我们注册的管理员账户而非启动 CA 服务时的引导账户,引导账户跟管理员账户的区别也是我至今难以理解的地方 以上命令成功后便可以看到 FABRIC_CA_CLIENT_HOME/FABRIC_CA_CLIENT_MSPDIR 目录下生成的证书文件。然后需要构造 admin1 的 msp 目录:mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/admincerts/cert.pem 复制代码 这里的操作仅仅是将 admin1 的签名证书复制到新建的 admincerts 文件夹下,这样做的原因是 Fabric 的 MSP 规范要求其下需有 admincerts 目录,否则后面操作组织 peer 节点时会报错,因此建议在所有联盟链网络服务节点的 msp 目录下添加 admincerts 证书。然后登录 orderer 的 orderer1 的组织内账户:export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://orderer1:orderer1@orderer.ifantasy.net:7150 mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/msp/admincerts cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/msp/admincerts/cert.pem 复制代码 然后登录 orderer 的 orderer1 的组织间 TLS-CA 账户:export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://orderer1:orderer1@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts orderer1.orderer.ifantasy.net cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/keystore/key.pem 复制代码 最后一步便是构造 orderer 的组织 MSP 目录2(MSP 目录说明可参考 MSP结构):mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/users cp $LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/orderer.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/orderer.ifantasy.net/msp/config.yaml 复制代码 上面命令最后一行会在组织 msp 目录下添加节点组织单元配置文件 config.yaml ,其原理可以参考 节点组织单元和MSP ,如果缺少该文件或者文件内容错误,会报以下错误:loadLocalMSP -> Failed to setup local msp with config: administrators must be declared when no admin ou classification is set 复制代码 后面的流程跟这里类似,因此不再赘述。 构造 soft 组织成员证书: echo "Start Soft=============================" echo "Enroll Admin" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@soft.ifantasy.net:7250 mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/admincerts/cert.pem echo "Enroll Peer1" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://peer1:peer1@soft.ifantasy.net:7250 # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://peer1soft:peer1soft@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.soft.ifantasy.net cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/msp/admincerts cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/msp/admincerts/cert.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/users cp $LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/soft.ifantasy.net/msp/config.yaml echo "End Soft=============================" 复制代码构造 web 组织成员证书: echo "Start Web=============================" echo "Enroll Admin" export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/registers/admin1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://admin1:admin1@web.ifantasy.net:7350 mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/admincerts cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/admincerts/cert.pem echo "Enroll Peer1" # for identity export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/registers/peer1 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem export FABRIC_CA_CLIENT_MSPDIR=msp fabric-ca-client enroll -d -u https://peer1:peer1@web.ifantasy.net:7350 # for TLS export FABRIC_CA_CLIENT_MSPDIR=tls-msp export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem fabric-ca-client enroll -d -u https://peer1web:peer1web@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.web.ifantasy.net cp $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/msp/admincerts cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/msp/admincerts/cert.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/admincerts mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/cacerts mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/tlscacerts mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/users cp $LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/cacerts/ cp $LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/tlscacerts/ cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/admincerts/cert.pem cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/web.ifantasy.net/msp/config.yaml echo "End Web=============================" 复制代码配置系统通道及测试通道在 config 目录下创建 configtx.yaml 配置文件,文件太长在此不做展示,可以在 FabricLearn 中查看,其中各项已加说明注释3。 通过 configtxgen 生成创世区块和测试通道: configtxgen -profile OrgsOrdererGenesis -outputBlock $LOCAL_ROOT_PATH/data/genesis.block -channelID syschannel configtxgen -profile OrgsChannel -outputCreateChannelTx $LOCAL_ROOT_PATH/data/mychannel.tx -channelID mychannel 复制代码 在 compose/docker-compose.yaml 文件中添加 peer 和 orderer 服务相关配置: peer1.soft.ifantasy.net: container_name: peer1.soft.ifantasy.net extends: file: docker-base.yaml service: peer-base environment: - CORE_PEER_ID=peer1.soft.ifantasy.net - CORE_PEER_ADDRESS=peer1.soft.ifantasy.net:7051 - CORE_PEER_LOCALMSPID=softMSP - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.soft.ifantasy.net:7051 volumes: - $/soft.ifantasy.net/registers/peer1:$/peer ports: - 7251:7051 peer1.web.ifantasy.net: container_name: peer1.web.ifantasy.net extends: file: docker-base.yaml service: peer-base environment: - CORE_PEER_ID=peer1.web.ifantasy.net - CORE_PEER_ADDRESS=peer1.web.ifantasy.net:7051 - CORE_PEER_LOCALMSPID=webMSP - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.web.ifantasy.net:7051 volumes: - $/web.ifantasy.net/registers/peer1:$/peer ports: - 7351:7051 orderer1.orderer.ifantasy.net: container_name: orderer1.orderer.ifantasy.net extends: file: docker-base.yaml service: orderer-base environment: - ORDERER_HOST=orderer1.orderer.ifantasy.net - ORDERER_GENERAL_LOCALMSPID=ordererMSP volumes: - $/orderer.ifantasy.net/registers/orderer1:$/orderer - $/data/genesis.block:$/orderer/genesis.block ports: - 7151:7777 复制代码 启动 peer 和 orderer 服务: docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d peer1.soft.ifantasy.net peer1.web.ifantasy.net orderer1.orderer.ifantasy.net 复制代码 此时我们已经启动了所有联盟链网络所需的容器如下: (base) root@DebianA:1_3Org2Peer1Orderer1TLS# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c59b88fa847 hyperledger/fabric-peer:2.4 "peer node start" 8 seconds ago Up 6 seconds 0.0.0.0:7251->7051/tcp peer1.soft.ifantasy.net 3906338f6861 hyperledger/fabric-peer:2.4 "peer node start" 8 seconds ago Up 6 seconds 0.0.0.0:7351->7051/tcp peer1.web.ifantasy.net 9f127a054343 hyperledger/fabric-orderer:2.4 "orderer" 8 seconds ago Up 6 seconds 7050/tcp, 0.0.0.0:7151->7777/tcp orderer1.orderer.ifantasy.net 949abd8f7070 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 7054/tcp, 0.0.0.0:7150->7050/tcp orderer.ifantasy.net 011fe2b36c01 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 0.0.0.0:7050->7050/tcp, 7054/tcp council.ifantasy.net 207879f5bb33 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 7054/tcp, 0.0.0.0:7350->7050/tcp web.ifantasy.net d1850c86e096 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 7054/tcp, 0.0.0.0:7250->7050/tcp soft.ifantasy.net 复制代码 补全根目录中 envpeer1soft 的环境变量: export LOCAL_ROOT_PATH=$PWD export LOCAL_CA_PATH=$LOCAL_ROOT_PATH/orgs export DOCKER_CA_PATH=/tmp export COMPOSE_PROJECT_NAME=fabriclearn export DOCKER_NETWORKS=network export FABRIC_BASE_VERSION=2.4 export FABRIC_CA_VERSION=1.5 echo "init terminal soft" export FABRIC_CFG_PATH=$LOCAL_ROOT_PATH/config export CORE_PEER_TLS_ENABLED=true export CORE_PEER_LOCALMSPID="softMSP" export CORE_PEER_ADDRESS=peer1.soft.ifantasy.net:7251 export CORE_PEER_TLS_ROOTCERT_FILE=$LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem export CORE_PEER_MSPCONFIGPATH=$LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp export ORDERER_CA=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem 复制代码 复制 envpeer1soft 为 envpeer1web 作为 web 组织的环境变量: export LOCAL_ROOT_PATH=$PWD export LOCAL_CA_PATH=$LOCAL_ROOT_PATH/orgs export DOCKER_CA_PATH=/tmp export COMPOSE_PROJECT_NAME=fabriclearn export DOCKER_NETWORKS=network export FABRIC_BASE_VERSION=2.4 export FABRIC_CA_VERSION=1.5 echo "init terminal web" export FABRIC_CFG_PATH=$LOCAL_ROOT_PATH/config export CORE_PEER_TLS_ENABLED=true export CORE_PEER_LOCALMSPID="webMSP" export CORE_PEER_ADDRESS=peer1.web.ifantasy.net:7351 export CORE_PEER_TLS_ROOTCERT_FILE=$LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem export CORE_PEER_MSPCONFIGPATH=$LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp export ORDERER_CA=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem 复制代码 通过 soft 创建 mychannel 测试通道的创世区块: source envpeer1soft peer channel create -c mychannel -f $LOCAL_ROOT_PATH/data/mychannel.tx -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --outputBlock $LOCAL_ROOT_PATH/data/mychannel.block 复制代码 如果出现以下错误,请检查环境变量 FABRIC_CFG_PATH 所指目录是否包含 core.yaml 配置文件: InitCmd -> ERRO 001 Fatal error when initializing core config : Could not find config file. Please make sure that FABRIC_CFG_PATH is set to a path which contains core.yaml 复制代码 如果出现以下错误,请检查环境变量 CORE_PEER_TLS_ROOTCERT_FILE 是否只想 TLS-CA 根证书、 环境变量 ORDERER_CA 是否指向 orderer1 的 TLS-CA 根证书: ERRO 002 Client TLS handshake failed after 1.116738ms with error: x509: certificate is not valid for any names, but wanted to match localhost remoteaddress=127.0.0.1:7151 复制代码 将 mychannel 创世区块复制到其成员组织目录: cp $LOCAL_ROOT_PATH/data/mychannel.block $LOCAL_CA_PATH/soft.ifantasy.net/assets/ cp $LOCAL_ROOT_PATH/data/mychannel.block $LOCAL_CA_PATH/web.ifantasy.net/assets/ 复制代码 分别通过成员组织的 cli 加入通道: source envpeer1soft peer channel join -b $LOCAL_CA_PATH/soft.ifantasy.net/assets/mychannel.block source envpeer1web peer channel join -b $LOCAL_CA_PATH/web.ifantasy.net/assets/mychannel.block 复制代码 如果出现以下错误,请检查环境变量 CORE_PEER_ADDRESS 是否与对应组织的 docker 配置中的 peer 地址和端口是否一致: Client TLS handshake failed after 1.554615ms with error: x509: certificate is valid for peer1soft, peer1.soft.ifantasy.net, not soft.ifantasy.net remoteaddress=127.0.0.1:7251 复制代码 成功后,便可通过 peer channel getinfo -c mychannel 查看已加入通道: 安装/测试链码soft 打包并安装链码: source envpeer1soft peer lifecycle chaincode package basic.tar.gz --path asset-transfer-basic/chaincode-go --label basic_1 peer lifecycle chaincode install basic.tar.gz 复制代码 安装成功后,可使用 peer lifecycle chaincode queryinstalled 命令查询已安装链码信息(其中 Package ID 需要记下来): (base) root@DebianA:1_3Org2Peer1Orderer1TLS# peer lifecycle chaincode queryinstalled Installed chaincodes on peer: Package ID: basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718, Label: basic_1 复制代码 web 安装链码: source envpeer1web peer lifecycle chaincode install basic.tar.gz 复制代码 设置链码 ID 环境变量: export CHAINCODE_ID=basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718 复制代码 soft 和 web 批准链码: source envpeer1soft peer lifecycle chaincode approveformyorg -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID source envpeer1web peer lifecycle chaincode approveformyorg -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID 复制代码 批准后,可使用以下命令查看本组织的链码批准情况: (base) root@DebianA:1_3Org2Peer1Orderer1TLS# peer lifecycle chaincode queryapproved -C mychannel -n basic --sequence 1 Approved chaincode definition for chaincode 'basic' on channel 'mychannel': sequence: 1, version: 1.0, init-required: true, package-id: basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718, endorsement plugin: escc, validation plugin: vscc 复制代码 也可使用以下命令查看指定链码是否已准备好被提交: (base) root@DebianA:1_3Org2Peer1Orderer1TLS# peer lifecycle chaincode checkcommitreadiness -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --version 1.0 --sequence 1 --init-required Chaincode definition for chaincode 'basic', version '1.0', sequence '1' on channel 'mychannel' approval status by org: softMSP: true webMSP: true 复制代码 使用任意合法组织提交链码: source envpeer1soft peer lifecycle chaincode commit -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --init-required --version 1.0 --sequence 1 --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE 复制代码 可使用以下命令查看链码提交情况: peer lifecycle chaincode querycommitted --channelID mychannel --name basic -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE 复制代码 初始化链码(非必须): peer chaincode invoke --isInit -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE -c '' 复制代码 其中带 --isInit 参数表示当前调用为链码初始化调用,在不需要初始化的链码中可以省略此步骤。如果出现下列错误,请检查: 整个 docker 内的 networks 的值必须为 $ 环境变量中 COMPOSE_PROJECT_NAME 和 DOCKER_NETWORKS 是否被赋值、 docker-base.yaml 中 CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE 的值必须是 $_$ error starting container: error starting container: API error (404): network hyperledger_fabric-ca not found"复制代码 调用链码: peer chaincode invoke -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE -c '' 复制代码 如果出现下列错误,请检查 approveformyorg 的链码包 ID 与 install 的链码包 ID 必须一致: endorsement failure during invoke. response: status:500 message:"make sure the chaincode fabcar has been successfully defined on channel mychannel and try again: chaincode definition for 'basic' exists, but chaincode is not installed" 复制代码 调用成功后可在控制台查看链码输出: 2022-04-05 14:25:16.529 CST 0001 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200 payload:"[,,,,,]" 复制代码 参考FootnotesNisen. Fabric账号、cryptogen和fabirc-ca. github.io. [2018-06-19] ↩ Hyperledger. 成员服务提供者 (MSP). hyperledger-fabric.readthedocs.io. [2021-05-22] ↩ hubwiz.com. configtx.yaml中文详解. hubwiz.com. [2019-04-24 ] ↩
2023年03月22日
6 阅读
0 评论
0 点赞
2023-03-15
Aptos DAPP之智能合约编写
背景在之前的文章中我们介绍了如何在aptos上编译和发布模块,也就是智能合约,而智能合约发布之后就可以与之交互,而对于一般用户而言,与智能合约的交互就是通过DAPP,接下来几篇文章将会介绍如何从零开始在aptos上构建一个DAPP。准备工作首先我们需要创建一个目录my-first-dapp,然后进入该目录创建一个move目录用于存放智能合约的代码 然后我们在move目录下使用aptos move init --name my_todo_list命令,该命令会创建一个sources目录和Move.tom文件。 什么是Move.toml文件一个Move.toml文件是一个配置文件,其中包括了一些元数据如名字、版本号和包的依赖,我们使用命令创建的Move.toml内容如下:[package] name = 'my_to_list' version = '1.0.0' [dependencies.AptosFramework] git = 'https://github.com/aptos-labs/aptos-core.git' rev = 'main' subdir = 'aptos-move/framework/aptos-framework' 复制代码我们可以看到包信息和一个AptosFramework的依赖,其中的name属性就是我们使用--name指定的属性,其中的AptosFrame依赖指向github仓库main分支aptos-core/aptos-move/framework/aptos-framework。sources目录sources目录是包含一系列.move模块文件的目录,之后我们想要使用命令行编译时编译器会寻找sources目录以及与其相关的Move.toml文件。创建Move模块正如上篇文章我们所提到的,当我们发布一个Move模块时我们需要一个账户,所以我们需要创建一个帐户,一旦我们拥有了一个账户的私钥,我们就可以在该账户下创建一个模块,也可以使用该账户发布模块。在move目录下使用aptos init --network devnet命令,当有提示时直接回车确。这个命令为我们创建了.aptos目录,其中包含了config.yaml文件,这个文件包含了一些描述信息,其中的内容如下:profiles: default: private_key: "0x664449b9aefa4694d6871b0025e84dc173a64c58c5dbf413478e79048bc5f6e9" public_key: "0xca1b0da9a12a3e51fdab6809e3c4bf2668379bdc62573f80b70da5b5635a0a19" account: 6f2dea63c25fcfa946dd54d002e11ec0de56fb37b0cb215396dd079872fc49eb rest_url: "https://fullnode.devnet.aptoslabs.com" faucet_url: "https://faucet.devnet.aptoslabs.com" 复制代码从现在开始,我们在move目录下使用命令行时会自动带上这些默认信息,需要注意的是我们使用的是devnet网络,我们最后也会将我们的包发布到测试网上去。正如之前所提到的我们的sources目录包含.move的模块文件,所以我们来添加我们第一个Move文件,打开Move.toml文件,在其中添加一下信息,其中的default-profile-account-addres就是我嘛从config.yaml文件中获取的account信息。[addresses] todolist_addr='<default-profile-account-address>' 复制代码所以我的Move.toml更改后如下:[addresses] todolist_addr='6f2dea63c25fcfa946dd54d002e11ec0de56fb37b0cb215396dd079872fc49eb' 复制代码然后在sources目录下创建todolist.move文件,其代码内容如下:module todolist_addr::todolist { } 复制代码一个Move模块需要存储在一个地址上,所以当它发布时可以通过该地址访问该模块,在我们的模块中,账户地址就是todolist_addr,也就是我们之前在Move.toml配置的,todolist是模块名。合约逻辑在正式去写代码前我们需要理解我们需要写的智能合约的功能,为易于理解我,我简化了智能合约的逻辑如下:一个账户可以创建一个新的列表 一个账户可以在列表上创建一个新的任务,无论谁创建一个新的任务都会提交一个task_created的任务 一个账户可以将它们的任务标记为完成 创建一个事件不是必须的,但是如果一个开发者想要监控数据,比如多少用户创建了新的任务,可以使用Aotos_Indexer我们可以定义一个TodoList结构体,其内容如下:task数组 一个新的task事件 一个task计数器,其用于记录创建的task的数量,我们可以以此区分不同的task。 我们也需要创建一个Task的结构体,其内容如下:task ID,从TodoList1的task计数器获取 address,创建task的账户地址 content,task的内容 completed,一个boolean标记任务是否完成 这两个结构体的定义如下:struct TodoList has key { tasks: Table<u64, Task>, set_task_event: event::EventHandle<Task>, task_counter: u64 } struct Task has store, drop, copy { task_id: u64, address: address, content: String, completed: bool } 复制代码我们可以看到TodoList拥有key能力,key能力允许结构体被当作一个存储标识符,换句话说,key能力代表了可以被存储在顶层并且表现的像一个存储空间,在这里我们需要TodoList称为一个资源存储在用户的账户里,当一个结构体拥有key能力,这个结构体就会转化为一个资源(resource),资源是存储在一个账户下面,因此只能被这个账户赋值和获取。Task则是拥有store,drop和copy的能力。store,Task需要能被存储在其他结构体内如TodoList copy, 值可以被拷贝 drop,值可以被丢弃 关于结构体的四种能力更详细的可以看之前Move的相关文章。 我们应编写了需要结构体,现在来尝试编译一下代码,可以在move目录下使用aptos move compile编译代码,可以看到发生了Unbound type错误,错误如下:error[E03004]: unbound type ┌─ /Users/xilou/blockchain/blog/my-first-dapp/move/sources/todolist.move:3:16 │ 3 │ tasks: Table<u64, Task>, │ ^^^^^ Unbound type 'Table' in current scope error[E03002]: unbound module ┌─ /Users/xilou/blockchain/blog/my-first-dapp/move/sources/todolist.move:4:25 │ 4 │ set_task_event: Event::EventHandle<Task>, │ ^^^^^ Unbound module alias 'Event' error[E03004]: unbound type ┌─ /Users/xilou/blockchain/blog/my-first-dapp/move/sources/todolist.move:11:18 │ 11 │ content: String, │ ^^^^^^ Unbound type 'String' in current scope { "Error": "Move compilation failed: Compilation error" } 复制代码这是由于我们使用了一下没有import的类型,所以编译器无法获取他们,在模块的顶部加上以下代码use aptos_framework::event; use std::string::String; use aptos_std::table::Table; 复制代码然后再编译就可以编译成功,其返回结果如下INCLUDING DEPENDENCY AptosFramework INCLUDING DEPENDENCY AptosStdlib INCLUDING DEPENDENCY MoveStdlib BUILDING my_to_list { "Result": [ "6f2dea63c25fcfa946dd54d002e11ec0de56fb37b0cb215396dd079872fc49eb::todolist" ] } 复制代码创建列表一个账户最先做的事情是创建一个新的列表,创建一个新的列表需要提交一次交易,所以我们需要知道signer,也就是谁提交了交易,其函数定义如下:public entry fun create_list(account: &signer) { } 复制代码我们来看看其中的关键entry,一个entry函数可以被一次交易调用,当我们需要发起一次链上交易时我们就需要调用一个entry函数 &signer,singer参数是会被Move虚拟机劫持当做签名交易的地址 我们的代码有一个TodoList资源,资源是被存储在一个账户下的,所以其只能被该账户获取和赋值,这意味着我们创建一个TodoList我们需要将其赋值给一个账户,create_list函数需要处理TodoList的创建,其完整代码如下:public entry fun create_list(account: &signer) { let task_holer = TodoList { tasks: table::new(), set_task_event: account::new_event_handle<Task>(account), task_count: 0 }; move_to(account, tasks_holder); } 复制代码我们使用了account模块,所以需要使用以下代码添加use aptos_framework::account; 复制代码创建task函数正如之前所说,我们需要一个创建task的函数,从而能使一个账户创建一个新的task,创建一个task也是需要提交一个交易,所以我们需要知道signer和task的content:public entry fun create_task(account: &signer, content: String) acquires TodoList { //获取地址 let signer_address = signer::address_of(account); //获取TodoList资源 let todo_list = borrow_global_mut<TodoList>(signer_address); //task计数器计数 let counter = todo_list.task_counter + 1; //创建一个新的task let new_task = Task { task_id: counter, address: signer_address, content, completed: false }; table::upsert(&mut todo_list.tasks, counter, new_task); todo_list.task_counter = counter; event::emit_event<Task>( &mut borrow_global_mut<TodoList>(signer_address).set_task_event, new_task, ) } 复制代码由于我们使用了新的模块,我们需要引入signer和table,可以使用以下代码:use std::signer; use aptos_std::table::; // This one we already have, need to modify it 复制代码task完成函数我们还需要一个函数去标记task已经完成public entry fun complete_task(account: &signer, task_id: u64) acquires TodoList { // 获取signer地址 let signer_address = signer::address_of(account); // 获取TodoList资源 let todo_list = borrow_global_mut<TodoList>(signer_address); // 根据task id获取相应的task let task_record = table::borrow_mut(&mut todo_list.tasks, task_id); // 更新任务未已完成 task_record.completed = true; } 复制代码然后我们还可以使用aptos move compile进行编译增加验证我们主要的逻辑已经写完了,但是还是希望在创建新task和更新task前加一些验证,从而保证我们的函数能够正常工作。public entry fun create_task(account: &signer, content: String) acquires TodoList { // gets the signer address let signer_address = signer::address_of(account); // 验证已经创建了一个列表 assert!(exists<TodoList>(signer_address), 1); ... } 复制代码public entry fun complete_task(account: &signer,task_id: u64) acquires TodoList { // gets the signer address let signer_address = signer::address_of(account); // 验证已经创建了列表 assert!(exists<TodoList>(signer_address), 1); let todo_list = borrow_global_mut<TodoList>(signer_address); // 验证task存在 assert!(table::contains(&todo_list.tasks, task_id), 2); let task_record = table::borrow_mut(&mut todo_list.tasks, task_id); // 验证task未完成 assert!(task_record.completed == false, 3); task_record.completed = true; } 复制代码可以看到assert接受两个参数,第一个是检查内容,第二个是错误码,对于错误码我们最好可以提前定义。const E_NOT_INITIALIZED: u64 = 1; const ETASK_DOESNT_EXIST: u64 = 2; const ETASK_IS_COMPLETED: u64 = 3; 复制代码添加测试主要逻辑已经完成,现在需要添加测试,测试函数可以用#[test]标识,在代码最后添加如下代码:#[test] public entry fun test_flow() { } 复制代码我们需要完成以下测试创建列表 创建任务 更新任务已完成 代码如下#[test(admin = @0x123)] public entry fun test_flow(admin: signer) acquires TodoList { account::create_account_for_test(signer::address_of(&admin)); create_list(&admin); create_task(&admin, string::utf8(b"new task")); let task_count = event::counter(&borrow_global<TodoList>(signer::address_of(&admin)).set_task_event); assert!(task == 1, 4); let todo_list = borrow_global<TodoList>(signer::address_of(&admin)); assert!(todo_list.task_counter == 1, 5); let task_record = table::borrow(&todo_list.tasks, todo_list.task_count); assert!(task_record.task_id == 1, 6); assert!(task_record.completed == false, 7); assert!(task_record.content == string::utf8(b"new task"), 8); assert!(task_record.address == signer::address_of(&admin), 9); complete_task(&admin, 1); let todo_list = borrow_global<TodoList>(signer::address_of(&admin)); let task_record = table::borrow(&todo_list.tasks, 1); assert!(task_record.task_id == 1, 10); assert!(task_record.completed == true, 11); assert!(task_record.content == string::utf8(b"new task"), 12); assert!(task_record.address == signer::address_of(&admin), 13); } 复制代码由于我们的测试运行在我们的账户的范围之外,所以需要创建一个测试账户,我是使用了一个admin账户,其地址为@0x123,在正式运行测试之前,我们需要使用以下语句引入模块use std::string::; // already have it, need to modify 复制代码使用aptos move test进行测试,结果如下INCLUDING DEPENDENCY AptosFramework INCLUDING DEPENDENCY AptosStdlib INCLUDING DEPENDENCY MoveStdlib BUILDING my_to_list Running Move unit tests [ PASS ] 0x6f2dea63c25fcfa946dd54d002e11ec0de56fb37b0cb215396dd079872fc49eb::todolist::test_flow Test result: OK. Total tests: 1; passed: 1; failed: 0 { "Result": "Success" } 复制代码发布模块我们在move目录下使用命令aptos move compile编译模块,报错如下 use std::string::; │ ^^^^^^ Unused 'use' of alias 'string'. Consider removing it 复制代码那是因为我们在测试模块中使用了string,但是在正式合约代码中未使用,改成如下即可use std::string::String; // change to this ... #[test_only] use std::string; // add this 复制代码使用aptos move puhlish发布模块,遇到提示直接回车继续 ,结果如下{ "Result": { "transaction_hash": "0x0e443ef21c8b19783c06741eb4a5306f11b1529664cf39e4f86fd6679e658686", "gas_used": 1675, "gas_unit_price": 100, "sender": "6f2dea63c25fcfa946dd54d002e11ec0de56fb37b0cb215396dd079872fc49eb", "sequence_number": 0, "success": true, "timestamp_us": 1678615900086281, "version": 1605342, "vm_status": "Executed successfully" } } 复制代码最后这篇文章主要讲述了DAPP中智能合约的编写,更多文章可以关注公众号QStack。
2023年03月15日
5 阅读
0 评论
0 点赞
2023-03-11
一文读懂比特币、区块链、web3.0之间的关系(⊙ˍ⊙)
什么是比特币???比特币简称BTC(Bitcoin),是P2P(将小额资金聚集起来对有资金需求的一种小额借款模式,已接入征信系统)形式的数字货币,也是加密货币。 它的核心技术就是区块链,使用密码学技术确保货币交易的安全性和不可篡改性,完全中心化,意思为它不接受任何政府和金融机构的控制,而是依赖于网络上的节点和矿工,可以在网络上进行匿名交易,数量有限,限制为2100万个,可以通过挖矿或购买交易所中心的现有货币获取 比特币的交易数据会打包到一个”数据块“,区块链接收到第一个区块后,交易会得到进一步的确认,在连续得到6个区块之后,交易基本就不可逆转的得到了确认。 所有的交易历史都会存储到区块链中,持续延长,新区块一旦加入就不会被移走,每隔10分钟就会有新的区块增加上去。 货币特征: 中心化、全世界流通、专属所有权、低交易费用、无隐藏成本、跨平台挖掘优点: 无发行机构、可匿名、免税、跨境汇款不会留下跨境交易记录什么是区块链???一串数据串组成的数据库,多方共同维护,一起达成共识写入数据,不会有人单方面控制数据。每个计算机自己计算自己的账,变成共同记账,数据也就保持了一致性、公开透明。 每个数据块(即“区块”)都包含了一定数量的交易记录和其它元数据,同时包含了前一区块的数字指纹既哈希值,形成了一个不可篡改的“链”,区块链只许写入不可删除和修改。 可是陌生网络交易如果能够获得对方的信任呢,区块链节点会审核到对方节点信息是否属实,若发现不属实会自动原路退回到账户中。 目前,区块链技术已广泛应用于数字货币(比如比特币)、智能合约、供应链管理、物联网、医疗保健、民生、政务、司法、能源、制造业等等。 什么是web3.0???web3.0是互联网的第三次迭代,特点在于基于去中心化和基于区块链技术,web 3.0 的核心内涵就是信息的高度整合和高度的智能化服务,将分散式的应用程序和服务(dApps)带入了Web,为用户提供了更加隐私安全的体验。web3.0和web2.0发生变化的是思想的创新,可以解决社会信息优化信息聚合的问题,所以主观的核心就是高度的智能化服务web2.0web3.0可读写,交互式互联网可读写、可拥有、多方互动、契约互联网社交、电商、媒体图文、交互需求、用户参与度、社交和自媒体时代以数字化契约(共识系统+智能合约)代替互联网的中介角色,图文+交互+用户拥有所有权人和人之间互动为中心,聚集在平台用户为中心,强调自主用户创造、平台所有、控制、分配用户创造、用户所有、控制、参与分配最新的应用场景都有哪些呢?互联网是资金、合约以及各种数据化价值资产的互通,就会出现信任问题,所以基于区块链技术的互联网可信度就被指出,目前web3.0的大概指可读+可写+可信任,在信任的基础上搭建了一个生活化的互联网虚拟场景,页面展示从2D转3d具有的特点?1、api(应用程序编程接口)是全球范围的,也就是XMLWebServices 2、速度达到10G,应用不用担心速度问题 3、是一个技术框架或操作系统它们之间的关系比特币使用了区块链技术来实现一个去中心化的数字货币系统。在比特币系统中,所有的交易都被记录在区块链中,并且每个参与者都可以验证这些交易的有效性。 比特币是第一个基于区块链技术的加密货币,区块链是一种去中心化的数据库加密技术,而web3是区块链技术在互联网上的应用。 Web3是区块链技术在互联网上的应用。它包括了许多新兴技术,如去中心化应用程序(DApp)、智能合约、数字身份和数字资产等。通过使用Web3技术,用户可以直接与区块链系统进行交互,而不需要依赖中心化的第三方机构。 比特币是区块链技术的第一个应用,区块链技术提供了比特币系统的核心功能,而Web3则是区块链技术在互联网上的应用,为用户提供了更多的服务和功能。
2023年03月11日
4 阅读
0 评论
0 点赞
2023-03-10
使用Hardhat进行合约测试
Hardhat是一个开源的以太坊开发框架,简单好用、可扩展、可定制的特点让它在开发者中间很受欢迎。Hardhat在支持编辑、编译、调试和部署合约方面都非常的方便,也有很多功能可以使合约测试工作更加高效和便捷,本文就是聚焦在合约测试领域,探寻Hardhat的特点和日常测试过程中的一些使用技巧。一、环境准备可以参考Hardhat官网教程,进行环境的准备和Hardhat安装。Hardhat提供了快速构建合约工程的方法:建立空的工程目录 在目录下执行npx hardhat 根据交互提示完成Hardhat工程的创建 二、示例合约与测试方法快速创建Hardhat工程,可以在contract目录下看到Lock.sol的合约,此合约是一个简单的示例,实现了在指定时间前(unlockTime)锁定资产的功能。 // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; // Uncomment this line to use console.log import "hardhat/console.sol"; contract Lock { uint public unlockTime; address payable public owner; event Withdrawal(uint amount, uint when); constructor(uint _unlockTime) payable { require( block.timestamp < _unlockTime, "Unlock time should be in the future" ); unlockTime = _unlockTime; owner = payable(msg.sender); } function withdraw() public { // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); require(block.timestamp >= unlockTime, "You can't withdraw yet"); require(msg.sender == owner, "You aren't the owner"); emit Withdrawal(address(this).balance, block.timestamp); owner.transfer(address(this).balance); } } 复制代码同时,在test目录下,有Lock.ts(或Lock.js)的测试代码,测试代码里分别展示了对合约部署,合约中涉及的功能的测试。其中值得学习的部分:一是定义了一个具有setup功能的函数,此函数定义了一些状态变量的初始状态,后面在每次测试代码运行前,可以通过loadFixture方法执行此函数,把状态变量还原到函数中定义的初始状态。这种给状态变量取快照,并用快照还原的方式,解决了很多因为状态变量改变而测试用例执行异常的问题,是个很有用很便捷的方法。另一个是用到了很便捷的断言方式,这就省掉了写很多麻烦的校验条件,来验证一个执行结果。比如下面这个断言,直接能验证当withdraw函数被调用后出现的回滚情况:await expect(lock.withdraw()).to.be.revertedWith( "You can't withdraw yet" ); 复制代码三、LoadFixture的使用使用场景用于每次执行测试前的setup操作,可以定义一个函数,在此函数中完成诸如合约部署,合约初始化,账户初始化等操作,在每次执行测试前利用loadFixture的功能,进行相同的变量状态的设置,对合约测试提供了很大的帮助。 工作原理根据Hardhat源码,可以看到loadFixture维护了一个快照数组snapshots,一个快照元素包含: fixture: Fixture类型的入参函数,type Fixture = () => Promise; data:fixture函数中定义的状态变量 restorer:一个有restore方法的结构体,在“./helpers/takeSnapshot”方法中有定义,可以触发evm_revert操作,指定区块链退回到某个快照点。 不同的函数f作为loadFixture入参时,会有不同的snapshot存储在loadFixture维护的snapshots数组中。在loadFixture(f)首次执行时,属于f函数的snapshot为undefined,此时会记录f函数中定义的全部状态变量,同时执行: const restorer = await takeSnapshot(); 并将此时的snapshot元素加入到snapshots数组中,后面再次用到同一个入参函数f的loadFixture时,在快照数组snapshots中已存在快照,可直接进行区块链状态回滚: await snapshot.restorer.restore(); loadFixture的用法 官方文档示例如下: 复制代码```js async function deployContractsFixture() { const token = await Token.deploy(...); const exchange = await Exchange.deploy(...); return ; } it("test", async function () { const = await loadFixture(deployContractsFixture); // use token and exchanges contracts }) ``` 注意:loadFixture的入参不可以是匿名函数,即: ```js //错误写法 loadFixture(async () => ) //正确写法 async function beforeTest(){ //定义函数 } loadFixture(beforeTest); ``` 复制代码四、Matchers的使用Machers:在chai断言库的基础上增加了以太坊特色的断言,便于测试使用1.Events用法 contract Ademo { event Event(); function callFunction () public { emit Event(); } } 复制代码对合约C的call方法进行调用会触发一个无参数事件,为了测试这个事件是否被触发,可以直接用hardhat-chai-matchers中的Events断言,用法如下: const A=await ethers.getContractFactory("Ademo"); const a=await A.deploy(); //采用hardhat-chai-matchers的断言方式,判断Events是否触发 await expect(a.callFunction()).to.emit(a,"Event"); 复制代码Reverts用法: //最简单的判断revert的方式 await expect(contract.call()).to.be.reverted; //判断未发生revert await expect(contract.call()).not.to.be.reverted; //判断revert发生并且带了指定的错误信息 await expect(contract.call()).to.be.revertedWith("Some revert message"); //判断未发生revert并且携带指定信息 await expect(contract.call()).not.to.be.revertedWith("Another revert message"); 复制代码除了上述常用的判断场景外,hardhat-chai-matchers还支持了对Panic以及定制化Error的判定:await expect(…).to.be.revertedWithPanic(PANIC_CODES) await expect(…).not.to.be.revertedWithPanic(PANIC_CODES) await expect(…).to.be.revertedWithCustomError(CONTRACT,"CustomErrorName") await expect(…).to.be.revertedWithoutReason(); 复制代码Big Number 在solidity中最大整型数是2^256,而JavaScript中的最大安全数是2^53-1,如果用JS写solidity合约中返回的大数的断言,就会出现问题。hardhat-chai-matchers提供了关于大数的断言能力,使用者无需关心大数之间比较的关系,直接以数字的形式使用即可,比如: expect(await token.balanceOf(someAddress)).to.equal(1);关于JavaScript的最大安全数问题:Number.MAX_SAFE_INTEGER 常量表示在 JavaScript 中最大的安全整数,其值为2^53-1,即9007199254740991 。因为Javascript的数字存储使用了IEEE 754中规定的双精度浮点数数据类型,而这一数据类型能够安全存储(-2^53-1 ~ 2^53-1)之间的数(包括边界值),超出范围后将会出现错误,比如:const x = Number.MAX_SAFE_INTEGER + 1; const y = Number.MAX_SAFE_INTEGER + 2; console.log(Number.MAX_SAFE_INTEGER); // Expected output: 9007199254740991 console.log(x); console.log(y); // Expected output: 9007199254740992 console.log(x === y); // Expected output: true 复制代码Balance Changes 可以很方便的检测用户钱包的资金变化额度,适用于以太币的金额变化,或者ERC-20代币的金额变化。单个钱包地址的金额变化:await expect(() => sender.sendTransaction() ).to.changeEtherBalance(sender, "-200"); await expect(token.transfer(account, 1)).to.changeTokenBalance( token, account, 1 ); 复制代码也可以用来检测多个账户的金额变化,在测试转账交易时,非常适用:await expect(() => sender.sendTransaction() ).to.changeEtherBalances([sender, receiver], [-200, 200]); await expect(token.transferFrom(sender, receiver, 1)).to.changeTokenBalances( token, [sender, receiver], [-1, 1] ); 复制代码字符串比较 可以用hardhat-chai-matchers提供的方法,方便地校验各种复杂的字符串,比如一个字符串是否是正确的地址格式、私钥格式等,用法如下:// 是否符合address格式 expect("0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2").to.be.a.properAddress; //是否符合私钥格式 expect(SOME_PRI_KEY).to.be.a.properPrivateKey; //判断十六进制字符串的用法 expect("0x00012AB").to.hexEqual("0x12ab"); //判断十六进制字符串的长度 expect("0x123456").to.be.properHex(6); 复制代码
2023年03月10日
4 阅读
0 评论
0 点赞
2023-03-08
CESS机制详解(2):区块链层与随机选取轮值(R²S)共识节点机制
对于任何一个区块链项目而言,基于区块链的共识层是最重要的底层架构,共识层的设计直接决定了整体网络的效率、安全性、去中心化程度等问题。当下众多新公链的崛起,很大程度上也是因为以太坊在DeFi Summer应用爆发后,链承载能力不足的问题被放大而导致的流量外溢。相较于单纯的公链,存储公链虽然是一个比较细分的功能性网络,但对于数据处理效率的要求并不亚于一般公链。究其原因,还是由于当下公链为了追求效率,很多时候链上仅仅作为最终状态确认的场所,而将较多的复杂内容放在链下执行。作为Web3.0底层基础设施,去中心化云存储网络CESS(Cumulus Encrypted Storage System)在设计之初秉持着对去中心化理念的坚持,在“信息上链”层面做到了尽可能的满足,并利用高效的链上处理效率来避免去中心化带来的低效问题,在“分散”和“高效”两个对立面上做到了很好的平衡。1. 随机选取轮值共识节点机制(R²S)为了在提高链上事务处理效率的同时又可以实现节点的去中心化,CESS采用了创新的随机选取轮值共识节点机制(R²S)来实现区块打包以及其他链上事务。正如字面上所看到的,该机制中完成链上共识的节点是轮值的,也就是说会随着时间的推移而变化。另一方面,所谓的“轮值”,在选择上也是“随机”的,单从字面意思来看,CESS在一个时间窗口内会由一定数量的轮值节点负责共识的维护,并且通过选取的随机性来保证去中心化程度。不过,真实的R²S并不如字面上看起来那么简单。1.1 如何实现“随机”与“轮值”其实区块链最重要的点是共识问题,但在解释R²S的共识机制之前,需要先介绍一下该机制中节点相关的问题。R²S机制允许所有希望成为节点运营者的用户可以自由地加入候选节点,但在每一个时间窗口内(例如每1万个区块),只选取11个正式的轮值节点参与出块。而未参与出块的候选节点,也可以通过参与数据预处理流程来为自己的工作能力提供证明,从而参与下一轮的正式轮值节点选取。在这个过程中,网络对每个节点都会进行信誉评分,当节点在工作过程中出现对网络整体利益存在损害的行为时,将会降低其分数。当分数低于某一基准线时,该节点将无法参与候选节点的竞争。这里简单解释一下,CESS对于用户上传的数据需要经过一轮数据预处理后,再分配给节点进行存储。预处理包含了数据的分片、加密、冗余等流程。具体的内容我们会在后续存储的具体流程中展示。我们来完整看一下机制的整套运作流程:首先,网络从所有候选节点中随机选取11个轮值节点,在固定的时间窗口内完成出块等共识的维护工作,而候选节点则参与数据的预处理过程为自己的工作能力提供证明。在轮值节点当值过程的同时,网络将会在满足条件的候选节点中再度随机选取11个节点作为下一个时间窗口内的正式轮值节点进行共识维护,以此类推。在这个过程中,如果有个别正式节点存在故意作恶或无法满足网络要求等问题,从而导致被强制下线时,网络将从候选节点里随机选抽节点补上直至完成此轮时间窗口的当值。所以对共识节点运营者而言,即使仅仅作为候选节点也需要保持对网络的持续贡献,如此可以大大增加获取收益的可能性。1.2 拜占庭容错与可验证随机函数在了解完具体的节点进入与退出机制后,下面就是区块链的核心问题:如何在去中心化的前提下保证链上数据的准确性。在该方面,CESS选择了采用安全性更高的拜占庭容错与可验证随机函数来确保共识的安全。1.2.1 拜占庭容错CESS借鉴PBFT共识算法,引入门限签名算法和收集者角色,实现高可用性的拜占庭容错共识算法。该算法保证了当网络中出现作恶节点时,依然可以实现链上共识的达成。本算法的11个当值共识节点可分为主节点和副节点,其中副节点根据任务不同,共包含转发节点和收集节点两个角色。每轮的共识过程都会有一个主节点,主节点在收到来自客户端的请求后将打包交易成块并发送至所有副节点。然后,转发节点将确认与签名消息并转发至收集节点。收集节点通过门限签名机制,把收集到的所有消息聚合成一个签名消息,随即发送至其他所有节点。接下来,继续新的一轮转发与收集过程,直至将确认消息返回至客户端。值得注意的是,两轮的收集节点可以指定为同一节点,也可为不同节点。本算法保证安全性和活性的的前提同样是假设系统中拜占庭节点数量不超过系统总节点数的1/3。节点总数量为N时,最多只能容纳f个拜占庭故障(叛徒)节点,令N大于等于3f + 1。1.2.2 可验证随机函数与大多数公链不同,CESS的共识节点通过随机选取生成,这意味着对网络应对变化的能力有更高的要求。为了可以在这样的背景下依然尽可能保证安全性,CESS采用“随机从候选共识节点中选取出若干共识节点,接着再通过共识算法合作打包交易出块”的模式,在增加节点选举的随机性和不可预测性的前提下,提升区块链的安全性。每个候选共识节点拥有一个公私钥对,在每轮时间窗口选举当值共识节点时,各候选共识节点通过以下公式计算哈希随机输出。R=VRF_Hash(SK, Seed)P=VRF_Proof(SK, Seed)其中,SK是节点的私钥,Seed是CESS链上某区块中的一个字段信息,无法提前预测。R为哈希随机输出,P为哈希证明。通过上述步骤,验证者可以轻易验证和两个值确实是由拥有该值的节点产生。R=VRF_P2H(P)VRF_Verify(PK, Seed, P)其中PK为被验证节点的公钥。此时,可选择哈希随机输出最小的11个节点为当值共识节点。如果选出的节点多于11个,将根据信誉度评分高低进行筛选。1.3 准入与退出虽然CESS对节点的进入并未设置过于严苛的前置要求,但也需要满足网络运行条件的基本运行指标、资源贡献指标,并质押一定数量的CESS代币来进行参与,防止节点作恶。在节点完成了CESS代币的质押之后,就可以参与到上述的流程中去。当节点想要退出时,网络会根据节点在运营过程中的评分来判定是否全额退还抵押代币。理论上只要节点正常工作,未出现长时间的掉线或者故意作恶等问题,网络都将全额退还抵押代币。该准入机制可预防女巫攻击,提高共识安全性。2. R²S机制优势何在单从机制设计的角度上来说,R²S略显复杂了一些,但CESS团队在设计该模式的时候,有针对存储公链特别的考量。2.1 解决“矿工困境”,避免垄断“矿工困境”是指在存储网络中,由于矿工更倾向于存储可以产生收益的数据而并非区块历史(可以理解为不愿意建立全节点),只通过向少数全节点调取数据来保证网络同步或者加入矿池,从而导致了全节点的过于中心化。CESS通过R²S来实现共识和存储的隔离,一方面保证了对于区块历史的存储更加去中心化,另一方面也防止大矿工的过于集权而对网络整体的发展不利。2.2 大幅提高去中心化框架下的效率如果单纯由11个节点来维护共识,虽然提高了效率,但网络却会像联盟链一样非常地中心化。CESS为了在该高效方案的背景下实现去中心化,所以设置了随机选取每一轮参与维护共识的机制。只需要满足节点要求即有机会参与出块,很好地解决了中心化的问题。2.3 实现链上事务处理CESS的链上数据,除了交易以及合约的确认,还包括了用户上传数据的“位置”信息。也就是说,CESS成功实现了所存储内容元数据的上链。虽然当下很多项目倾向于使用部分数据链下处理来提高链上效率,但这样的方案在安全性上需要非常多的保证机制,并且也是由于链处理效率较低而不得已为之。CESS由于链上事务处理的高效,所以可以实现元数据的上链,从而在数据存储的寻址等方面可以直接通过链上数据实现,而上链则是保证了数据的真实性。但这个需要说明的是,实际的操作中,为了存储网络效率优先的原则,节点会维护一个元数据的数据库,寻址将首先从该数据库中出发,只有在无法找到的情况下才会选择在链上调取数据。该数据库是通过同步链上信息而生成的,本质上并没有破坏真实性这个特点。而作为共识节点之所以需要将同样的数据同时在链上链下进行保存,一方面是为了在网络需求旺盛时降低不断向链上请求数据造成的高成本,另一方面也是方便了其他调度方可以更快地处理用户数据。3. 总结总体而言,CESS采用R²S机制,一方面实现了共识与存储分离,防止出现“矿工困境”与垄断;另一方面,通过可信执行环境(TEE)技术定期检查共识节点的诚实性和调度功能,来保证节点之间通过公平竞争来为网络提供尽可能优质的服务。基于Substrate开源框架开发的CESS去中心化云存储网络,不仅支持WASM,还将在未来兼容EVM智能合约,这不仅是为了方便开发者建立CESS原生生态,让很多对数据交互需求较高的项目有容身之地;也使得很多应用可以无缝迁移至CESS,为前期的快速发展铺好了道路。
2023年03月08日
5 阅读
0 评论
0 点赞
2023-03-08
CESS机制详解 (3):存储、内容分发网络与多副本可恢复存储证明
上一篇文章我们详细解释了CESS(Cumulus Encrypted Storage System)在共识机制和区块链层的设计上的思路:通过随机选取轮值共识节点机制(R²S)来保证共识达成的公平与高效,同时避免存储矿工的话语权过大。区块链本身除了交易、证明、合约等基本信息外,还包含了用户上传内容的元数据,是少有实现了元数据链上记录的存储公链。这些要归功于CESS高效的链上事务处理效率,使得在链上处理数据这种更去中心化的方式得以成为现实。本篇文章将重点阐述CESS在存储和内容分发层上的设计,以及CESS独特的多副本可恢复存储证明机制。与存储挖矿相关的内容我们将在后续单独向大家展示包含了共识、存储以及内容分发的挖矿机制与分发规则。1. 存储网络CESS目前将存储层与内容分发层并为一层网络,但我们还是分开来看二者的功能。作为去中心化存储网络最为重要的功能的载体,存储网络是整个CESS网络的“心脏”。CESS的存储网络由存储矿工组成,解决当前去中心化存储无法提供弹性可伸缩的云存储能力的问题,CESS存储网络通过虚拟化技术将存储资源「池化」,对顶层应用或外部应用提供统一的、按需使用存储方式,屏蔽底层硬件差异化带来的不稳定问题。矿工通过一系列链上证明包括有效存储空间、存储数据量、流量贡献量、及运行性能等指标来向整个CESS网络提供有效的存储空间及可用存储空间,CESS并非通过撮合需求方和存储服务提供方来提供点对点的交易,而是整合存储矿工提供的存储资源,并通过算法将需求按照其所需的容量、带宽等分配给相应的存储服务提供方(即虚拟化技术,指将矿工提供的具体的服务抽象为「虚拟」存储服务),即当用户有数据存储的需求时,并为应用提供存储服务。在存储资源的利用上,CESS通过“池化”技术实现了资源利用效率的最大化。所谓“池化”,就是将所有的存储资源作为一个整体的存储资源池而非个体矿工进行看待,用户上传的数据将会随机分配给满足存储条件的存储矿工。具体来说,当用户上传数据后,共识节点会首先将数据进行加密(采用可信执行环境进行加密)、分片和冗余等预处理(去中心化代理重加密机制),处理完毕的数据将依据用户对数据的存储要求(例如存储时间等)挑选满足条件的矿工进行存储。最重要的是,CESS并非选择一个或几个矿工完成存储任务,而是将切片后的数据段随机分发给满足要求的矿工。如此便避免了Filecoin点对点的存储模式中可能出现的大户垄断的情况。另一方面,这样的模式还可以实现存储资源的利用率最大化。在现有的存储网络中,当接收了较大规模的数据存储任务(例如超过5TB的数据量),可能对某些家庭矿工而言就无法实现整体的存储,也就失去了竞争的能力。这一点在现有的大部分存储网络中都没有得到很好的解决,当存储网络发展到一定程度,Filecoin和Arweave等都会不可避免的走向存储的中心化。举例来说,当网络中存在矿工A(3TB存储容量)和矿工B(1TB存储容量)时,对于现有的存储网络而言,2TB的数据只能由矿工A存储,而CESS可以实现A和B各存储1TB,从而实现最大的利用率。除了利用率的提高,该模式还降低了存储设施的硬件门槛。一方面是由于矿工只需要执行存储的任务而无需进行例如“接单”和运行节点这样复杂和专业的事宜;另一方面,也是由于矿工会随机接收数据段,并不取决于矿工本身的规模有多大。如此而言,CESS的存储层真正实现了存储“去中心化”和使用效率最大化的愿景,真正将闲置资源利用起来,而并非完全为了获取收益而额外增加存储资源。2. 内容分发网络CESS中的内容分发网络事实上起到了传统的云中CDN的功能。对于去中心化的存储网络,最大的问题之一并非存储本身,而是“数据的上传”。对于矿工尤其是国内的矿工而言,下载用户需要存储的数据不难,但当用户需要使用时上传所需要的网络成本却比较高。这就导致很多矿工在存储数据后虽然通过存储证明保证了数据的续存但不愿意将数据上传给用户,导致了网络实际上的不可用。不仅是去中心化的存储网络,即使是对于传统的云来说,也无法承受用户直接从云数据中心直接调取数据而产生的高瞬时并发与流量,这也是CDN存在的必要性之一。CESS在内容分发网络中设计了缓存以及检索矿工来帮助网络实现更加高效的运转,其中缓存矿工将缓存热门数据来实现更快的调用速度,而检索矿工则将帮助应用快速定位所需数据的位置。3. 多副本可恢复存储证明 (PoDR²)上文中所提到的数据预处理、向矿工分发等过程,属于 CESS 创新的多副本可恢复存储证明(PoDR²)机制。多副本可恢复存储证明(PoDR²)机制确保 CESS 平台有效的存储了用户上传数据时定制的副本。任意一份数据上传 CESS 系统后,将会自动复制若干个数据副本(默认为三份,可定制),并为每个数据副本生成可恢复证明所需要辅助验证元数据,并将这些元数据保存到区块链系统之中。此时,CESS 可将处理后的数据下发至各个存储矿工之上,在有效的周期内,矿工需要上报自己存储的数据,便于 CESS 系统确认数据是否损坏。值得一提的是,PoDR² 机制会以组成单个文件(包括所有副本)的所有数据段为整体进行统计与监测。一旦某个数据段被认定为损坏时,CESS 会自动生成新的数据段作为补充,并发送至新的存储矿工,保证副本的可恢复性,提升系统数据存储的鲁棒性。显而易见的是,CESS 的存储机制最大的不同点就在于:相较于依赖矿工对数据进行冗余等保护操作的设计,CESS 在系统的底层就实现了对数据的加密、冗余等保护策略,而矿工需要做的仅仅是将系统处理好的数据段进行存储并保证存储的有效性。此外,即使部分矿工丢失了数据,系统也可以通过其他的数据段实现对原始数据的还原。此举大大降低了单点故障的可能性,提高了去中心化存储网络中数据的安全性。4. 总结CESS 在存储机制的设计上,一方面通过多副本可恢复存储证明(PoDR²)机制实现了对数据隐私和安全的保护,并且设计了容灾的应对措施;另一方面,也通过对存储资源的“池化”,实现了存储资源利用率的最大化,并且解决了真正调用“限制资源”的能力,为去中心化存储在机制和设计理念上的创新和进步做出了卓越的贡献。
2023年03月08日
4 阅读
0 评论
0 点赞
2023-03-08
CESS机制详解 (4):应用层
在之前我们讲解了 CESS 的整体架构以及区块链层和存储及数据分发层的设计,所有的这些都是 CESS 最为重要的功能型网络,而这些网络存在的最终目的就是为了可以实现对用户数据的安全存储,以及更进一步的,对实际应用的支持。所谓应用层就是未来 CESS 之上将会搭建的应用生态系统。作为存储公链,未来极有可能成为公链生态之中的一股中坚力量。究其原因,一方面是存储公链实际上还是依托于区块链本身,而区块链的所有功能存储公链都可以涵盖;另一方面,存储公链为应用提供存储服务,可以进一步实现项目的去中心化,保护数据安全。事实上,此前也出现过 AWS 发生故障从而导致大量所谓去中心化的 Web3 应用不可用的问题,都是由于公链本身的节点以及项目的很多需要链下处理的数据都存放在中心化的云上导致的。去中心化存储公链在这一点上可以为应用提供更加分散的数据处理方式,更加接近于 Web3 的“完全体”。那么 CESS 对于应用生态的建设做了怎样的设计呢?首先,CESS 可以支持大规模的商业应用,也是业内首个在原生设计上就支持大规模商业应用的去中心化存储协议。之所以能支持对数据交互需求较高的应用不仅取决于 CESS 区块链在共识机制设计上对于链上事务处理效率的最大化,还得益于 CESS 的内容分发网络可以实现对数据的快速定位以及对热门数据的缓存。可以说,CESS 在实现了去中心化框架之下最大可能的高效。除了存储层面为应用所做的充足准备之外,CESS 也为应用的开发提供了不少的支持。智能合约层面,基于 Substrate 框架开发的 CESS 不仅支持 WASM,也会兼容 EVM,如此便使得波卡生态和以太坊生态的原生应用都可以无缝迁移至 CESS。此外,CESS 将为应用的开发者提供模块化的开发工具以及 API 等服务,方便开发者使用网络的数据存储、分发、智能合约、隐私保护和数据确权等功能开发应用。除了开放的 Web3 应用,CESS 也支持企业级 SDK,可为企业级应用提供去中心化存储服务。事实上,CESS 在这点上已经开始了行动,此前 CESS 为 Substrate 代码库添加存储 API 的申请已获得 Web3 基金会的通过,如此 CESS 将顺利解决网络初期仅仅是不断积累存储资源,而没有足够需求的“空转”时期,可以在网络上线之后就直接接入应用生态,并在不断的实践中对网络进行改善和升级。对于基于区块链的去中心化存储而言,当下最重要的就是应用场景,很多非 Web3 应用不愿意使用类似的存储协议的主要原因在于对技术本身信任感的不足,但事实上有不少 P2P 的协议(例如迅雷)已经向我们展示了这种存储机制的优势所在,而随着 Web3 时代的到来,很多场景对去中心化的存储有着硬性的刚需。这里简单举一个例子。作为 Web3 原生应用的 NFT 就是最好的应用场景,很多人对于 NFT 有着非常大的误解。实际上仅仅通过 OpenSea 上的信息,我们就能得知很多项目中 NFT 本身的数据是存储在中心化服务器上的。也就是说,我们在链上的 ERC721 或者 ERC1155 代币本质上仅仅是指向「小图片」一个信号,我们从来不是真正「拥有」NFT。只有当 NFT 本身指向信息的数据是不由发行者控制而是由协议本身控制的时候,才能真正实现 NFT 的所有权。这种情况之下,例如 Filecoin 这样点对点的存储协议还是可以被存储服务提供方删除或丢失,但 CESS 通过对数据的预处理保证了数据的完整和安全且无法被随意删除或篡改,实现了对 NFT 真正的所有权。事实上,在 Web3 领域有相当多的应用,其数据存储在中心化的服务器上,导致用户并未真正拥有所有权,这就是当下去中心化存储最大的应用场景。基于区块链的去中心化存储网络的构想早在近 10 年之前就被提出,但受限于区块链本身以及在整体网络和存储证明等方面的发展,包括 Filecoin、Arweave 等比较知名的项目都还没有在实际的应用上体现出足够的爆发力。 CESS 吸收了“前辈”们的精华,并通过自身开发团队在存储协议上多年的积累,在整体网络设计的多方面都考虑了去中心化思想和高效两个“矛盾点”的融合。CESS 的入局并不算晚,相信随着 Web3 应用的飞速发展,加之传统行业对区块链理解的加深,CESS 会乘上下一波东风,扬帆起航!
2023年03月08日
11 阅读
0 评论
0 点赞
2023-03-08
温故知新: TCP 服务与 HTTP 服务
作者:林冠宏 / 指尖下的幽灵。转载者,请: 务必标明出处。掘金:juejin.im/user/178526…博客:www.cnblogs.com/linguanh/GitHub : github.com/af913337456…出版的书籍:《1.0-区块链DApp开发实战》 《2.0-区块链DApp开发:基于公链》 随着年龄增长,越发觉得,计算机网络的基础知识,很重要。初始的思维 面向自定义的 TCP 服务 HTTP 服务本质 服务的约束 初始的思维相信很多做后端开发的同学,在 github 或者其他地方阅读搜索一些开源代码,阅读它们的时候,都有见到过服务编写的多种形式,并意识到怎么不都是 HTTP 形式的服务。比如看到 A 项目的代码,里面的请求登录或获取用户信息,从入口函数到返回输出都没见到熟悉的RouterPath 以及 HttpMethod。这很正常,我们一开始接触后端服务的时候,99%的开发者都是从 HTTP 服务开始,思维习惯于 HTTP 服务的代码阅读风格。比如下面的,就很熟悉。 router = router.append("POST","/login",func()).append("POST","/getUserInfo",func()) server.listen(":9000",router) 复制代码这种服务格式对我们来说,一目了然。这就是使用最广的 HTTP 服务。而对于 TCP 服务的直接实现就看得云里雾里。面向自定义的 TCP 服务然而,当一些项目做得很大的时候,它们的服务所采用的实现方式绝大多数是自定义的形式。尽管如此,自定义的层数也多截止到传输层的 TCP。基于 TCP 协议做服务的定制化比如下面的 TCP 服务端伪代码。func main() { listen = net.Listen("tcp", ":20000") for { conn = listen.Accept() // 建立连接 go process(conn) } } func process(conn net.Conn) { defer conn.close() for { var buf [128]byte n = conn.Read(buf[:]) // if err return recvStr := string(buf[:n]) fmt.Println("服务端收到客户端发来的数据:", recvStr) conn.Write([]byte("Hello World")) } } 复制代码客户端请求的时候,怎么请求?直接就是建立 TCP 链接,然后写字节数据。这样的一来一往,完全没有了 HTTP 服务常见的 GET或POST等method,Path 也不见了。这样也能实现 Client 与 Server 的通讯。我一般称这类服务为:TCP 直连服务HTTP 服务本质HTTP 全称是超文本传输协议。属于 OSI 模型中的应用层。而 TCP 是传输层,属于更低层的协议,HTTP 所接收的服务请求最终都会走到 TCP 中来。既可以理解为 HTTP 是在 TCP 的基础上增加的一套通用且便捷的数据解析规则后形式的应用层协议。这套规则就是 HTTP 报文规则。比如一个 HTTP 请求报文 是下面的格式:[Method] [Url] [Version][\r\n] [Key:] [Value][\r\n] ... [Key:] [Value][\r\n] [\r\n] [Body] ----------对应于------------- GET /userInfo HTTP/1.1 Content-Type: text/html Content-Length: 44 Content Here ... 复制代码又由于,几乎 HTTP 服务的网络框架都支持了这么一套规则,所以这么一个报文,在传输到 TCP 端的时候,数据读取就会变成下面这个样子,我们改装下上面的的 process 函数,使得它实现 HTTP 的回复形式: func process(conn net.Conn) { defer conn.close() for { var buf [128]byte total = conn.Read(buf[:]) // if err return obj = httpParse(buf[:]) // 按照 Http 报文协议解析请求的数据流 if obj.metohd == "GET" && obj.url == "/userInfo" & ... { // 以 http 报文格式回复 resp = "Hello World" conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: \r\n\r\n"+resp)) contine } conn.Write([]byte("Hello World")) } } 复制代码上面伪代码展示了一个简单的例子。现在的 HTTP 服务框架都是基于这种形式来实现封装后给到开发者使用的。如果你想试试,你也可以封装自己的轮子,比如 HTT_Q 协议。业界还有 FTP、TELNET 这些应用层协议,它们和 HTTP 同级。都是基于 TCP 开发出来的。服务的约束如果基于 TCP 服务来实现一套自己的应用层协议。这意味着,请求的客户端也要跟随实现自己的请求框架。同时在网络中传输数据我们还要考虑安全性,整体去看就是开发成本比较高。所以基于下面的条件限制,我们现在绝大多数服务采用 HTTP 服务,而不是 TCP 数据裸传服务。协议规范定制; 基于规范的代码框架开发; 规范中安全算法的稳定及其可靠性; 数据的包装及其传输的效率。 对于安全这个,基于 HTTP 协议家族中的 HTTPS 就是专门解决这个问题而生的。推荐介绍个写代码查 bug 的小程序 helper:
2023年03月08日
12 阅读
0 评论
0 点赞
2023-03-06
Hyperledger Fabric 通道配置文件和容器环境变量详解
摘要Fabric 网络启动的过程中需要进行大量配置,新学时对各个配置的作用一无所知,这导致我曾在网络出问题时先对配置文件的内容进行排列组合后再祈祷它能在某个时刻顺利运行,因此掌握 fabric 各个配置项的含义至关重要。本文对 configtxgen 的配置文件 configtx.yaml 进行了详细的分析解释,对 peer 、 orderer 、 fabric-ca 容器的常用环境变量也给除了详细说明,其中某些配置由于比较罕见因此并没有展开介绍,直接使用默认值即可,会在将来用上时再更新。准备介绍Fabric 节点的主配置路径为 FABRIC_CFG_PATH 环境变量所指向路径(默认为/etc/hyperledger/fabric)。在不显式指定配置路径时,会尝试从主配置路径下查找相关的配置文件。项配置文件路径说明peer$FABRIC_CFG_PATH/core.yaml指定 peer 节点运行时参数orderer$FABRIC_CFG_PATH/orderer.yaml指定 orderer 节点运行时参数fabric-ca$FABRIC_CA_SERVER_HOME/fabric-ca-server-config.yaml指定 CA 节点运行时参数configtxgen$FABRIC_CA_SERVER_HOME/configtx.yaml指定 configtxgen 命令运行时参数通常 fabric 服务有两种启动方式,一种是直接通过二进制命令直接在主机根据配置文件启动节点,另一种是使用docker根据环境变量和默认配置文件启动节点,其中除了 configtxgen 必须使用配置文件外,其余各服务都可以通过 docker 启动。因此本文将重点介绍 configtxgen 的配置文件及其它服务的 docker 环境变量。configtx.yaml 详解transaction 的英文缩写是TX(表示交易), configtx 表示交易配置,所以和交易相关的配置,如应用通道、锚节点、 Orderer 服务等,都是在 configtx.yaml文件中配置的。 configtx.yaml 文件由6个部分组成,其中前5个部分的配置都是为了在 Profiles 被引用,在 Profiles 中引用其它部分的同时可以覆盖特定配置,本节示例文件来自于 configtx.yaml。12OrganizationsOrganizations 用来定义不同的组织,其中 MSP(Membership Service Provider) 是一个组织的身份标识,在fabric中组织是由 MSPID 来唯一标识。Organizations: - &councilMSP # 定义一个组织引用,类似于变量,可在Profile部分被引用;所有带 & 符号的都是引用变量,使用 * 来引用 Name: councilMSP # 组织名称 ID: councilMSP # 组织ID MSPDir: ../orgs/council.ifantasy.net/msp # 组织MSP文件夹的路径 Policies: # 组织策略 Readers: Type: Signature Rule: "OR('councilMSP.member')" Writers: Type: Signature Rule: "OR('councilMSP.member')" Admins: Type: Signature Rule: "OR('councilMSP.admin')" # 此文件内的Orderer端口皆为容器内端口 OrdererEndpoints: # 定义排序节点(可多个),客户端和对等点可以分别连接到这些orderer以推送transactions和接收区块。 - "orderer1.council.ifantasy.net:7051" - "orderer2.council.ifantasy.net:7054" - "orderer3.council.ifantasy.net:7057" AnchorPeers: # 定义锚节点,锚节点对外代表本组织通信 - Host: peer1.soft.ifantasy.net Port: 7251 复制代码CapabilitiesCapabilities 定义了 fabric 程序要加入网络所必须支持的特性,通过定义通道的能力,就明确了不满足该能力要求的 fabric 程序,将无法处理交易,除非升级到对应的版本。Capabilities: # Channel配置同时针对通道上的Orderer节点和Peer节点(设置为ture表明要求节点具备该能力); Channel: &ChannelCapabilities V2_0: true # 要求Channel上的所有Orderer节点和Peer节点达到v2.0.0或更高版本 # Orderer配置仅针对Orderer节点,不限制Peer节点 Orderer: &OrdererCapabilities V2_0: true # 要求所有Orderer节点升级到v2.0.0或更高版本 # Application配置仅应用于对等网络,不需考虑排序节点的升级 Application: &ApplicationCapabilities V2_0: true 复制代码ApplicationApplication 定义了应用内的访问控制策略和参与组织。Application: &ApplicationDefaults # 干预 创建链码的系统链码 的函数访问控制策略 _lifecycle/CheckCommitReadiness: /Channel/Application/Writers # CheckCommitReadiness 函数的访问策略 _lifecycle/CommitChaincodeDefinition: /Channel/Application/Writers # CommitChaincodeDefinition 函数的访问策略 _lifecycle/QueryChaincodeDefinition: /Channel/Application/Writers # QueryChaincodeDefinition 函数的访问策略 _lifecycle/QueryChaincodeDefinitions: /Channel/Application/Writers # QueryChaincodeDefinitions 函数的访问策略 # 关于 生命周期系统链码(lscc) 的函数访问控制策略 lscc/ChaincodeExists: /Channel/Application/Readers # getid 函数的访问策略 lscc/GetDeploymentSpec: /Channel/Application/Readers # getdepspec 函数的访问策略 lscc/GetChaincodeData: /Channel/Application/Readers # getccdata 函数的访问策略 lscc/GetInstantiatedChaincodes: /Channel/Application/Readers # getchaincodes 函数的访问策略 # 关于 查询系统链码(qscc) 的函数访问控制策略 qscc/GetChainInfo: /Channel/Application/Readers # GetChainInfo 函数的访问策略 qscc/GetBlockByNumber: /Channel/Application/Readers # GetBlockByNumber 函数的访问策略 qscc/GetBlockByHash: /Channel/Application/Readers # GetBlockByHash 函数的访问策略 qscc/GetTransactionByID: /Channel/Application/Readers # GetTransactionByID 函数的访问策略 qscc/GetBlockByTxID: /Channel/Application/Readers # GetBlockByTxID 函数的访问策略 # 关于 配置系统链码(cscc) 的函数访问控制策略 cscc/GetConfigBlock: /Channel/Application/Readers # GetConfigBlock 函数的访问策略 cscc/GetChannelConfig: /Channel/Application/Readers # GetChannelConfig 函数的访问策略 # 关于 peer 节点的函数访问控制策略 peer/Propose: /Channel/Application/Writers # Propose 函数的访问策略 peer/ChaincodeToChaincode: /Channel/Application/Writers # ChaincodeToChaincode 函数的访问策略 # 关于事件资源的访问策略 event/Block: /Channel/Application/Readers # 发送区块事件的策略 event/FilteredBlock: /Channel/Application/Readers # 发送筛选区块事件的策略 # 默认为空,在 Profiles 中定义 Organizations: # 定义本层级的应用控制策略,路径为 /Channel/Application/<PolicyName> Policies: Readers: # /Channel/Application/Readers Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" LifecycleEndorsement: Type: ImplicitMeta Rule: "MAJORITY Endorsement" Endorsement: Type: ImplicitMeta Rule: "MAJORITY Endorsement" Capabilities: <<: *ApplicationCapabilities # 引用上节 Capabilities 的 ApplicationCapabilities 复制代码OrdererOrderer 定义了排序服务的相关参数,这些参数将用于创建创世区块或交易。Orderer: &OrdererDefaults OrdererType: etcdraft # 排序服务算法,目前可用:solo,kafka,etcdraft Addresses: # 排序节点地址 - orderer1.soft.ifantasy.net:7051 - orderer2.web.ifantasy.net:7052 - orderer3.hard.ifantasy.net:7053 # 定义了 etcdRaft 排序类型被选择时的配置 EtcdRaft: Consenters: # 定义投票节点 - Host: orderer1.council.ifantasy.net Port: 7051 ClientTLSCert: ../orgs/council.ifantasy.net/registers/orderer1/tls-msp/signcerts/cert.pem # 节点的TLS签名证书 ServerTLSCert: ../orgs/council.ifantasy.net/registers/orderer1/tls-msp/signcerts/cert.pem - Host: orderer2.council.ifantasy.net Port: 7054 ClientTLSCert: ../orgs/council.ifantasy.net/registers/orderer2/tls-msp/signcerts/cert.pem ServerTLSCert: ../orgs/council.ifantasy.net/registers/orderer2/tls-msp/signcerts/cert.pem - Host: orderer3.council.ifantasy.net Port: 7057 ClientTLSCert: ../orgs/council.ifantasy.net/registers/orderer3/tls-msp/signcerts/cert.pem ServerTLSCert: ../orgs/council.ifantasy.net/registers/orderer3/tls-msp/signcerts/cert.pem # 区块打包的最大超时时间 (到了该时间就打包区块) BatchTimeout: 2s # 区块链的单个区块配置(orderer端切分区块的参数) BatchSize: MaxMessageCount: 10 # 一个区块里最大的交易数 AbsoluteMaxBytes: 99 MB # 一个区块的最大字节数,任何时候都不能超过 PreferredMaxBytes: 512 KB # 一个区块的建议字节数,如果一个交易消息的大小超过了这个值, 就会被放入另外一个更大的区块中 # 参与维护Orderer的组织,默认为空(通常在 Profiles 中再配置) Organizations: # 定义本层级的排序节点策略,其权威路径为 /Channel/Orderer/<PolicyName> Policies: Readers: # /Channel/Orderer/Readers Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" BlockValidation: # 指定了哪些签名必须包含在区块中,以便peer节点进行验证 Type: ImplicitMeta Rule: "ANY Writers" Capabilities: <<: *OrdererCapabilities # 引用上节 Capabilities 的 OrdererCapabilities 复制代码ChannelChannel 定义要写入创世区块或配置交易的通道参数。Channel: &ChannelDefaults # 定义本层级的通道访问策略,其权威路径为 /Channel/<PolicyName> Policies: Readers: # 定义谁可以调用 'Deliver' 接口 Type: ImplicitMeta Rule: "ANY Readers" Writers: # 定义谁可以调用 'Broadcast' 接口 Type: ImplicitMeta Rule: "ANY Writers" # By default, who may modify elements at this config level Admins: # 定义谁可以修改本层策略 Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ChannelCapabilities # 引用上节 Capabilities 的 ChannelCapabilities 复制代码ProfilesProfiles 配置用于 configtxgen 工具的配置入口,主要是引用其余五个部分的参数,其定义了一系列的配置模板,每个模板代表了特定应用场景下的自定义的通道配置,可以用来创建系统通道或应用通道。配置模板中可以包括 Application 、 Capabilities 、 Consortium 、 Consortiums 、 Policies 、 Orderer 等配置字段,根据使用目的不同,一般只包括部分字段。除了通道默认的配置,创建系统通道初始区块的模板一般需要包括 Orderer 、 Consortiums 字段信息(也可以包括 Applicaion 字段定义初始应用通道配置):Profiles: # OrgsChannel用来生成channel配置信息,名字可以任意 # 需要包含Consortium和Applicatioon两部分。 OrgsChannel: Consortium: SampleConsortium # 通道所关联的联盟名称 <<: *ChannelDefaults Orderer: <<: *OrdererDefaults Organizations: - *councilMSP Capabilities: *OrdererCapabilities Application: <<: *ApplicationDefaults Organizations: - *softMSP - *webMSP - *hardMSP Capabilities: <<: *ApplicationCapabilities 复制代码peer 配置详解当 Peer 节点启动时,会按照优先级从高到低的顺序依次尝试从命令行参数、环境变量和配置文件中读取配置信息,当从环境变量中读入配置信息时,除了日志使用单独的 FABRIC_LOGGING_SPEC 环境变量进行指定,其他都需要以 CORE_ 前缀开头,例如配置文件中的 peer.id 项,对应环境变量 CORE_PEER_ID 。Peer 节点默认的配置文件读取路径为 $FABRIC_CFG_PATH/core.yaml ,如果没找到则尝试查找当前目录下的 ./core.yaml 文件,如果还没有找到则尝试查找默认的 /etc/hyperledger/fabric/core.yaml 文件。在结构上, core.yaml 文件中可以分为 peer 、 vm 、 chaincode 、 ledger 、 operations 、 metrics 六大部分, core.yaml 文件太过冗长在此不详细介绍,本节只介绍 Docker 环境下的常用环境变量(以后用到再更新),一个常用 示例配置 如下3: peer-base: image: hyperledger/fabric-peer:$ environment: - FABRIC_LOGGING_SPEC=info - CORE_PEER_ID=peer1.soft.ifantasy.net - CORE_PEER_LISTENADDRESS=0.0.0.0:7251 - CORE_PEER_ADDRESS=peer1.soft.ifantasy.net:7251 - CORE_PEER_LOCALMSPID=softMSP - CORE_PEER_MSPCONFIGPATH=$/peer/msp - CORE_PEER_TLS_ENABLED=true - CORE_PEER_TLS_CERT_FILE=$/peer/tls-msp/signcerts/cert.pem - CORE_PEER_TLS_KEY_FILE=$/peer/tls-msp/keystore/key.pem - CORE_PEER_TLS_ROOTCERT_FILE=$/peer/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.soft.ifantasy.net:7251 - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=$_$ working_dir: $/peer volumes: - /var/run:/host/var/run networks: - $ 复制代码通常我们喜欢使用 extends 方式分割通用容器,需要注意的是父容器的环境变量无法被子容器环境变量覆盖。其中各项含义如下:FABRIC_LOGGING_SPEC :指定日志级别 CORE_PEER_ID : Peer 在网络中的 ID 信息,用于辨识不同的节点 CORE_PEER_LISTENADDRESS :服务监听的本地地址,本地有多个网络接口时可指定仅监听某个接口 CORE_PEER_ADDRESS :对同组织内其他节点的监听连接地址。当服务在NAT设备上运行时,该配置可以指定服务对外宣称的可访问地址。如果是客户端,则作为其连接的 Peer 服务地址 CORE_PEER_LOCALMSPID :Peer 所关联的 MSPID ,一般为所属组织名称,需要与通道配置内名称一致 CORE_PEER_MSPCONFIGPATH :MSP 目录所在的路径,可以为绝对路径,或相对配置目录的路径 CORE_PEER_TLS_ENABLED :是否开启 server 端 TLS 检查 CORE_PEER_TLS_CERT_FILE :server 端使用的 TLS 证书路径 CORE_PEER_TLS_KEY_FILE :server 端使用的 TLS 私钥路径 CORE_PEER_TLS_ROOTCERT_FILE :server 端使用的根CA的证书,签发服务端的 TLS证书 CORE_PEER_GOSSIP_USELEADERELECTION :是否允许节点之间动态进行组织的代表(leader)节点选举,通常情况下推荐开启 CORE_PEER_GOSSIP_ORGLEADER :本节点是否指定为组织的代表节点,与useLeaderElection不能同时指定为true CORE_PEER_GOSSIP_EXTERNALENDPOINT :节点向组织外节点公开的服务地址,默认为空,代表不被其他组织所感知 CORE_VM_ENDPOINT :docker daemon 的地址 CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE :运行链码容器的网络 orderer 配置详解排序节点在 Fabric 网络中为 Peer 提供排序服务。与Peer节点类似,排序节点支持从命令行参数、环境变量或配置文件中读取配置信息。环境变量中配置需要以 ORDERER_ 前缀开头,例如,配置文件中的 general.ListenAddress 项,对应到环境变量 ORDERER_GENERAL_LISTENADDRESS 。节点默认的配置文件读取路径为 $FABRIC_CFG_PATH/orderer.yaml ,如果没找到则尝试查找当前目录下的 ./orderer.yaml 文件,如果还没有找到则尝试查找默认的 /etc/hyperledger/fabric/orderer.yaml 文件。在结构上, orderer.yaml 文件中一般包括 General 、 FileLedger 、 RAMLedger 、 Kafka 、 Debug 、 Operations 、 Metrics 和 Consensus 八大部分, orderer.yaml 文件太过冗长再此不详细介绍,本节只介绍 Docker 环境下的常用环境变量(以后用到再更新),一个常用 示例配置 如下4: orderer-base: image: hyperledger/fabric-orderer:$ environment: - ORDERER_HOME=$/orderer - ORDERER_HOST=orderer1.council.ifantasy.net - ORDERER_GENERAL_LOCALMSPID=councilMSP - ORDERER_GENERAL_LISTENPORT=7051 - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_BOOTSTRAPMETHOD=none - ORDERER_CHANNELPARTICIPATION_ENABLED=true # - ORDERER_GENERAL_GENESISMETHOD=file # - ORDERER_GENERAL_GENESISFILE=$/orderer/genesis.block - ORDERER_GENERAL_LOCALMSPDIR=$/orderer/msp - ORDERER_GENERAL_LOGLEVEL=debug - ORDERER_GENERAL_TLS_ENABLED=true - ORDERER_GENERAL_TLS_CERTIFICATE=$/orderer/tls-msp/signcerts/cert.pem - ORDERER_GENERAL_TLS_PRIVATEKEY=$/orderer/tls-msp/keystore/key.pem - ORDERER_GENERAL_TLS_ROOTCAS=[$/orderer/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem] - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=$/orderer/tls-msp/signcerts/cert.pem - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=$/orderer/tls-msp/keystore/key.pem - ORDERER_GENERAL_CLUSTER_ROOTCAS=[$/orderer/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem] - ORDERER_ADMIN_TLS_ENABLED=true - ORDERER_ADMIN_TLS_CERTIFICATE=$/orderer/tls-msp/signcerts/cert.pem - ORDERER_ADMIN_TLS_PRIVATEKEY=$/orderer/tls-msp/keystore/key.pem - ORDERER_ADMIN_TLS_ROOTCAS=[$/orderer/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem] - ORDERER_ADMIN_TLS_CLIENTROOTCAS=[$/orderer/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem] - ORDERER_ADMIN_LISTENADDRESS=0.0.0.0:8888 - ORDERER_METRICS_PROVIDER=prometheus - ORDERER_OPERATIONS_LISTENADDRESS=0.0.0.0:9999 - ORDERER_DEBUG_BROADCASTTRACEDIR=data/logs networks: - $ 复制代码其中各项含义如下:ORDERER_HOME :orderer 运行的根目录 ORDERER_HOST :orderer 运行的主机 ORDERER_GENERAL_LOCALMSPID : orderer 所关联的 MSPID ,一般为所属组织名称,需要与通道配置内名称一致 ORDERER_GENERAL_LISTENPORT :服务绑定的监听端口 ORDERER_GENERAL_LISTENADDRESS :服务绑定的监听地址,一般需要指定为所服务的特定网络接口的地址或全网(0.0.0.0) ORDERER_GENERAL_BOOTSTRAPMETHOD :获取引导块的方法,2.x版本中仅支持file或none ORDERER_CHANNELPARTICIPATION_ENABLED :是否提供参与通道的 API ORDERER_GENERAL_GENESISMETHOD :当 ORDERER_GENERAL_BOOTSTRAPMETHOD 为 file 时启用,指定创世区块类型 ORDERER_GENERAL_GENESISFILE :指定创世区块位置 ORDERER_GENERAL_LOCALMSPDIR :本地 MSP 文件路径 ORDERER_GENERAL_LOGLEVEL :日志级别 ORDERER_GENERAL_TLS_ENABLED :启用TLS时的相关配置 ORDERER_GENERAL_TLS_CERTIFICATE :Orderer 身份证书 ORDERER_GENERAL_TLS_PRIVATEKEY :Orderer 签名私钥 ORDERER_GENERAL_TLS_ROOTCAS :信任的根证书 ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE :双向TLS认证时,作为客户端证书的文件路径,如果没设置会使用 TLS.Certificate ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY :双向TLS认证时,作为客户端私钥的文件路径,如果没设置会使用 TLS.PrivateKey ORDERER_GENERAL_CLUSTER_ROOTCAS :信任的根证书 ORDERER_ADMIN_TLS_ENABLED :是否启用 orderer 的管理服务面板 ORDERER_ADMIN_TLS_CERTIFICATE :管理服务的证书 ORDERER_ADMIN_TLS_PRIVATEKEY :管理服务的私钥 ORDERER_ADMIN_TLS_ROOTCAS :管理服务的可信根证书 ORDERER_ADMIN_TLS_CLIENTROOTCAS :管理服务客户端的可信根证书 ORDERER_ADMIN_LISTENADDRESS :管理服务监听地址 ORDERER_METRICS_PROVIDER :统计服务类型,可以为statsd(推送模式),prometheus(拉取模式),disabled ORDERER_OPERATIONS_LISTENADDRESS :RESTful 管理服务的监听地址 ORDERER_DEBUG_BROADCASTTRACEDIR :广播请求的追踪路径 fabric-ca 配置详解在 fabric 官方示例中,通常使用 cryptogen 生成静态证书文件,但这种方式不适合用于生产环境,而 fabric-ca 可以在生产环境中为所有成员提供安全的证书服务。与其它类型节点类似, fabric-ca 支持从命令行参数、环境变量或配置文件中读取配置信息,且 fabric-ca 分为 fabric-ca-server 和 fabric-ca-client ,前者用于提供 CA 服务,后者用于向用户提供操作 fabric-ca-server 的方法。一个常用 示例配置 如下: ca-base: image: hyperledger/fabric-ca:$ environment: - FABRIC_CA_SERVER_HOME=$/ca/crypto - FABRIC_CA_SERVER_TLS_ENABLED=true - FABRIC_CA_SERVER_DEBUG=true - FABRIC_CA_SERVER_CSR_CN=council.ifantasy.net - FABRIC_CA_SERVER_CSR_HOSTS=council.ifantasy.net networks: - $ 复制代码其中各项内容含义如下:FABRIC_CA_SERVER_HOME :指定 fabric-ca-server 运行的根目录 FABRIC_CA_SERVER_TLS_ENABLED :是否启用 TLS FABRIC_CA_SERVER_DEBUG :是否启用 debug 模式 FABRIC_CA_SERVER_CSR_CN :指定证书主体的 cn 字段 FABRIC_CA_SERVER_CSR_HOSTS :指定证书主体的 hosts 字段 参考Footnotes黑帽子技术. Hyperledger Fabric 通道配置文件解析. 掘金. [2022-03-22] ↩ chainbees. Fabric创建通道Channel的配置文件configtx.yaml详解. CSDN. [2021-12-17] ↩ 黑帽子技术. Hyperledger Fabric Peer 配置解析. 掘金. [2022-03-22] ↩ 黑帽子技术. Hyperledger Fabric Orderer 配置解析. 掘金. [2022-03-22] ↩
2023年03月06日
5 阅读
0 评论
0 点赞
1
...
8
9
10
11