Fabric

官网:https://haomo-tech.com

作者:毫末科技

邮箱:hxg@haomo-studio.com

微信二维码:

1 系统概述

1.1 HyperLeger

包含以下几个模块

  • Hyperledger Fabric:

    区块链技术的一个实现,它的目标是成为开发应用和解决方案的基础,设计为模块化架构,允许组件如共识和成员服务模块,可以插入即用。

  • Hyperledger Sawtooth:高度模块化的分布式账本平台,Hyperledger Sawtooth是一个模块化平台,用以创建、部署和运行分布式账本。Hyperledger Sawtooth包含诺韦尔共识算法,计时验证(PoET), 它针对的是以最小的资源消耗处理大量的分布式验证器。

  • Hyperledger Iroha:轻量级分布式账本,侧重于移动。Hyperledger Iroha 是一个业务区块链框架,用于简单和容易地并入需要分布式账本技术的基础设施项目。

  • Hyperledger Burrow:智能合约客户端,是一个可以许可的智能合同机。Burrow发布于2014年12月,首次提供了一个模块化的、带经过许可的智能合约解释器的区块链客户端,它采用了部分以太坊虚拟机(EVM)的技术规范。

  • Hyperledger Indy:Hyperledger Indy 提供了工具、程序库和可重复使用的组件,用于提供基于区块链或者其它分布式账本的数字身份,从而让它们跨管理域、跨应用和其他silo进行互操作。

  • Hyperledger Explorer:展示和查询区块链块、事务和相关的Web应用。Hyperledger Explorer 可以查看、调用、部署或者查询区块、事务和相关数据、网络信息、链码和事务序列,以及任何其它保存在账本中的相关信息。

  • Hyperledger Cello:Bass工具集,帮助创建、管理、终止区块链。Hyperledger Cello 的目标是将按需的 “即服务” 部署模式带给区块链生态系统,减少创建、管理和终止区块链所需要的工作量。

  • Hyperledger Composer:Hyperledger Composer 是一个协同工具,用以创建区块链业务网络,加速智能合约及其跨分布式账本部署的发展。

1.2 什么是Fabric

GitHub 地址:https://github.com/hyperledger/fabric

Linux基金会于2015年成立超级账本,以推进跨行业的区块链技术。相对于申报一个区块链标准,它鼓励通过社区合作的方式来发展区块链技术,带着知识产权,鼓励开源,且随着时间的推移来采用不同的标准。

Fabric是超级账本区块链中的一个项目,与其他的区块链技术一样,它具有一个账本,使用智能合约,且是一个参与者可以分别管理自身交易的系统。

Fabric与其他区块链系统最大的不同在于它是隐私的、许可的网络。相对于像其他区块链那样通过“工作量证明”来验证身份(允许任何人加入网络),Fabric的成员通过会员注册服务提供商来加入网络。

Fabric提供了多种可插拔的选择,账本数据可以以多种形式存储,共识机制可切换,且支持不同的会员服务。Fabric还提供了创建通道的能力,允许一组参与者创建一个单独的账本交易。这对于一些不想让其竞争对手(同为参与者)知道其每一笔交易的参与者来说尤其重要,如果两个参与者间创建了一个通道,那么其他参与者不会拿到此通道的数据。

共享账本

超级账本的总账子系统包括两部分:世界状态与交易日志。Fabric的每个参与者都持有一份账本副本。世界状态部分描述了账本在某个时间点的状态。它是账本的数据库。交易日志部分则记录了导致当前世界状态的所有交易,是世界状态的历史记录。账本是世界状态与交易日志的结合。

账本的世界状态有可替换的数据存储区,默认是Level-DB键值数据库。交易日志不需要可插拔,它只是简单的记录了账本交易前后的数据。

智能合约

Fabric智能合约写在链码中,且当外部应用与账本互动时被调用。大多数情况中,链码只与账本的数据库部分互动(查询等),即世界状态,而不是交易日志。链码可以被多种语言编写,当前支持Go与Java,未来会发布更多语言的支持。

私密性

私密性依赖于网络的需求,对于一个B2B网络的参与者来说,对共享的信息量尤其敏感。相对于其他开放网络,Fabric网络支持私密性的关键业务需求。

共识

交易必须按照它们发生的顺序写入账本,即使它们可能发生在网络中不同的参与者身上。为了做到这一点,必须建立交易的排序服务,且有一套抵制错误交易(恶意)写入账本的方法。

这是一个已经在计算机科学中被研究的比较彻底的领域,有许多方法可以实现它,且每种方法都有不同的取舍。比如PBFT(实际拜占庭容错)提供了一个机制使得文件副本互相交流来保持一致,哪怕出现一定数量的背叛。再比如在比特币中,排序发生在一个叫做采矿的过程中,在这个过程中,竞争的计算机竞相解决一个密码难题,它定义了所有交易处理随后建立的顺序。

Hyperledger Fabric已经被设计成允许网络建立者选择一个共识机制最能代表参与者之间存在的关系。与私密性一样,有各种各样的需求:在关系上是更高度结构化的网络,还是更为对等的网络。

1.2 发展历史

1.3 发展现状

1.4 未来趋势

1.5 名词解释

  • Anchor(锚点):一般指作为刚启动时候的初始联络元素或与其它结构的沟通元素。如刚加入一个 channel 的节点,需要通过某个锚点节点来快速获取 channel 内的情况(如其它节点的存在信息)。
  • Auditability(审计性):在一定权限和许可下,可以对链上的交易进行审计和检查。
  • Block(区块):代表一批得到确认的交易信息的整体,准备被共识加入到区块链中。
  • Blockchain(区块链):由多个区块链接而成的链表结构,除了初始区块,每个区块头部都包括前继区块内容的 hash 值。
  • Chaincode(链码):区块链上的应用代码,扩展自“智能合约”概念,支持 golang、nodejs 等语言,多为图灵完备。
  • Channel(通道):Fabric 网络上的私有隔离。通道中的 chaincode和交易只有加入该通道的节点可见。同一个节点可以加入多个通道,并为每个通道内容维护一个账本。
  • Committer(提交节点):1.0 架构中一种 peer 节点角色,负责对 orderer 排序后的交易进行检查,选择合法的交易执行并写入存储。
  • Commitment(提交):提交节点完成对排序后交易的验证,将交易内容写到区块,并更新世界观的过程。
  • Confidentiality(保密):只有交易相关方可以看到交易内容,其它人未经授权则无法看到。
  • Endorser(推荐节点或背书节点):1.0 架构中一种 peer 节点角色,负责检验某个交易是否合法,是否愿意为之背书、签名。
  • Endorsement:背书过程。按照 chaincode 部署时候的 endorsement 策略,相关 peer对交易提案进行模拟和检查,决策是否为之背书。如果交易提案获得了足够多的背书,则可以构造正式交易进行进一步的共识。
  • Invoke(调用):一种交易类型,对 chaincode 中的某个方法进行调用,一般需要包括调用方法和调用参数。
  • Ledger(账本):包括区块链结构(带有所有的交易信息)和当前的世界观(world state)。
  • Member(成员):代表某个具体的实体身份,在网络中有用自己的根证书。节点和应用都必须属于某个成员身份。同一个成员可以在同一个通道中拥有多个 peer 节点,其中一个为 leader 节点,代表成员与排序节点进行交互,并分发排序后的区块给属于同一成员的其它节点。
  • MSP(Member Service Provider,成员服务提供者):抽象的实现成员服务(身份验证,证书管理等)的组件,实现对不同类型的成员服务的可拔插支持。
  • Non-validating Peer(非验证节点):不参与账本维护,仅作为交易代理响应客户端的 REST 请求,并对交易进行一些基本的有效性检查,之后转发给验证节点。
  • Orderer(排序节点):1.0 架构中的共识服务角色,负责排序看到的交易,提供全局确认的顺序。
  • Permissioned Ledger(带权限的账本):网络中所有节点必须是经过许可的,非许可过的节点则无法加入网络。
  • Privacy(隐私保护):交易员可以隐藏交易的身份,其它成员在无特殊权限的情况下,只能对交易进行验证,而无法获知身份信息。
  • System Chain(系统链):由对网络中配置进行变更的配置区块组成,一般可以用来作为组成网络成员们形成的联盟约定。
  • Transaction(交易):执行账本上的某个函数调用或者部署 chaincode。调用的具体函数在 chaincode 中实现。
  • Transactor(交易者):发起交易调用的客户端。
  • Validating Peer(验证节点):维护账本的核心节点,参与一致性维护、对交易的验证和执行。
  • World State(世界状态):即最新的全局账本状态。Fabric 用它来存储历史交易发生后产生的最新的状态,可以用键值或文档数据库实现。

2 系统目标及意义

Hyperledger Fabric是一种独特的分布式账本实现技术(DLT),提供企业级的网络安全性、可扩展性、保密性与性能,是一个模块化的区块链架构。Hyperledger Fabric提供了如下的区块链功能:

Fabric从功能上主要作用如下:

  • 提供分布式的部署方案。
  • 自动将本地的数据操作(账户建立、数据插入等)自动传送到全部节点上。
  • 提供数据查询,并确保数据的准确性和安全性。

2.1 身份管理

为了实现许可网络,Fabric提供了会员身份服务,在网络中管理用户ID与参与者的身份。访问控制列表可以通过授权特定的网络操作来提供额外的权限层。例如,一个特定的用户ID可以允许调用链码的应用程序,但禁止部署新的链码。关于Fabric网络的一个真理是,成员彼此认识(身份),但他们不知道对方在做什么(隐私保密)。

2.2 隐私保密

Fabric允许商业利益的角逐,允许要求私密交易的任何团体在同一许可网络共存。私有通道限制了消息传递路径,可用于为网络中特定子集的参与者提供交易的隐私性和机密性。通道上的所有数据(包括交易、成员和通道信息)对于未显式地授予对该通道访问权限的任何网络成员来说都是不可访问的。

2.3 高效处理

Hyperledger Fabric通过节点类型来分配网络角色。为了为网络提供并发性和并行性,交易处理与交易排序分开执行。在排序之前处理交易使每个对等节点能够同时处理多个交易。这种并发执行提高了每个对等节点的处理效率,加快了交易向排序服务的交付。

除了实现并行处理外,劳动力的分工使得排序节点免于大量的交易处理与账本维持工作,而对等节点则从排序共识工作负担中解脱出来。角色的这种分叉也降低了授权和验证所需的处理要求;所有对等节点不必信任所有的排序节点,反之亦然,因此对其中一个节点的处理可以独立于另外一个节点进行验证。

2.4 智能合约

链码应用的编码逻辑会被通道中具体类型的交易调用。链码定义了资产所有权转移的参数,例如,保证所有所有权转移交易依照相同的规则与要求。系统级链码区别于链码,它定义了整个通道的操作参数。生命周期与配置系统链码定义了通道规则,背书与验证系统链码定义了背书与验证交易的要求。

2.5 模块设计

Fabric实现了一个模块化的架构,为网络设计师提供功能选择。模块化还包括身份认证,共识算法以及加密算法。其结果是一个通用的区块链架构,在任何行业和公共领域都可以采用,以确保其网络可以在跨市场、监管以及地理边界时能够协同操作。

3 系统组成

3.1 Hyperledger Fabric模型

本节概述了关键的设计特点以使得Fabric履行承诺成为一个全面的、可定制的、企业级的区块链解决方案:

  • 资产:资产定义可以在网络中交易几乎所有具有货币价值的东西,从食品到古董汽车再到货币期货。
  • 链码:链码的执行可以划分为交易排序、限制信任等级要求、跨界点类型认证与优化网络性能与可扩展性几个部分。
  • 账本特点:不可改变的共享账本记录了每个通道的整个交易历史,并包含了用于高效审计与解决争议的类SQL查询功能。
  • 通道私密性:对于要求在公用网络上交换资产的相互竞争的企业与受管制的行业,通道机制使多层次的交易具有高度的隐私性和机密性。
  • 安全性与会员服务:会员服务提供可信的区块链网络,参与者了解所有交易可以被监管者与审计者检测与跟踪。
  • 共识:独特的共识机制满足企业级的灵活性与可扩展性的需求。

资产

资产范围涵盖了从有形资产(房地产和硬件)到无形资产(合同和知识产权)全部内容。Hyperledger Fabric提供了使用链码交易修改资产的能力。资产在Fabric中可以表示为一个键值对的集合,随着状态记录变更作为交易写入通道的账本中。资产可以用二进制或JSON形式表示。

你可以很轻松的在Fabric应用中定义并使用资产,通过使用工具:Hyperledger Composer。

链码

链码是定义资产与修改资产的指令。换句话说,它是业务逻辑。链码通过执行自身逻辑来查询或修改键值对或者其他数据库信息。链码函数通过数据库当前状态执行,且通过交易提案初始化。链码执行的结果是一系列键值写(写集),该写集将会被提交至网络并应用于所有节点中。

账本特点

账本是Fabric中所有的有序的、防篡改记录。状态转换是参与者进行链码调用后提交的结果。资产键值对集合的每笔交易结果都会以创建、更新、删除的形式提交。

总账有区块链以区块的形式来存储不可改变的、有序的记录,且有一个状态数据库来存储当前Fabric状态。每个通道有一个账本,通道中每个成员节点维护一个账本副本。

  • 使用基于Key的查询、范围查询、复合键查询来查询或更新账本。
  • 只读查询支持丰富的查询语句(CouchDB)。
  • 只读的历史查询——实现数据追溯场景。
  • 交易包含读取链码键值对(读集),以及写入链码键值对(写集)的版本。
  • 交易包含所有背书节点提交至排序服务的签名。
  • 交易被打包排序成区块,并通过通道从共识节点传至对等节点。
  • 对等节点通过背书政策标准来验证交易。
  • 在增加区块前,需要执行版本检查以确保数据在链码执行时间段没有被篡改。
  • 当交易被验证并承诺后,便不可改变。
  • 每个通道的账本都包含配置区块,它定义了政策标准、访问控制列表与其他相关信息。
  • 通道包含了会员服务提供商实例,因此加密证书能传递到不同的证书颁发机构。

通道私密性

Hyperledger Fabric在每个通道的基础上雇佣了不可改变的账本与链码,它可以操纵与修改当前资产状态(比如更新键值对)。账本在通道区域内存在——可以在整个网络中共享(假设所有参与者在同一个通道操作)——或者它可以私有化,只包含一组特定的参与者。

在后一种场景中,这些参与者将创建一个单独的通道,从而隔离他们的交易和账本。为了解决需要弥合总透明性和隐私之间的差距的场景,链码只能安装在需要访问资产状态进行读取和写入的节点(也就是说,如果一个链码没有被安装在节点上,它将无法与账本对接)。为了进一步混淆数据,链码内部数据可以在写入到账本之前加密,这可以使用常见的加密算法如AES等。

安全性与会员服务

Hyperledger Fabric支撑了一个所有参与者已知身份的交易网络。公钥基础设施在这里被用来生成绑定到网络中不同组织与应用客户端的加密证书。因此,它可以更广泛地在通道级别上操纵和控制数据访问控制。正是Fabric这种“许可”的概念,与通道的存在和功能,形成了隐私性与保密性这个关键问题的解决方案。

共识

在分布式账本技术中,一致性最近成为单个函数中特定算法的同义词。然而,共识不仅仅包含同意交易秩序,还包括在Fabric在整个交易流程的扮演基本角色,包括从提案和背书,再到排序,验证和承诺。简言之,一致性被定义为包含在一个块中的一组交易的正确性的一系列验证。

当打包后的交易的顺序以及结果通过标准检查后,才达成共识。这些验证发生在交易执行的整个生命周期中,这些标准包括:判定何种成员须支持何种交易类的使用,通过系统链码来保证这些标准的实施与维护等。对于最终承诺的确认,节点将雇佣这些系统链码来确保通过了足够多的验证。此外,在将任何包含交易的区块添加到账本之前,都会进行版本检查,最后的检查提供了对双花操作和其他可能危及数据完整性的威胁的保护措施。

除了大量的背书、验证与版本检查之外,还有一些不断进行的身份认证发生在交易流程的各个方面。例如:访问控制列表在分层的网络层中实现(从排序到通道),消息体被各种组件多次签名,检查并认证为一个交易提案。总的来说,共识不仅仅局限于某一批交易的顺序,而是一个总体特征,是一个交易从提案到承诺的过程中不断验证的副作用。

4 系统原理

4.1 交易周期

5 系统架构

交易流程

上图中:

  • 应用程序通过SDK发送请求道Peer节点(一个或多个)
  • peer节点分别执行交易(通过chaincode),但是并不将执行结果提交到本地的账本中(可以认为是模拟执行,交易处于挂起状态),参与背书的peer将执行结果返回给应用程序(其中包括自身对背书结果的签名)
  • 应用程序 收集背书结果并将结果提交给Ordering服务节点
  • Ordering服务节点执行共识过程并生成block,通过消息通道发布给Peer节点,由peer节点各自验证交易并提交到本地的ledger中(包括state状态的变化)

运行时架构

典型拓扑

Transaction 交易

包含两种:

  • 部署交易 Deploy:将ChainCode部署到区块链上
  • 调用交易 Invoke:调用部署的ChainCode

Nodes 节点

包含三种节点:

  • 客户端 Client
  • 对等节点 Peer
  • 一致性服务节点 Orderer

协议 Protocol

fabric是用gRPC来做P2P通讯的,是一个双向流消息传递。使用 Protocol Buffer来序列化要传递的数据结构。

Message

message分四种:

  • Discovery
  • Transaction
  • Synchronization
  • Consensus

5 产品介绍

5.1 商业产品

5.1.1 xxx商业产品

简介
功能模块
优缺点

5.1.2 xxx商业产品

简介
功能模块
优缺点

5.2 开源产品

5.2.1 xxx开源产品

简介
功能模块
优缺点

5.2.2 xxx开源产品

简介
功能模块
优缺点

6 开发

6.1 Ledger

6.2 官方容器说明

重要的官方容器包括:

  • hyperledger/fabric-ca CA节点
  • hyperledger/fabric-couchdb CouchDB持久化节点
  • hyperledger/fabric-orderer 一致性服务节点
  • hyperledger/fabric-peer 对等节点
  • hyperledger/fabric-ccenv 构建ChainCode的节点

6.3 使用Hyperledger Composer

Composer架构图

6.3.1 建模语言

6.3.2 ACL语言

ACL语言定义在.acl文件中,acl文件中的规则按顺序执行。通常acl文件名称应为permissions.acl,如果此文件存在,默认规则为拒绝(deny);如果此文件不存在,那么所有的人都具有所有权限。

ACL语言将对以下内容产生影响:

  • Composer网络控制
    • start 启动
    • download 下载
    • list 列举
    • loglevel 日志级别
    • ping
    • undeploy 取消部署
    • update 更新
  • Composer身份处理
    • import 导入
    • issue 发布
    • revoke 吊销
  • Composer参与者
    • add 添加

ACL具有两种类型的规则:

  • 简单ACL规则:根据participant类型或者participant实例,控制对namespace、asset或者asset的property的操作权限
  • 条件ACL规则 :引入participant和resource的变量,表达式为true则为ALLOW,表达式为false则为DENY。

关于ACL中的各个属性,说明如下:

  • Resource: ACL控制的对象。可以是类、命名空间或者是对象
    • Namespace: org.example.*
    • Namespace (recursive): org.example.**
    • Class in namespace: org.example.Car
    • Instance of a class: org.example.Car#ABC123
  • Operation:操作,包含CREATE, READ, UPDATE, DELETE,ALL四种,可以用逗号分隔开。当指定ALL时,指的是同时具有前面四种权限
  • Participant:参与者。可以指定类、对象或者ANY
    • Class in namespace: "org.example.Driver"
    • Instance of a class: "org.example.Driver#Fred"
    • ANY: "ANY"
  • Transaction:指定交易类型
  • Condition:使用JavaScript语法,返回结果需要是Boolean类型。可以采用if表达式。
  • Action:ALLOW或者DENY
示例

示例1,具有Network的所有操作权限:

rule networkControlPermission {
  description:  "networkControl can access network commands"
  participant: "org.acme.vehicle.auction.networkControl"
  operation: ALL
  resource: "org.hyperledger.composer.system.Network"
  action: ALLOW  
}

示例2,所有参与者具有所有操作权限:

rule AllAccess {
  description: "AllAccess - grant everything to everybody"
  participant: "org.hyperledger.composer.system.Participant"
  operation: ALL
  resource: "org.hyperledger.composer.system.**"
  action: ALLOW
}

示例3,简单规则:

rule SimpleRule {
  description: "Description of the ACL rule"
  participant: "org.example.SampleParticipant"
  operation: ALL
  resource: "org.example.SampleAsset"
  action: ALLOW
}

示例4,条件规则:

rule SampleConditionalRule {
  description: "Description of the ACL rule"
  participant(m): "org.example.SampleParticipant"
  operation: ALL
  resource(v): "org.example.SampleAsset"
  condition: (v.owner.getIdentifier() == m.getIdentifier())
  action: ALLOW
}

6.2.3 查询语言

查询语言定义在queries.qry文件中。所有的查询必须包含description和statement两个属性。

语法说明如下:

  • description:描述查询的功能
  • statement:定义查询的规则,有以下操作符:
    • SELECT:必选,定义registry,可以是asset或者participant类型
    • FROM:可选。指定registry。
    • WHERE:可选。 定义registry应该满足的条件。
    • AND:可选。WHERE操作符中的条件 与 操作。
    • OR:可选。WHERE操作符中的条件 或 操作。
    • CONTAINS:可选。数组对象“包含”关系。
    • ORDER BY:可选。定义返回结果排序规则。
    • SKIP:可选。定义跳过的数据数量。
    • LIMIT:可选。定义最大返回的数据数量,默认为25。

示例1 简单查询:

query Q20{
    description: "Select all drivers younger than the supplied age parameter or who are named Dan and whose lastName is not Selman, ordered by lastname, firstname"
    statement:
        SELECT org.acme.Driver
            WHERE ((age < _$ageParam OR firstName == 'Dan') AND (lastName != 'Selman'))
                ORDER BY [lastName ASC, firstName DESC]
}    

示例2 带参数查询:

query Q17 {
    description: "Select all drivers aged older than PARAM"
    statement:
        SELECT org.acme.Driver
            WHERE (_$ageParam < age)
}    

6.2.4 连接配置 Connection Profiles

完整的连接配置如下:

{
    "name": "my-fabric",
    "type": "hlfv1",
    "ca": {
        "url": "https://localhost:7054",
        "name": "ca.org1.example.com",
        "trustedRoots" : ["-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----", "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"],
        "verify": true
    },
    "orderers": [
        {
           "url" : "grpcs://localhost:7050",
           "cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
           "hostNameOverride": "ordererHostName"
        }
    ],
    "peers": [
        {
            "requestURL": "grpcs://localhost:7051",
            "eventURL": "grpcs://localhost:7053",
            "cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
            "hostNameOverride": "peerHostName"
        }
    ],
    "channel": "composerchannel",
    "mspID": "Org1MSP",
    "timeout": 300,
    "globalCert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
    "maxSendSize": 20,
    "maxRecvSize": 20,
    "hsm": {
        "library": "/usr/local/lib/myhsm.so",
        "slot": 0,
        "pin": 98765432
    }
}

对以上配置中的各个参数说明如下:

  • name:必选。定义连接配置的名字。
  • type:必选。定义目标Hyperledger Fabric的版本,对于Hyperledger Fabric v1.0 则必须填写 hlfv1。
  • ca:必选。定义Hyperledger Fabric的CA认证配置。
  • orderers:必选。指定要进行通讯的orderer节点。
  • peers:必选。指定要进行通讯的peers节点。
  • channel:?。指定通讯的频道。
  • hostnameOverride:可选。只用在测试环境下,不可用在生产环境下。
  • mspID:运行Fabric的组织的MSP ID.
  • timeout:可选。指定向orderer或peer发起请求的超时时间。
  • globalCert:可选。指定TLS证书。
  • maxSendSize:可选。定义outbound grpc消息的最大包尺寸,单位为MB。默认为?MB;如果设置为-1,则没有大小限制。
  • maxRecvSize:可选。定义inbound grpc消息的最大包尺寸,单位为MB。默认为?MB;如果设置为-1,则没有大小限制。
  • hsm:可选。硬件加密模块。Hyperledger Fabric v1.0支持硬件加密模块。
    • library:pkcs#11库的绝对路径。 is the absolute path to the pkcs#11 library required for communication with your specific HSM
    • slot:HSM的slot编号。
    • pin:slot的pin。

6.3 钱包

6.4 交易平台

7 参考资料

results matching ""

    No results matching ""