返回介绍

第 18 章 Hyperledger Fabric v2.0.0

发布于 2023-06-19 14:14:32 字数 19477 浏览 0 评论 0 收藏 0

18.1. 安装 Hyperledger Fabric v1.1.x

18.1.1. 依赖工具

			
yum -y install epel-release
yum install -y git
yum install -y golang
			
			

18.1.2. 安装Docker

			
curl -s https://raw.githubusercontent.com/oscm/shell/master/virtualization/docker/docker.centos7.ce.sh	 | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/virtualization/docker/registry-mirror.sh	 | bash
or 
curl -fsSL https://get.docker.com/ | sh	

创建2个docker网络,如下:
docker network create fabric_noops
docker network create fabric_pbft
			
			

安装 docker-compose

			
curl -s https://raw.githubusercontent.com/oscm/shell/master/virtualization/docker/docker-compose/docker-compose.sh	 | bash			
			
			

18.1.3. 安装 Node.js 环境

			
yum install -y nodejs
npm install
			
			

18.1.4. 安装 hyperledger 1.1.0

运行后 hyperledger 相关镜像被安装到 Docker 中

			
cd /usr/local/src
curl -s https://raw.githubusercontent.com/hyperledger/fabric/release/scripts/bootstrap-1.1.0.sh | bash			
			
			

由于上面脚本会安装所有节点,速度较慢,作者建议你参考下一章节,手工安装所需最低配置节点。

18.1.5. 手工安装 hyperledger v 1.1.0 开发环境

对于开发环境,最小化的环境,包括 1 个 peer 节点、1 个 Orderer 节点、1 个 CA 节点。

准备一个服务器或者虚拟机,安装 CentOS 操作系统。

如果你是在已有的Docker上安装,建议你删除所有容器后在安装。以免出现冲突等情况。

			
docker stop $(docker ps -q) && docker rm $(docker ps -aq)			
			
			

18.1.5.1. 登录 docker

				
[root@localhost ~]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: netkiller
Password: 
Login Succeeded				
				
				

18.1.5.2. Docker 安装

				
docker pull hyperledger/fabric-baseimage:latest \
  && docker pull hyperledger/fabric-membersrvc:latest \
  && docker pull hyperledger/fabric-peer:latest \
  && docker pull hyperledger/fabric-orderer:latest \
  && docker pull hyperledger/fabric-ca:latest \
  && docker pull hyperledger/blockchain-explorer:latest
				
				

安装会出现下面问题

				
[root@localhost ~]# docker search fabric-peer | grep hyperledger/fabric-peer
hyperledger/fabric-peer            Fabric Peer docker image for Hyperledger Pro…   69

[root@localhost ~]# docker pull hyperledger/fabric-peer:latest
Error response from daemon: manifest for hyperledger/fabric-peer:latest not found
				
				

可以 search 到的镜像 pull 不了,原因是 fabric-peer:latest,latest 不存在,你需要指定版本号。

				
docker pull hyperledger/fabric-ca:x86_64-1.1.0 \
&& docker pull hyperledger/fabric-peer:x86_64-1.1.0 \
&& docker pull hyperledger/fabric-orderer:x86_64-1.1.0 \
&& docker pull hyperledger/fabric-couchdb:x86_64-1.1.0 \
&& docker pull hyperledger/fabric-tools:x86_64-1.1.0

docker tag hyperledger/fabric-ca:x86_64-1.1.0 hyperledger/fabric-ca \
&& docker tag hyperledger/fabric-peer:x86_64-1.1.0 hyperledger/fabric-peer \
&& docker tag hyperledger/fabric-orderer:x86_64-1.1.0 hyperledger/fabric-orderer \
&& docker tag hyperledger/fabric-couchdb:x86_64-1.1.0 hyperledger/fabric-couchdb \
&& docker tag hyperledger/fabric-tools:x86_64-1.1.0 hyperledger/fabric-tools
				
				

查看镜像

				
[root@localhost src]# docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
hyperledger/fabric-orderer      latest              368c78b6f03b        2 months ago        151MB
hyperledger/fabric-orderer      x86_64-1.1.0        368c78b6f03b        2 months ago        151MB
hyperledger/fabric-peer         latest              c2ab022f0bdb        2 months ago        154MB
hyperledger/fabric-peer         x86_64-1.1.0        c2ab022f0bdb        2 months ago        154MB
hyperledger/fabric-membersrvc   latest              b3654d32e4f9        15 months ago       1.42GB				
				
				

18.1.5.3. 编译安装

				
git config --global core.autocrlf false				
$ git clone https://github.com/hyperledger/fabric.git 
$ make docker 
$ git clone https://github.com/hyperledger/fabric-ca.git		
$ make docker 

cd fabric/devenv
vagrant box add hyperledger/fabric-baseimage centos7.box
vagrant up

yum -y install epel-release
yum -y install git
yum -y install golang
yum -y install python-pip	
pip install --upgrade backports.ssl_match_hostname
pip install docker-compose

docker-compose -version
				
				

18.1.6. 启动 docker 虚拟机

体验 Hyperledger Fabric 在 https://github.com/hyperledger/fabric/tree/release/examples 下面有一些例子供用户学习。这里我选择的是 fabric-samples

这里我们最小化启动,需要四个节点,分别是 ca, peer, order, couchdb。

创建文件 docker-compose.yml

				
[root@localhost ~]# mkdir -p docker
[root@localhost ~]# cd docker
[root@localhost docker]# vim docker-compose.yml
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'

networks:
  basic:

services:
  ca.example.com:
    image: hyperledger/fabric-ca
    environment:
      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
      - FABRIC_CA_SERVER_CA_NAME=ca.example.com
      - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
      - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/4239aa0dcd76daeeb8ba0cda701851d14504d31aad1b2ddddbac6a57365e497c_sk
    ports:
      - "7054:7054"
    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
    volumes:
      - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
    container_name: ca.example.com
    networks:
      - basic

  orderer.example.com:
    container_name: orderer.example.com
    image: hyperledger/fabric-orderer
    environment:
      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderer
    command: orderer
    ports:
      - 7050:7050
    volumes:
        - ./config/:/etc/hyperledger/configtx
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/:/etc/hyperledger/msp/orderer
        - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/:/etc/hyperledger/msp/peerOrg1
    networks:
      - basic

  peer0.org1.example.com:
    container_name: peer0.org1.example.com
    image: hyperledger/fabric-peer
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer0.org1.example.com
      - CORE_LOGGING_PEER=debug
      - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      # # the following setting starts chaincode containers on the same
      # # bridge network as the peers
      # # https://docs.docker.com/compose/networking/
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_basic
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
      # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
      # provide the credentials for ledger to connect to CouchDB.  The username and password must
      # match the username and password set for the associated CouchDB.
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: peer node start
    # command: peer node start --peer-chaincodedev=true
    ports:
      - 7051:7051
      - 7053:7053
    volumes:
        - /var/run/:/host/var/run/
        - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/msp/peer
        - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users
        - ./config:/etc/hyperledger/configtx
    depends_on:
      - orderer.example.com
      - couchdb
    networks:
      - basic

  couchdb:
    container_name: couchdb
    image: hyperledger/fabric-couchdb
    # Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password
    # for CouchDB.  This will prevent CouchDB from operating in an "Admin Party" mode.
    environment:
      - COUCHDB_USER=
      - COUCHDB_PASSWORD=
    ports:
      - 5984:5984
    networks:
      - basic

  cli:
    container_name: cli
    image: hyperledger/fabric-tools
    tty: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
      - CORE_CHAINCODE_KEEPALIVE=10
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
        - /var/run/:/host/var/run/
        - ./chaincode/:/opt/gopath/src/github.com/
        - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
    networks:
        - basic
    #depends_on:
    #  - orderer.example.com
    #  - peer0.org1.example.com
    #  - couchdb
			
				
			

启动 Docker

				
[root@localhost docker]# docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com couchdb			
				
			

查看进程

				
[root@localhost docker]# docker-compose ps 
         Name                       Command               State                       Ports                      
----------------------------------------------------------------------------------------------------------------
ca.example.com           sh -c fabric-ca-server sta ...   Up      0.0.0.0:7054->7054/tcp                         
cli                      /bin/bash                        Up                                                     
couchdb                  tini -- /docker-entrypoint ...   Up      4369/tcp, 0.0.0.0:5984->5984/tcp, 9100/tcp     
orderer.example.com      orderer                          Up      0.0.0.0:7050->7050/tcp                         
peer0.org1.example.com   peer node start                  Up      0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp
				
				
			
			

			
			

18.1.7. 管理 hyperledger

18.1.7.1. CouchDB 管理界面

					
[root@localhost fabcar]# curl http://localhost:5984
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}					
					
				
http://localhost:5984/_utils/

18.1.8. 部署 chaincode

18.1.8.1. channel 管理

Hyperledger Fabric Channel 可以理解为 vlan (交换机术语) 用来实现区块隔离。

				
[root@localhost docker]# docker-compose exec peer0.org1.example.com bash
root@dcb09db1cbc8:/go/src/github.com/hyperledger/fabric#				
				
				
18.1.8.1.1. 列出 channel
					
root@595ec455c0ff:/opt/gopath/src/github.com/hyperledger/fabric# peer channel list 
2018-02-07 03:24:41.151 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2018-02-07 03:24:41.152 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2018-02-07 03:24:41.154 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2018-02-07 03:24:41.155 UTC [msp/identity] Sign -> DEBU 004 Sign: plaintext: 0A85070A5B08031A0B08F9E2E9D30510...631A0D0A0B4765744368616E6E656C73 
2018-02-07 03:24:41.156 UTC [msp/identity] Sign -> DEBU 005 Sign: digest: 238CBAB61A0524954DC3C511588EB8FC1F886E636A8800131EBE16FB95FB0C9A 
2018-02-07 03:24:41.167 UTC [channelCmd] list -> INFO 006 Channels peers has joined to: 
2018-02-07 03:24:41.167 UTC [channelCmd] list -> INFO 007 mychannel 
2018-02-07 03:24:41.167 UTC [main] main -> INFO 008 Exiting.....					
					
					
18.1.8.1.2. 创建 Channel
					
CORE_PEER_LOCALMSPID=Org1MSP
CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp
peer channel create -o orderer.example.com:7050 -c mychannel -f /etc/hyperledger/configtx/channel.tx					
					
					
18.1.8.1.3. 加入 Channel
					
CORE_PEER_LOCALMSPID=Org1MSP
CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp
peer channel join -b mychannel.block
					
					

18.1.8.2. 部署连

				
[root@localhost basic-network]# docker-compose exec cli bash
root@b1ded848f967:/opt/gopath/src/github.com/hyperledger/fabric/peer#

				
				

安装合约

				
CORE_PEER_LOCALMSPID=Org1MSP
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
peer chaincode install -n fabcar -v 1.0 -p github.com/fabcar			
				
				

实例化合约

				
CORE_PEER_LOCALMSPID=Org1MSP
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n fabcar -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
				
				

初始化合约

				
CORE_PEER_LOCALMSPID=Org1MSP
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"initLedger","Args":[""]}'				
				
				

18.1.8.3. 查询合约

				
root@b1ded848f967:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode query -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"queryCar","Args":["CAR9"]}'
2018-02-07 05:11:59.737 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2018-02-07 05:11:59.737 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2018-02-07 05:11:59.738 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2018-02-07 05:11:59.738 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2018-02-07 05:11:59.738 UTC [msp/identity] Sign -> DEBU 005 Sign: plaintext: 0A93070A6908031A0C089F95EAD30510...0A0871756572794361720A0443415239 
2018-02-07 05:11:59.739 UTC [msp/identity] Sign -> DEBU 006 Sign: digest: 84E6F021BEA8C5F2D97B1C8BFEA4BB07B91DBC167E0BBD188260B234DC4620E8 
Query Result: {"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}
2018-02-07 05:11:59.771 UTC [main] main -> INFO 007 Exiting.....

				
				

18.1.8.4. 调用合约

调用合约,新增一条记录,然后做查询操作。

				
peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"createCar","Args":["CAR15", "Toyota", "Rezi", "White", "Neo"]}'				
peer chaincode query -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"queryCar","Args":["CAR15"]}'
				
				

演示结果

				
root@b1ded848f967:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"createCar","Args":["CAR15", "Toyota", "Rezi", "White", "Neo"]}'
2018-02-07 05:16:57.415 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2018-02-07 05:16:57.415 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2018-02-07 05:16:57.417 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2018-02-07 05:16:57.417 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2018-02-07 05:16:57.418 UTC [msp/identity] Sign -> DEBU 005 Sign: plaintext: 0A93070A6908031A0C08C997EAD30510...52657A690A0557686974650A034E656F 
2018-02-07 05:16:57.418 UTC [msp/identity] Sign -> DEBU 006 Sign: digest: D9BDF565353FFAD37CDC64DBFBD06DA8B5A049AA32305E1668A695E6522C3043 
2018-02-07 05:16:57.443 UTC [msp/identity] Sign -> DEBU 007 Sign: plaintext: 0A93070A6908031A0C08C997EAD30510...4B5F674D96D8DE9BE699613B72ED46B1 
2018-02-07 05:16:57.443 UTC [msp/identity] Sign -> DEBU 008 Sign: digest: 2951E3522A902D2644E08508E52A1D833AF9E11A420EE933851CC5673B005375 
2018-02-07 05:16:57.451 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 009 ESCC invoke result: version:1 response:<status:200 message:"OK" > payload:"\n \327\324\006\316\004\230\3262{\300\\|\275\035\336\243\316L\232\247x\020n`2\346\334\031\n(<\262\022\204\001\nn\022T\n\006fabcar\022J\032H\n\005CAR15\032?{\"make\":\"Toyota\",\"model\":\"Rezi\",\"colour\":\"White\",\"owner\":\"Neo\"}\022\026\n\004lscc\022\016\n\014\n\006fabcar\022\002\010\001\032\003\010\310\001\"\r\022\006fabcar\032\0031.0" endorsement:<endorser:"\n\007Org1MSP\022\200\006-----BEGIN -----\nMIICGjCCAcCgAwIBAgIRAPlwF/rUZUP9mqN4wSml4iswCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwODMxMDkxNDMyWhcNMjcwODI5MDkxNDMy\nWjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEfMB0GA1UEAxMWcGVlcjAub3JnMS5leGFtcGxlLmNvbTBZ\nMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHihxW6ks3B2+5XdbAVq3CBgxRRRZ22x\nzzpqnD86nKkz7fBElBuhlXl2K6rTxyY2OBOB0ts8keqZ93xueRGymrajTTBLMA4G\nA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIEI5qg3Ndtru\nuLoM2nAYUdFFBNMarRst3dusalc2Xkl8MAoGCCqGSM49BAMCA0gAMEUCIQD4j0Rn\ne1rrd0FSCzsR6u+IuuPK5dI/kR/bh7+VLf0TNgIgCfUtkJvfvzVEwZLFoFyjoHtr\ntvwzNUS1U0hEqIaDeo4=\n-----END -----\n" signature:"0E\002!\000\364q\r\026\267\205\357\245\006\364\354v\333r92\022l\2267[Yb@F\263N\230\324\351.\025\002 \022K\275P\234\262A\3338\244\337\216\340q%-K_gM\226\330\336\233\346\231a;r\355F\261" > 
2018-02-07 05:16:57.451 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 00a Chaincode invoke successful. result: status:200 
2018-02-07 05:16:57.451 UTC [main] main -> INFO 00b Exiting.....


root@b1ded848f967:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode query -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"queryCar","Args":["CAR15"]}'
2018-02-07 05:17:07.383 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2018-02-07 05:17:07.383 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2018-02-07 05:17:07.383 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2018-02-07 05:17:07.383 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2018-02-07 05:17:07.384 UTC [msp/identity] Sign -> DEBU 005 Sign: plaintext: 0A93070A6908031A0C08D397EAD30510...0871756572794361720A054341523135 
2018-02-07 05:17:07.384 UTC [msp/identity] Sign -> DEBU 006 Sign: digest: FBFD595C716FB185BABBBD3709040F6D1538964931BA47A8B653E878C2084C4B 
Query Result: {"colour":"White","make":"Toyota","model":"Rezi","owner":"Neo"}
2018-02-07 05:17:07.411 UTC [main] main -> INFO 007 Exiting.....

				
				

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文