Fabric 网络搭建前期准备
1.安装goalang 
一、通过apt-get安装
sudo apt-get install golang
2、设置GOPATH变量
GOPATH是扩展库的目录，Go先搜索标准库目录，然后搜索GOPATH库目录，所有的非标准库都放在GOPATH下。以GOPATH为“/usr/local/go”目录为例子：
（1）把export GOPATH=/opt/go加入到~/.bashrc(或者/etc/profile)文件的最后。
（2）source ~/.bashrc（或者/etc/profile） 重新加载配置
使用apt-get安装无法保证我们下载的版本。下面介绍源码安装思路。
二：源码安装
1.下载安装包
国外的
https://golang.org/dl/
  
国内的
https://studygolang.com/dl
 
选择要下载的版本。
1.	解压 tar xzvf go1.**.*.linux-amd64.tar.gz -C /usr/lib/
2.	在~/.bashrc(或者/etc/profile)中，添加环境变量（如果是别的sh，请在别的sh中配置
#GOROOT
export GOROOT=/usr/lib/go
#GOPATH go项目路径
export GOPATH=/root/gocode
#GOPATH bin
export PATH=$PATH:$GOPATH/bin
#GOPATH root bin
export PATH=$PATH:$GOROOT/bin
 
3.	source ~/.bashrc(或者/etc/profile)
4.	验证
[root@compute84 bin]# go version
go version go1.12.7 linux/amd64
[root@compute84 bin]#
[root@compute84 bin]# go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/root/gocode"
GOPROXY="https://goproxy.io"
GORACE=""
GOROOT="/usr/lib/go"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build670179
2.下载docker
（更新apt包索引）
sudo apt-get update 
（安装docker）
sudo apt install docker.io
 验证docker
查看docker服务是否启动：
$ systemctl status docker
若未启动，则启动docker服务：
$ sudo systemctl start docker
查询docker安装版本：
$ sudo docker version

默认安装完 docker 后，每次执行 docker 都需要运行 sudo 命令，非常浪费时间影响效率。如果不跟 sudo，直接执行 docker images 命令会有如下问题：
Get http:///var/run/docker.sock/v1.15/containers/json: dial unix /var/run/docker.sock: permission denied
解决办法：
如果还没有 docker group 就添加一个
sudo groupadd docker
ubuntu下，通过一下命令来看有没有group
cat /etc/group
将用户加入该 group 内。然后退出并重新登录就生效啦。
sudo gpasswd -a ${USER} docker
重启 docker 服务
sudo service docker restart



3 .安装docker-compose

安装
$ sudo apt install docker-compose 
测试安装结果
$ docker-compose version



1.启动fabric网络
实现我们从github 上拉取 fabric
git clone "https://github.com/hyperledger/fabric.git"

# 进入对应的文件
cd /opt/gopath/src/hyperledger/fabric
#下载必备的文件
cd scripts/
#这一步会下载官方的例子以及所需要的Docker镜像，并下载相应的二进制文件以及fabric-sample
#下载是比较慢的，如果出现错误或者长时间没有速度只需要重新运行就可以了，我是在阿里云上面进行下载，所以没有翻墙，如果你要是在本地一定要翻墙
sudo ./bootstrap.sh    
 
当我们完成一系列操作以后我们需要将下载的configtxgen,configtxlator,cryptogen添加进环境变量中因为我们在下一步时候需要他们。我们生成的configtxgen,configtxlator,cryptogen 二进制文件在 fabric目录的.build/bin 目录下，我的地址是
/opt/gopath/src/github.com/hyperledger/fabric/.build/bin 
将对应的二进制文件添加进环境变量（我一般都是讲这些二进制文件，copy 到/usr/local/bin 目录下）
vim ~/.profile
#文件中最后添加以下内容
export PATH=$PATH:$GOPATH/src/github.com/hyperledger/fabric/./build/bin
#更新一下
source ~/.profile
 
上面我们就完成了全部的准备工作，我们可以开始启动我们的fabric 网络了。
#进入first-network文件夹，fabric-samples 文件是我们在完成./bootstrap.sh 命令后出现的
cd ~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/
#执行命令
 ./byfn.sh up  //时间会比较长我们需要耐心等待

当出现
===================== Query successful on peer1.org2 on channel 'mychannel' ===================== 

========= All GOOD, BYFN execution completed =========== 


 _____   _   _   ____   
| ____| | \ | | |  _ \  
|  _|   |  \| | | | | | 
| |___  | |\  | | |_| | 
|_____| |_| \_| |____/  

证明我们启动完成。

./byfn.sh down 关闭fabric 网络。

 
2.部署fabric-sdk-go
fabric-sdk-go 本身的项目还是很复杂的，尤其代码写的是相当难以阅读，再加上fabric项目的配置项本身就很复杂，所以使得fabric-sdk-go 这个项目还是比较难以掌握的。在这里我先记录下fabric-sdk-go 最简单的启动配置。至于更加复杂的部分以后我再补上。
首先我们先从github 拉去最新的fabric-sdk-go 代码。我当前版本是fabirc-sdk-go 1.4 版本。
git clone https://github.com/hyperledger/fabric-sdk-go.git
 
因为在新版的fabric-sdk-go 中我们使用的是golang 1.13,我们知道golang 在1.13 版本中已经支持了mod。（如果是直接拉取我们的项目已经存在vendor，这一步可以忽略）
#进入fabric-sdk-go 地址
cd /opt/gopath/src/github.com/hyperledger/fabric-sdk-go 
# 执行下载fabric-sdk-go 依赖第三方库,科学上网（当时我就是无法科学上网导致浪费了很多时间）
go mod download
# 建立vendor 并copy相应的依赖。
go mod vendor
 
此时fabric-sdk-go 项目相应的依赖库我们已经下载完毕。下一步我们需要将我们在搭建fabric生成的密钥文件拷贝到我们的fabric-sdk-go 项目中。
# fabric 网络中的密钥文件地址 
/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/crypto-config
# 在 fabric-sdk-go 需要存放的地址
/opt/gopath/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/fabric/v1
# 我们copy fabric 下的crypto-config 目录，到fabric-sdk-go 的v1 目录下
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/
cp -r crypto-config /opt/gopath/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/fabric/v1

当我们完成密钥文件的替换后我们需要检查下，fabric 网络的端口是否是通的。当然如果我们的fabric与fabric-sdk-go是在同一台服务器上没有问题，如果不是在同一台我们可以使用telnet 127.0.0.1 7050 来检查我们的端口是否是开通的。
 
2.1 测试例子（query,invoke ）
下面给大家看下我写的测试代码。至于为什么我需要一个新的测试代码而不用fabric-sdk-go 的测试代码，因为我只是想简单测试一下我的fabric-sdk-go 是否可以与我的fabric 网络的节点链接。fabric-sdk-go 的测试代码，是将整个的周期都测试一遍。还是很复杂的，这样如果出错我们也不是很好排查。所以我们仿照 的e2e 测试例子自己实现了一个简单的测试代码。我们也可以将测试代码放在end_2_end_test.go 文件中。
/*
 	进行简单的chaincode invoke,query sample

*/

func TestCcQuery(t *testing.T) {
	result := fabric_sdk.CcQuery(“mycc”,”query”, [][]byte{[]byte("b")}) //return query result
	fmt.Println(string(result))  
}
 
并同样在fabric-sdk-go/test/integration/e2e 目录下添加一个新的文件ccprovider.go,为了不和e2e的代码有冲突。
func getConfig() core.ConfigProvider {
	configPath := "../../fixtures/config/config_e2e.yaml"
	return config.FromFile(configPath)
}

/*
Parameters:
  ccId: is chaincode name(such mycc)
  functionName: is invoke chaincode functionName (such query)
  ccArgs: is invoke chaincode args
*/
func CcQuery(ccId ,functionName string,ccArgs [][]byte) []byte {
	configOpt := getConfig()
	sdk, err := fabsdk.New(configOpt)
	if err != nil {
		fmt.Printf("Failed to create new SDK: %s \n", err)
	}
	defer sdk.Close()
	//prepare channel client context using client context
	clientChannelContext := sdk.ChannelContext(MychannelID, fabsdk.WithUser("Admin"), fabsdk.WithOrg(MyorgName))
	// Channel client is used to query and execute transactions (Org1 is default org)
	client, err := channel.New(clientChannelContext)
	if err != nil {
		fmt.Printf("Failed to create new channel client: %s \n", err)
	}
	return querycc(client,ccId,functionName,ccArgs)
}
/*
Parameters:
  ccId: is chaincode name(such mycc)
  functionName: is query chaincode functionName (such query)
  ccArgs: is query chaincode args
*/
func CcInvoke(ccId ,functionName string,ccArgs [][]byte) []byte {

	configOpt := getConfig()
	sdk, err := fabsdk.New(configOpt)
	if err != nil {
		fmt.Printf("Failed to create new SDK: %s \n", err)
	}
	defer sdk.Close()
	//prepare channel client context using client context
	clientChannelContext := sdk.ChannelContext(MychannelID, fabsdk.WithUser("Admin"), fabsdk.WithOrg(MyorgName))
	// Channel client is used to query and execute transactions (Org1 is default org)
	client, err := channel.New(clientChannelContext)
	if err != nil {
		fmt.Printf("Failed to create new channel client: %s \n", err)
	}
	return executeCc(client,ccId,functionName,ccArgs)
}

func querycc(client *channel.Client, ccId ,functionName string,ccArgs [][]byte,targetEndpoints ...string) []byte {
	response, err := client.Query(channel.Request{ChaincodeID: ccId, Fcn: functionName, Args: ccArgs},
		channel.WithRetry(retry.DefaultChannelOpts),
		channel.WithTargetEndpoints(targetEndpoints...),
	)
	if err != nil {
		fmt.Printf("Failed to query funds: %s \n", err)
	}
	return response.Payload
}

func executeCc(client *channel.Client,ccId ,functionName string,ccArgs [][]byte) []byte {
	response, err := client.Execute(channel.Request{ChaincodeID: ccId, Fcn: functionName, Args: ccArgs},
		channel.WithRetry(retry.DefaultChannelOpts))
	if err != nil {
		fmt.Printf("Failed to move funds: %s", err)
	}
	return response.Payload
} 

2.2 配置文件
当我们阅读代码的时候我们可以看到在getConfig（）方法中我们引用了../fixtures/config/config_e2e.yaml 的配置文件。下面我们学习如何修改config_e2e.yaml配置文件。config_e2e.yaml配置文件是fabric-sdk-go 项目提供的配置文件，如果我们直接使用它的配置文件，我们会发现项目你怎么也跑不起来，所以我们在这里对它进行一些修改。（当然我们也可以新建一个配置文件）
1：首先需要修改相应的密钥路径配置文件，除了下面我摘出来的部分需要特别注意，其他的部分我们正常填写就ok了。
tlsCerts:
    # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
    systemCertPool: true
    # [Optional]. Client key and cert for TLS handshake with peers and orderers
    client:
      key:
        path: /opt/gopath/src/github.com/fabric-sdk-sample/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org1.example.com/users/User1@org1.example.com/tls/client.key
      cert:
        path: /opt/gopath/src/github.com/fabric-sdk-sample/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org1.example.com/users/User1@org1.example.com/tls/client.crt
 
2：在channels 部分填写，下面是我的配置（大家可以发现我增加了orderers和peers 的配置）
mychannel:
    orderers:
      - orderer.example.com
    peers:
      peer0.org1.example.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      peer0.org2.example.com:
		 endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
3：配置url,这部分不需要特别说明，我们需要在orderer or peer 的url 部分填写我们相应的ip
关于配置文件的介绍我们先简单介绍到这里，后面我们在详细介绍。
        
当我们完成配置以后我可以进行测试，测试结果如下
GOROOT=/usr/local/go #gosetup
GOPATH=/opt/gopath #gosetup
/usr/local/go/bin/go test -c -o /tmp/___TestCcQuery_in_github_com_fabric_sdk_sample_fabric_sdk_test_linux github.com/fabric-sdk-sample/fabric-sdk-test #gosetup
/usr/local/go/bin/go tool test2json -t /tmp/___TestCcQuery_in_github_com_fabric_sdk_sample_fabric_sdk_test_linux -test.v -test.run ^TestCcQuery$ #gosetup
=== RUN   TestCcQuery
210
--- PASS: TestCcQuery (0.69s)
PASS

Process finished with exit code 0
 
2.3 错误笔记

为了大家更好的调试代码，下面我将我记录的错误笔记记录下来：
fabric 错误笔记：
1.执行invoke 交易的时：
Transaction processing for endorser [39.98.194.244:7151]: Chaincode status Code: (500) UNKNOWN. Description: cannot retrieve package for chaincode mycc/1.0, error open /var/hyperledger/production/chaincodes/mycc.1.0: no such file or directory
错误原因：表示在对应的peer 节点上没有安装对应的chaincode 

2.执行invoke 交易的时： 
Failed to move funds: CreateAndSendTransaction failed: SendTransaction failed: calling orderer 'orderer.example.com:7050' failed: Orderer Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection timed out [orderer.example.com:7050]
错误原因：进行commit transaction 时，我们链接orderer 节点的ip都是orderer.example.com:7050，当时已经进行了order url IP的修改，最后发现是在mychannel 中没有设置orderer 


3：在执行invoke 交易的时：
Event Server Status Code: (10) ENDORSEMENT_POLICY_FAILURE. Description: received invalid transaction
错误原因：出现的错误，错误原因是背书策略错误。

4：执行 query 交易时
event service creation failed: could not get chConfig cache reference: QueryBlockConfig failed: target(s) required Failed to create new channel client: event service creation failed: could not get chConfig cache reference: QueryBlockConfig failed: target(s) required 
出现这个错误的原因是我们没有在mychannel 的peers 部分添加对应的peer 

5：执行query 与invoke 交易时
event service creation failed: could not get chConfig cache reference: QueryBlockConfig failed: queryChaincode failed: Transaction processing for endorser [39.98.194.244:7251]: Endorser Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection timed out [39.98.194.244:7251] 
错误原因：出现这个错误的原因，大概率是tls 错误

1：fabric 的全部安装工作，
2：fabric-sdk-go 的配置部署， 
3：错误笔记
4：query,invoke 的使用例子。

配置的详细使用介绍。
