读懂以太坊的客户端多样性 为何如此重要?
以太坊有多个可互操作的客户端,由独立团队用不同的语言开发和维护。这是一项重大成就,通过将漏洞或攻击的影响限制在运行受影响客户端的网络部分,可以为网络提供弹性。然而,只有当所有用户大致均匀地分布在各个可用的客户端上时,才能实现这种优势。目前,绝大多数以太坊节点运行单个客户端,给网络带来不必要的风险。
以太坊将很快经历自成立以来其架构最重要的一次升级——从工作量证明 (PoW) 到权益证明 (PoS) 的合并。这将从根本上改变该网络对区块链的真实状态达成共识的方式,并维护网络安全。这种新架构将带来安全性、可扩展性和可持续性方面的好处,但同时也放大了与这种由单个客户端占主导地位有关的风险。这篇文章将探讨其中的缘由...
信标链
信标链是一条 PoS 区块链。它目前与以太坊主网并行运行,但两者很快将“合并”在一起。合并之后,现有的以太坊主网客户端 (“执行客户端”) 将继续托管以太坊虚拟机 (EVM),并验证和广播交易,但将停止参与工作量证明 (PoW) 挖矿,并放弃对区块链链头 (顶端区块) 达成共识的责任。相反,这种共识将成为“共识客户端”的责任,“共识客户端”负责把来自“执行客户端”的交易与共识所需的信息一起打包进“信标区块”中,这些信标区块就构成了信标链。“矿工”将被“验证者” (validators) 取代,这些验证者需要将 ETH 存入某个以太坊智能合约中 (这一过程称为“质押”(staking))。验证者质押的 ETH 将作为抵押品,以激励他们正确地完成验证工作。不履行验证工作 (比如因为离线) 或进行恶意行为的验证者,将导致其质押的 ETH 的一部分被销毁。另一方面,如果验证者行为得当,那么将会获得 ETH 奖励。
1. 验证者的职责
对于验证者来说,良好的行为意味着参与验证从其他验证者那里接收到的信标区块,并对区块链链头进行投票。如果验证者接收到的区块是有效的,那么验证者将对区块进行“证明”(attest),实际上就是投票支持将该区块添加到区块链中。一个节点将不定期地被要求提议一个新区块,其他验证者将“证明”该区块。当区块链有多个分叉时,只有那条在其历史上积累了最多“证明”(attestations) 的链才是正确的区块链。
验证者还将不定期地参与到某个同步委员会 (sync committee) 中,同步委员会是一个由随机选择的 512 名验证者组成的小组,这些被随机选中的验证者将对区块头 (block headers) 进行签名,这样轻客户端就可以检索这些被验证过的区块,而无需访问整条历史链或整个验证者集。
2. 合理化 & 被敲定
信标链为网络设定节奏。这种节奏被组织成两个时间单位:slot 和 epoch。slot 是将区块添加到信标链的机会,每 12 秒出现一次。某个 slot 可能没有区块,但当系统以最佳方式运行时,区块会添加到每个可用的 slot 中。epoch 是以 32 个 slot (约 6.4 分钟) 为单位的。slot 和 epoch 设定了以太坊区块链的节奏。
在每个 epoch 期间,第一个 slot 中的区块是一个检查点 (checkpoint)。检查点是非常重要的,因为检查点被用于使区块链账本上的记录变得永久和不可逆转——这是一个分为两个阶段的过程:首先,如果所有活跃验证者质押的 ETH 余额中至少有 2/3 (即“绝对多数”) 证明了最近的两个检查点 (当前的被称为“目标检查点”,前一个被称为“源检查点”),那么这两个检查点之间的这段区块就被“合理化” (justified) 了。“合理化”是迈向成为以太坊权威链上永久记录的第一步。一旦某个被“合理化”的检查点之后新出现了另一个被“合理化”的检查点,那么前一个检查点就是“被敲定” (finalized) 了,也即使其具有了永久性和不可逆转 (即这个检查点之前的所有记录都成为了区块链上永久不可篡改的记录)。
这个“合理化”和“敲定”的过程要求验证者进行的“证明”(attestations) 实际上要比上文阐述的要更复杂一些。有两种类型的证明:一种是 LMD GHOST 投票,用于证明区块链的链头 (LMD GHOST 是分叉选择算法);第二种是用于对两个检查点进行证明的 FFG 投票 (FFG 是“最终性小工具” (finality gadget),对区块链进行合理化和最终敲定)。所有验证者都会对每个检查点进行 FFG 投票,而只有一个随机选中的验证者子集在每个 slot 进行 LMD GHOST 投票。
3. 验证者的质押奖励、惩罚和罚没
奖励
如前所述,验证者质押的 ETH 用于作为“抵押品”,以激励验证者的诚实行为。随着验证者因为参与到保护网络中而获得奖励,这些被质押的 ETH 将随着时间的推移而增加。当验证者进行的 LMD-GHOST 投票和 FFG 投票与大多数其他验证者一致时,那么验证者就会获得证明奖励。当验证者被选中作为“区块提议者”(block proposer) 时,如果其提议的区块被“敲定”, 那么该验证者也将获得奖励。区块提议者也可以通过将有关其他验证者行为不当的证明打包进自己提议的区块中,从而增加自己获得的奖励。这些奖励是鼓励验证者诚实行事的“报酬”。
惩罚
验证者可能受到的“惩罚”是以各种机制的形式来销毁一部分验证者质押的 ETH。当验证者未能提交一个 FFG 投票、提交延迟了或者提交了错误的 FFG 投票时,都会受到证明惩罚 (attestation penalties)。但如果验证者错过了进行 LMD-GHOST 投票,则不会受到惩罚,只是错过了本可以通过对链头进行投票而获得的奖励。验证者余额被削减的数额,等同于如果他们提交正确的证明而本可以获得的奖励数额。这意味着,一个诚实但“懒惰”的验证者,他因为错过了证明而遭受到的最大惩罚,就是损失他如果以完美的方式进行证明时本可以获得的奖励金额的 3/4。此外,当验证者被分配至“同步委员会”(sync committee) 时,如果该验证者未能签名区块,那么其受到的惩罚将等同于如果他成功地签名区块时本可以获得的 ETH 价值。
总的来说,这些惩罚是温和的,验证者持续的怠惰 (inactivity) 仅会使其质押的 ETH 受到一个相当缓慢的削减。
罚没
罚没 (slashing) 是一种更严重的行为,这会导致验证者被强制从网络中移除,并导致相关的 ETH 质押金损失。有三种方式会导致验证者被罚没,所有这些都相当于验证者进行了不诚实的区块提议或区块证明:
在同一个 slot 提议和签名两个不同的区块;
对“环绕”某个区块的另一个区块进行证明 (实际上就是更改区块链历史);
通过对同一个区块的两个候选区块进行“双重投票”(double voting)。
如果检测到上述这些操作,验证者就会罚没。这意味着相当于其质押的 ETH 的 1/64 (最高可达 0.5 ETH) 将立即被销毁,然后一个为期 36 天的移除期开始了:在此期间,验证者的质押金将逐渐被削减;且在这段期间的中间点 (第18天),该验证者还将受到额外的惩罚,惩罚大小将与此次罚没事件发生之前的 36 天内所有被罚没的验证者的 ETH 质押总额成比例。这意味着,当更多的验证者被罚没时,此次罚没的量级将会增加。最大的罚没是所有被罚没的验证者的全部有效余额 (也即,如果有大量验证者被罚没,那么他们可能损失全部的质押金)。另一方面,一个单独的、独立的罚没事件只会销毁验证者一小部分的质押金。这种随着被罚没验证者的数量而变化的中间惩罚被称为“串谋惩罚”(correlation penalty)。
Inactivity Leak 机制
如果信标链已经有超过 4 个 epoch 都没有被敲定,那么一个称为“inactivity leak”的经济机制将被激活。Inactivity leak 的最终目的是创造条件使区块链重新恢复敲定。如上文所解释的,“敲定”(finality) 需要 2/3 的 ETH 总质押金对“源检查点”和“目标检查点”达成共识。如果超过 1/3 的验证者离线或未能提交证明的证明,那么就不可能有 2/3 的绝对多数验证者来敲定检查点。此时,Inactivity leak 机制会让属于这些不活跃的验证者的 ETH 质押金逐渐被削减,直到这些验证者控制的质押金少于网络中总质押金的 1/3,从而允许剩余的活跃验证者对区块链进行敲定。无论这些不活跃的验证者数量有多大,剩余的验证者最终都将控制 >2/3 的总质押金。这种质押金的削减将是一个强烈的刺激因素,激励不活跃的验证者尽快重新激活!
信标链设计中的奖励、惩罚和罚没鼓励了个体验证者正确行事。然而,从这些设计选择中出现了一个系统,它强烈地激励了验证者在多个客户端之间的平等分配,并强烈地抑制这种由单个客户端占主导地位的情况。这是因为,“绝对多数制”对于信标链来说非常重要,单独一个恶意验证者对网络而言是相当无害的,但大量恶意验证者将可能造成严重破坏。让我们来看看一些潜在的场景......
风险场景
这种资产激励共识客户端多样性是有风险的。通过在多个客户端之间均匀分布验证者,可以大大减少针对特定客户端的攻击或漏洞带来的影响,而单一客户端占主导地位则会增加这种风险。这种风险倍增效应会随着单个主导性客户端占据的网络份额多少而变化。
我们可以通过一些假设的 (但可能实际会发生的) 场景来获得更多的直觉感知。让我们假设一个 bug 意外地被引入到一个共识客户端中,这个 bug 可以直接导致该客户端进行不正确的证明,或者暴露一个漏洞,使得恶意攻击者能够迫使客户端进行不正确地证明。那么,客户端多样性会如何影响这种 bug 带来的后果呢?
场景1:受影响的客户端控制了少于 1/3 的 ETH 质押金
这种情况为信标链提供了最大的弹性,因为仍有 2/3 被质押的 ETH 仍在进行正确地证明,允许信标链正常地进行敲定。因此,从网络的角度来看,这种场景的后果是可以忽略的。受影响的验证者将受到怠惰惩罚,因为他们提交了不正确的证明。这些损失相对较小,受影响的验证者可以等待客户端被修复或者切换到另一个客户端。无论哪种方式,验证者都可以以最小的经济后果和不会破坏信标链的方式继续进行正确的证明。
场景2:受影响的客户端控制了超过 1/3 的 ETH 质押金
这种情况的问题要大得多,因为只剩不到 2/3 的 ETH 质押金在正确地进行证明,即没有绝对多数的验证者来正确地达成共识。这意味着信标链无法实现敲定,且 Inactivity Leak 机制将被激活。此时,这个 bug 对整个网络造成了影响。对于搭建在以太坊之上的交易所和 Dapps (去中心化应用) 而言,区块链被敲定 (finality) 是至关重要的,如果区块链无法被敲定,那么就不能保证交易是永久性和不可篡改的。对于使用了这个受影响的客户端的个体验证者来说,相关的惩罚要严重得多,因为 Inactivity Leak 机制的激活意味着个体验证者质押的 ETH 将逐步被销毁,直到这个受 bug 影响的客户端控制了少于 1/3 的 ETH 总质押金,且只有到那个时候信标链才会恢复敲定。这种 ETH 的销毁可能实际上会在信标链恢复之后持续一段时间,从而为验证者数量的较小变化提供缓冲。只有当一个受影响的客户端控制了超过 1/3 的 ETH 总质押金时,信标链的敲定才会处于危险之中。
在这种场景中,正常运行其他替代性客户端的验证者在 Inactivity Leak 机制被激活期间不会收到任何奖励。这是一种安全机制,用于防止攻击者蓄意启动 Inactivity Leak 机制,从而提高该攻击者控制的其他以正确方式运行的验证者获得的总奖励。这些都是很小的惩罚,但关键是,没有人能从一个控制着超过 1/3 的 ETH 总质押金的客户端的共识 bug 的负面后果中逃脱。
场景3:受影响的客户端控制着 1/2 的 ETH 质押金
这种情况可能导致信标链中出现不可恢复的分叉。如果有共识 bug 的客户端分叉到它自己的链上,那么原始的链和新的分叉链都无法实现敲定,因为新旧两条链都缺失了大约一半的验证者,并且都将激活 Inactivity Leak 机制。此时,这两条链上缺失的验证者的 ETH 质押金将会逐渐被销毁,直到他们控制的质押金少于 1/3 的网络 ETH 总质押金,此时每条链上的验证者才可以再次开始进行敲定。这个过程在两条链上花费的时间相同,因为恢复敲定需要销毁的 ETH 数量是相等的。这两条链将使用不同的检查点来独立完成敲定。这两条链可能永远不会合并成为一条单独的“权威链”。解决方法将需要以太坊社区对哪条链是“权威链”达成共识,这个过程肯定会在政治上很难处理和引发分歧,导致一半的社区由于切换区块链而产生的经济损失 (这还不包括 ETH 可能贬值)。也许更糟糕的是,社区可能只是继续分裂下去 (类似于 The DAO 事件导致以太坊经典的产生)。
为了避免信标链的永久分裂,使用受影响的客户端的验证者将必须与 Inactivity Leak 赛跑进行客户端切换,或者在区块链开始敲定之前修复他们的客户端。可能有 3-4 周时间,在此期间开发者将争相拯救以太坊。在这个场景中,对于大量的验证者来说,无法逃避重大的经济损失。
场景4:受影响的客户端控制着超过 2/3 的 ETH 质押金
对于信标链来说,这是噩梦般的情况,因为受影响的客户端控制着一个超级多数的验证者,并且能够敲定自己的链。这样,不正确的信息就很有可能永远被固定在以太坊的历史记录中。在区块链开始敲定非法区块之前,客户端团队将有大约 13 分钟的时间来确定该共识 bug、修复它,并将客户端更新信息广播给受影响的验证者。
对于这种情况,唯一可行的缓解方法是让受影响的验证者取出他们质押的 ETH 并从区块链中退出。如果在 bug 修复之后,这些受影响的验证者试图重新加入那条正确的区块链中,他们将由于“串谋惩罚”而被罚没,因为他们此时证明的检查点是与他们之前证明的检查点相矛盾,而且是集体进行这样的操作。Inactivity Leak 机制将由于大量验证者离去而被激活,这意味着这些受影响的验证者将在他们等待取款 (退出) 时不断损失他们的 ETH 质押金。由于有大量验证者要退出,因此等待的队伍将很长、缓慢和昂贵。
唯一的其他选择是,剩下的未受影响的客户端接受该 bug,加入新的链,并同意该 bug 从此成为以太坊共识层的预期行为。这将与 staking (质押) 社区的核心原则背道而驰,而且会造成极大的分裂。这些少数客户端将在新链上受到怠惰惩罚,即使他们的行为得当。
两种选择都不是好的选择。前一个选择对于受影响的验证者来说非常昂贵,并且在逻辑上难以纠正。后一种选择将严重破坏对以太坊的信任,并导致我们接受一个永久被玷污的链。
其他风险
逆转最终性
如果单个客户端控制着超过 2/3 的 ETH 总质押金,那么该客户端的开发者就有能力选择哪个版本的区块链历史是正确的。比如,如果该客户端的开发者变得恶意,他们可以花费一些 ETH (比如通过某个交易所套现,或者桥接到另一个区块链网络),然后这些开发者集体投票,使用另一个不包含这笔花费交易的链版本来代替当前这个已经被敲定的链。这是一种“双花”,因为该客户端控制着绝大多数验证者使其能够逆转最终性和重写历史。与此同时,诚实的少数验证者会因为他们不一致的证明而受到惩罚。一个恶意的控制了绝对多数 ETH 总质押金的攻击者也可以威胁做出这样的行为,并控制网络索要赎金。即便是一个控制着 1/3 的 ETH 总质押金的恶意团队也可以威胁停止链的敲定并激活 Inactivity Leak 机制。
共同的责任
前一点对客户端开发团队的看法有些悲观,不是因为这是合理的,而是因为恶意行为是可能的,因此需要防范。然而,这些开发人员最有可能永远是好人,他们自己需要抵制单个客户端占主导性地位,不仅仅是因为他们很可能是以太坊用户 (以及 ETH 持有者或质押者),还因为网络安全的责任不应该集中在一个小团队的肩上。开发者的行为对整个以太坊的健康造成了巨大的影响,他们的压力和心理健康是真正的代价。客户端多样性通过在多个独立团队之间分担责任来避免这种情况。
中心化
即使客户端开发团队由完全出于善意的开发者组成,当他们控制了大部分的 ETH 质押金时,他们仍然保留了以太坊运作方面的过度权力。去中心化是以太坊的一个核心原则,这必须包括开发者、用户和托管商的去中心化。跨多个客户端的开发团队的去中心化,通过均匀分配 ETH 质押金,从而限制了单个客户端团队对诸如分叉内容和时间等做出关键决策,从而限制了他们对以太坊哲学方向的影响。客户端多样性确保了在开发者层面做出去中心化的决策。
政治
对一条诚实链的社交恢复 (social recovery) 是一个充满政治的问题。以太坊的共识机制应该基于编码到其客户端的规则来确定——这是它的主要目标。干预这一过程可能会导致以太坊社区的分裂,导致不同的用户在哲学上、伦理上和技术上对于缓解某个主要客户端的共识 bug/攻击有各种各样的观点。治理决策将是笨拙的、破坏性的,而且可能过于缓慢而无法达到最大的有效性。
真实例子
上述场景发生的概率相对较低。开发者在研究和测试他们软件的每一个更新时都是一丝不苟的,没有理由怀疑任何客户端团队的职业操守。然而,这些场景也不是纯粹的假设。已经有真实例子表明,客户端多样性拯救了以太坊主网,使其免于永久损坏,且一些共识 bug 也破坏了以太坊测试网。下面将介绍其中的一些例子。
上海攻击
2016年9月,在上海 DevCon 会议期间,黑客攻击了以太坊,利用客户端软件中的几个漏洞,导致网络速度显著放缓。攻击者坚持不懈,迅速部署新的类似攻击,而客户端开发人员则竞相对这些攻击进行逆向工程和修补。最终,攻击者在 Geth 客户端中发现了一个无法修补的漏洞,使得硬分叉成为必然。即使在硬分叉升级之后,攻击者仍然发现了一个拒绝服务漏洞,该漏洞利用之前攻击所导致的膨胀状态,迫使客户端在每个区块中进行数万次缓慢的磁盘I/O操作。客户端多样性赢得了胜利,因为当开发人员努力修复 Geth 中的漏洞时,以太坊能够继续使用替代性的 Parity 客户端,该客户端没有遭受同样的漏洞。
由于有多个客户端,上海攻击是可以恢复的,但如果一个类似的 bug 影响了多数共识客户端,情况可能会截然不同。如果一个“共识客户端”与当时 Geth 被攻击时有着相同的主导性地位,那么以太坊量将无法实现敲定,因为此时大多数验证者将无法对区块进行证明。Inactivity Leak 将被激活,因为只有少于 1/3 的 ETH 质押金可用于进行证明。
Insecura 链
“远程攻击”的可行性最近在 Pyrmont 测试网得到了证明。其想法是建立一组验证者来证明一个备用的区块链历史。然后,这些验证者被用来诱骗新的验证者加入这条不诚实的“Insecura”链,从而逐渐增加被影响的验证者的数量,最终达到中断区块链敲定、激活 Inactivity Leak 并耗尽诚实多数验证者的 ETH 质押金的程度。最终,这可能导致受影响的客户端最终敲定自己版本的区块链。虽然所需要的时间和金钱的投入使这种行为不太可能成为攻击向量,但类似的动态可能导致一个占主导地位的共识客户端中的一个 bug 感染网络的大部分。
Medalla 测试网
此前由于 Prysm 客户端的时钟问题,Medalla 测试网的活跃验证者数量突然下降。这条链无法进行敲定,因为太多的验证者退出了网络,以至于 2/3 绝大多数被质押的 ETH 已经不再可用于进行证明。其恢复是渐进的,因为这依赖于验证者将客户端从 Prysm 切换到其他少数客户端上。然后,真实的时间与 Prysm 客户端错误的时钟时间赶在一起,之前无效的证明突然间变得有效了。这导致 Prysm 客户端陷入停滞,同时 Teku 和 Lighthouse 客户端也因突然处理大量的证明而遭遇了巨大的状态膨胀。如果 Prysm 是 Medalla 测试网的唯一客户端,那么整个网络都已经停滞了;如果 Prysm 客户端控制了少于 1/3 的 ETH 总质押金,那么许多混乱就可以避免了。
Prysm 的存款根 bug
2021 年初,Prysm 客户端遇到了一个与 Eth1 存款根验证相关的 bug。当时,Prysm 客户端能够生成无效的存款根 (deposit root),并将其传递给其他 Prysm 节点。因为 Prysm 拥有如此大的验证者份额,这种无效的存款根很快在网络中传播,且由于 Prysm 遵循绝大多数投票机制而非在每个区块中显性地验证存款根,因此加速了其传播。虽然该 bug 带来的影响很小,没有中断信标链的敲定,也没有对验证者带来重大的经济惩罚,但这个事件从两个方面证明了客户端多样性的重要性:首先,如果 Prysm 客户端有着较小的验证者份额,那么就会限制该 bug 在整个网络的传播,减少其影响;其次,该事件发生后的分析文章描述了如何使用替代性客户端实现作为基准,帮助开发人员快速识别和修复该 bug。显然,如果没有多个积极维护的客户端,这是不可能实现的。
当前的客户端多样性
上图为当前以太坊客户端的多样性情况:左边为执行客户端的占比情况,右边为共识客户端的占比情况。
上面的两个饼状图显示了以太坊执行层和共识层的当前客户多样性的快照 (截至 2022 年 1 月撰写本文时):执行层由 Geth 客户端主导,OpenEthereum 客户端远远排在第二,Erigon 客户端排第三,Nethermind 排第四,其他客户端只占不到网络的 1%。共识层上最常用的客户端 Prysm 虽然不像执行层的 Geth 客户端那样占主导地位,但仍然拥有了超过 60% 的网络,Lighthouse 和 Teku 分别占 20% 和 14%,其他客户端则很少使用。
执行层数据于 2022 年 1 月 23 日通过 Ethernodes 网站 (ethernodes.org/) 获取;共识客户端的数据来自 Michael Sproul (github.com/sigp/blockprint)。共识客户端数据要更难获取,因为信标链客户端并不总是具有可以用来识别它们的明确踪迹。这些数据是使用一种分类算法生成的,这种算法有时会弄错一些少数客户端。然而,很明显,共识层的大部分网络节点都在运行 Prysm。Prysm 的优势有时更高,超过 68%。尽管只是快照,但图中的占比情况提供了客户端多样性的当前状态的良好总体认识。
执行层的客户端多样性包含在上图中,因为影响执行客户端的 bug 可能也会传播到共识层,这是由于合并之后,共识层和执行层将耦合在一起,且执行客户端生成的执行负载 (execution payload) 将是信标区块的核心组件。
个人质押者 & 质押池
解决客户端分配不平衡的问题,需要主要交易所和押注池 (stking pools) 采取行动。然而,个人质押者也可以通过选择运行非 Geth/Prysm 客户端组合来发挥作用。搭建少数客户端的说明须知可以在这个 clientdiversity.org 页面找到:
https://clientdiversity.org/
对于持有量少于 32 ETH 或者不想要承担运行验证者的责任的质押者来说,有一些质押服务提供商可以使用。一些主要的中心化交易所提供 ETH 质押服务,但他们的质押池中的客户端分布情况通常是隐秘的,而且这些交易所提供的 ETH 质押代币的可交易性是有限的。出于这些和其他的原因,不建议使用这些中心化的服务商。
一个更好的选择是使用更去中心化的流动性押注服务提供商,如 Lido 或 Rocketpool。这些服务商提供 ETH 质押服务,同时还提供了一种流动性代币 (比如用户通过 Lido 协议质押 ETH 将获得具有流动性的 stETH 代币),这些流动性代币的价值将随着验证者累积的奖励而增加。这些代币可以进行交易,或者用于赚取 DeFi 收益。这些流动性质押平台的客户端分布情况也要更加透明,比如 Lido 会发布季度更新,而 Rocketpool 现在也发布了他们的季度更新。对于不能或不愿意运行自己的验证器者的用户,这些服务是实现更好的客户端多样性的途径。
总结
信标链的奖罚协议直接激励了客户端多样性。单个客户端占主导地位将是对以太坊的潜在威胁,当单个主导性客户端表现良好时,这种威胁是无形的,但当该客户端出现共识 bug 时,这种威胁可能是灾难性的。拥有多个客户端是以太坊的独特优势,也是开发者社区勤奋努力的证明。然而,当一个客户端控制了大部分 ETH 质押金时,这种 (以太坊开发者社区的) 努力就会被削弱。理想的情况是在至少 4 个客户端上平均分配 ETH 质押金,给每个客户端最多 1/4 的 ETH 质押金。通过使用现在可用的生产就绪的客户端,这是很容易实现的。
撰文:Joseph Cook
编辑:南风
[注:本文部分图片来自互联网!未经授权,不得转载!每天跟着我们读更多的书]
互推传媒文章转载自第三方或本站原创生产,如需转载,请联系版权方授权,如有内容如侵犯了你的权益,请联系我们进行删除!
如若转载,请注明出处:http://www.hfwlcm.com/info/286958.html