隔离见证的代价与风险

作者:Bitcoin Core

来源:https://bitcoincore.org/en/2016/10/28/segwit-costs/

原文出版于 2016 年 10 月 28 日。

引言

本文是早些时候的博文《隔离见证的好处》的补充,为通过 BIP141 激活的隔离见证(segregated witness)方案可能带来的技术代价和风险给出了概要的说明。

目的

出于本文的目的,我们使用 “代价” 一词来表示假如隔离见证部署和激活就一定会发生的负面结果,而 “风险” 则表示可能会发生的负面影响,以及一些并不是所有人都公认为负面的变化。

在分析风险时,我们也考虑可以 规避 风险的措施(也就是尽可能降低风险发生的概率),以及可以 缓解 风险的措施(在风险确实发生时,可以降低其影响)。

本文无意定论隔离见证的好处是否大于其风险、隔离见证是否应该激活;不如说,本文是为了提供背景知识,帮助利益相关方做出充分知情的决定。

序列化代价

交易和区块的信息主要出于下面三个理由而需要序列化:

  1. 在点对点网络中传播;
  2. 存储区块链在硬盘上;以及
  3. 计算区块资源限制。

隔离见证会影响两个方面的序列化:

  • 见证数据的承诺会被包含在 coinbase 交易中,使其体积增加 38 ~ 47 字节,约占区块体积限制的 0.005%(详见 BIP 141 – 承诺的结构
  • 为包含了隔离见证数据的交易使用了新的序列化方法(详见 BIP 141 或者 BIP 144)。为了易于分辨序列化的格式,需要给每笔交易增加 2 字节的开销;为了统计每个输出的见证数据对象,需要给每个输入增加 1 字节的开销。总的来说会给每笔交易增加约 1% 的开销。

在序列化之后,隔离见证数据格式(见 BIP 141 – witness 程序)有下列效果:

  • 对比 P2PKH,P2WPKH 的脚本公钥(scriptPubKey)字段 减少 了 3 个字节(减少了约 1%),而 witness 的字节数跟 P2PKH 脚本签名(scriptSig)的相同。
  • 相比 P2SH,P2WSH 在脚本公钥字段使用了额外的 11 个字节(增加了约 6%),而 witness 的字节数跟 P2SH 脚本签名的相同。
  • 对比 P2PKH,P2WPKH/P2SH 多用了 21 个字节(11 %),因为在脚本公钥字段(对比 P2PKH 脚本公钥)多用了 21 字节,而在脚本签名字段少用了 3 字节; witness 的字节数跟 P2PKH 脚本签名的相同。
  • 对比 P2SH,P2WSH/P2SH 多用了 35 字节(19%),因为(对比 P2SH 脚本公钥)在脚本公钥字段多用了 24 字节,在脚本签名中多用了 11 字节;witness 的字节数跟 P2SH 脚本签名的相同。

上述的比例都基于 180 字节的交易(一个输入和一个输出)计算出来。如果 输入/输出 的数量同比例增加,上述的比例将大体准确;但如果使用了更加复杂的交易脚本(例如多签名),则会下降。

设计哲学

交易体积的开销变化源于两个因素:

  1. 为 P2WSH 使用一个 256 比特的哈希值,而不像 P2SH 那样使用 160 比特的哈希值;以及
  2. 通过 P2SH 来编码,以使不支持隔离见证功能的旧钱包也可以构造出可以使用隔离见证来花费的资金,让接收者可以获得隔离见证的好处。

要是没有这两个因素,开销就可以忽略不计了:P2WPKH 将少用 3 个字节;P2WSH 将多用 1 个字节。

第一个因素背后的动机在《通过 P2SH 提高多签名的安全性》一文中有讨论。

第二个因素是个人用户在公开收款地址时可以权衡的选择。选择 P2WPKH/P2SH 或者 P2WSH/P2SH 将因为开销的上升等比例支付更高的手续费。从长期来看,这会自然限制这种开销的上升会造成的影响。

进一步的削减

可以通过对网络和存储的序列化格式的变更,让大部分的开销消失:完全的序列化格式可以通过使用一个简单的标签(指明用到了什么格式,P2PKH、P2WPKH、P2WPKH/P2SH,等等)以及实际的数据(公钥和签名)来覆盖(举个例子,compacted_txn.txt)。

区块验证开销

隔离见证在验证区块时引入了额外的开销,这既是为了检查 witness 默克尔树,也是为了处理 P2SH 编码的隔离见证交易。每一笔交易需要多用 5 次 SHA256 运算,每个 P2SH 编码的 P2WSH 输入需要多用 1 次 SHA256 运算,每个 P2SH 编码的 P2WPKH 输出需要多用一次 HASH160 操作。不过,这就相当于在最多 4 MB 的数据运行 6 次 SHA256 运算,或者约等于总计 24MB 的 SHA256 哈希值;再换算过来,就是在树莓派 v1 小型电脑上需要为每个区块多付出 15 秒的处理时间,而在功能更强的硬件上,只需不到 1/10 秒。

引入 bug 的风险

隔离见证的补丁包是对比特币的一次重大变更,而且已经在 Bitcoin Core 0.13.0 发布了,只不过还未在比特币主网络上激活。任何这样的重大变更都有多种多样的风险,包括:

  • 彻底的错误:可能在设计或者实现上就有错误,导致意外以及有害的结果。例如:PR#8525
  • 用户误用:对系统的变更可能导致用户感到困惑,导致对系统的误用,然后反过来造成有害的后果。
  • 生态系统相互作用:比特币生态系统的不同部分可能有硬编码的假设,会在升级后得不到保证。举个例子,解析比特币的区块存储的应用需要升级,才能理解新的序列化格式。

规避措施

为了降低隔离见证激活时发生这些风险的概率,我们已经采取了下列步骤:

  • 同行评议:隔离见证中所有的变更,不论是设计还是实现,都已经被公开,并得到了多个独立的专家的评审;他们给出的建议一般都得到了采纳。公开的报告包括:技术评审报告有:
  • 测试:如《隔离见证的下一步》所述,“隔离见证这一对共识规则和 P2P 网络的综合性变更增设、修改了总计 1486 行代码。隔离见证的补丁还在单元测试和完整性测试中增加、改动了总计 3338 行代码,以保证隔离见证技术在每一个完整编译的 Bitcoin Core 软件中如预期般工作。”
  • 测试网络:在开发期间,隔离见证曾被部署到多个测试网络上,让代码可以被诊断、让来自广大生态系统(例如区块浏览器和钱包)的开发者可以保证他们的软件可以跟隔离见证技术正确交互。这些测试网络包括:
    • Elements Project —— 测试隔离见证实现作为一个硬分叉的概念,以及许多其它变更
    • 从 segnet1 到 segnet4 —— 测试隔离见证作为一种软分叉的实现,在 2016 年 1 月至 5 月间测试
    • testnet3 —— 隔离见证于 2016 年 5 月在标准的测试网上激活
  • 替代性实现:隔离见证相关的比特币升级提议已经由 btcd(go 语言的比特币客户端)和 Bcoin(Javascript 语言的比特币客户端)以及多种钱包和代码库实现。独立的重新实现可以帮助找出未得到明确声明的假设,以及设计中的歧义,并避免可能因此产生的 bug。

缓解措施

减轻所有 bug 的影响的一种重要方法就是将隔离见证实现为一种软分叉。这就意味着:

  • 比特币的用户可以直接不使用新引入的特性,直至他们个人确信所有技术都已经被正确实现了,这不会使他们损失任何现有的功能
  • 所有在隔离见证规则下有效的区块在升级前的软件中也会被认为是有效的区块,所以,没有包含隔离见证更新因此没有因为更新而引入新 bug 的旧版本客户端,可以用来验证区块,提供对共识退化(consensus regression)的第二层保证。

除此之外,为 “脚本” 语言设置版本控制的能力,带来了为比特币脚本语言修复 bug 的可能性,既包括对先前存在的 bug,也包括任何潜在的、可能由隔离见证引入的新 bug。

复杂性及技术债相关的风险

技术债” 的意思是,现在使用的权宜之计,可能会在未来导致更多的困难和问题;所以现在多花点时间和力气将被证明反而是更加经济的。

在比特币的语境下,技术债有两种类型:

  • 丑陋的或者说复杂的代码,可以在不影响用户和共识的前提下重构;以及
  • 糟糕的设计决策,其中许多不得不永久维护,不然有些比特币用户就会弄丢手上的币。

规避措施

如上所述,隔离见证的代码已经得到充分的评议,这可以帮助在代码和设计两方面抑制产生技术债。

也如上所述,隔离见证有多个独立的重新实现,这可以帮助在还有回头路的时候发现任何不必要的复杂性和技术债。

为了支持现有的、通过重构和升级比特币代码库来偿还技术债的努力,隔离见证作为一种仅包含代码的升级(code-only update),合并到了为发布 0.13.0 而积累的工作中。

缓解措施

比特币已经饱受许多重大设计债的痛苦,隔离见证是专门设计来减少某些债务的 —— 尤其是交易熔融性(transaction malleability,指交易的 ID 可以不因交易内容的变化而变化,译者注)、签名哈希操作的二次方膨胀问题(quadratic scaling of signature hashing,指交易输入数量的增长会导致签名验证时的哈希运算次数呈平方级增长,译者注),以及签名不覆盖输入值的问题(non-signing of input values)。

隔离见证所提供的脚本版本控制方法提供了一种优雅的方式,让未来的软分叉升级可以进一步减少设计债,包括修复现有操作码(比如 CHECKMULTISIG)中的 bug、重新启用先前被禁用的操作码(例如 CAT),以及切换到更好的验证方法(例如 Schnorr 签名,或者聚合签名)。

一般来说,比特币脚本中的设计债是无法完全偿清的,因为永远不能排除有些未花费的交易支付给了使用 “丑陋” 功能的 P2SH 地址。禁用这些特性将让这些交易变成不可花费的,等同于盗窃用户的财产。脚本的版本控制让这些设计债的 “代价” 可以降低,因为这些 “丑陋” 的功能将只对 “旧版本” 脚本可用,新的开发工作也可以在很大程度上忽略这些旧代码。

软分叉相关的风险

软分叉指的是会使一些以前有效的交易变得无效的共识规则变更。处理不当的软分叉可能在比特币生态系统中产生许多问题,而且,因为隔离见证让额外的见证数据成了建立比特币的分布式共识的关键数据,处理不当的升级可能增加系统出错的方式。主要的故障模式包括:

  1. 让一些比特币的持有者无法再花费自己的钱
  2. 导致旧的节点和升级后的节点对一笔未确认的交易是否有效、有无可能被挖出产生不同的看法
  3. 让矿工错误地挖掘在新规则下无效的区块
  4. 得到了激活以及一些实际用途,然后就无人问津了
  5. 让更大规模的区块链分叉得以出现,因为旧节点无法转发 witness 数据,通过旧节点形成的网络在实质上断连

规避措施

许多软分叉都已经在比特币上激活(包括 BIP 1634656668112 和 113),而且这种经验已经在为激活软分叉而编写的 BIP9 中得到了明文表述。BIP9 所述的流程曾用于部署 CSV 软分叉(BIP 68、112、113),结果是共识规则的快速升级,没有出现故障。

隔离见证的设计和 BIP9 部署流程以下列特性避免了上面提到的问题:

  1. 隔离见证所施加的新限制仅影响当前无人使用的交易,因为:
    • 受影响的交易在当前是非标准的,因此不会被网络中的绝大部分节点转发,大部分矿工也不会去挖掘
    • 受影响的交易在当前会被认为是 “任何人都可以花的”,因此可以立即被任何监控区块链的人拿走,也因此会被认为是 “弄丢了”
  2. 旧的节点会认为花费隔离见证输出的交易是非标准的,因为明显违反了 BIP62 的 CLEANSTACK 规则,因此不会被纳入旧节点的交易池中。类似地,带有 P2WPKH 或 P2WSH 输出的交易也会因为出现了一种新的输出类型而被认为是非标准的(但使用 P2SH 封装的 P2WPKH/P2WSH 不会)。所以,你无法通过向旧节点转发一笔交易、同时向新节点转发另一笔交易来重复花费同一个隔离见证输出。但是,这种差异依然会被用在重复花费的策划中,例如,在一笔交易中放置一个非隔离见证的输出和一个隔离见证的输出(那么这笔交易就只会被升级后的交易转发),然后尝试发起手续费更高的重复花费交易并只使用非隔离见证的输出,后一笔交易有可能可以通过旧节点成功转发。这些担忧只影响交易池中的未确认交易;一旦交易被某个区块确认,重复花费就是不可能的了。只要检测工具可以跟踪隔离见证的花费行为,现有的检测重复花费的方法就依然是有效的。
  3. 保证矿工只挖掘有效区块显然是每一个参与者的最高优先级,而在隔离见证上人么也投入了大量的工作来保证这一点。这里面既有直接的工作,例如 BIP145;也有间接的工作,例如 “致密区块(BIP152)”。
  4. 如果隔离见证软分叉在激活之后又回滚,发起过隔离见证交易的人就有可能丢钱 —— 举个例子,一个恶意的矿工可以在没有启用隔离见证的链上重播(replay)这笔交易,而在这时候,这笔交易是任何人都可以花费的,然后矿工就可以自己花掉它(偷走它)。有两种可能,隔离见证会在软分叉激活后又回滚、启用了隔离见证的交易会被偷盗:
    • 矿工可以放弃启用了隔离见证的链,在隔离见证未激活的位置开始挖掘分叉链。基于 BIP9 的激活规则,这需要放弃超过 2016 个区块(就是一个锁定期的长度,此外还要再加上足够多的区块,以避免到达 95% 支持率阈值)。这需要矿工集体放弃超过 25200 BTC 的区块奖励,按当前的价格就是超过 1500 万美元。
    • 矿工可以直接使用不理解隔离见证规则的软件(比如老版本的 Bitcoin Core),在已经激活隔离见证的链上挖掘区块。从理解隔离见证的软件的角度看,这是一种硬分叉,因此挖掘出来的区块会被使用可感知隔离见证的验证节点无视。只要有足够多的用户使用隔离见证节点,这样的硬分叉就无异于启动一种新的另类币。
    因此,无论哪一种可能,都不太可能。
  5. 人们已经投入了大量的工作来保证启用了隔离见证的对等节点会形成一个充分互联的比特币 P2P 网络,包括为启用隔离见证的节点使用一个专门的服务信号,并优先连接到到这样的节点。

与更大的区块相关的风险

隔离见证将 1MB 的区块体积限制变成了 400 万单位的 “重量(weight)” 限制;在统计重量时,序列化的 witness 数据(的 1 字节)会被统计为一个单位,而核心的区块数据(的 1 字节)会被统计为 4 个单位。随着使用隔离见证交易数量的增加,这一变更将允许单个区块包含更多的数据(如果区块内所有的交易都使用隔离见证特性,则预计每个区块会是 2MB 大小,但是,在最恶劣的情况下,单区块可能达到 4MB)。只要允许单区块放入更多的交易,可以预期 UTXO 数据库的增长速度也会变得更快(假设所有的交易都使用隔离见证特性,则增长率会变为大约两倍;但是,因为隔离见证是一种软分叉,在最恶劣的情形下,UTXO 集的增长率不会改变)(译者注:这里的意思可能是,如果无人采用隔离见证,UTXO 集的增长率就不会改变)。

这些结果可能具有积极意义(例如,更多的交易量,意味着可以容纳更多用户),但同样可能有重大的负面效果:

  • 更大的区块可能导致更慢的区块传播速度,进而导致矿工的孤块率升高 —— 反过来会导致安全性降低(掌控整个网络所需的哈希率变少),或者更深程度的中心化(更大体量的矿工更能减少孤儿块率)。
  • 更大的区块将提高全节点的运行门槛,可能导致用户关闭自己的节点,这也会导致更深的中心化。
  • 更大的 UTXO 集将提高挖矿的门槛,可能使共享验证资源的矿工比例上升,导致更深的中心化。

规避措施

更大区块的负面影响因此下列因素而得到了限制:

  • 得益于 libsecp256k1 库的部署,区块的验证时间已经大幅减少。
  • BIP152(致密区块)的部署,帮助限制了更大的区块的区块传播时间上的影响,因此也限制了对网络的孤儿块率和全节点的带宽使用量的影响。
  • 隔离见证的签名改变了签名哈希算法,避免了平方级膨胀问题,因此大幅减少了某些大体积交易的验证开销。

UTXO 集膨胀速度的恶化由下列因素得到限制:

  • 隔离见证的部署是一种软分叉,保证了在最恶劣的情况下,UTXO 的增长不会进一步恶化。
  • witness 数据在重量计算中的折扣,重新平衡了一个 UTXO 在生命周期中的开销,降低了为交易增设一个花费隔离见证输出的输入的代价,因此(相对来说)提高了增设一个输出(产生一个新的 UTXO)的代价,将 创建/花费 UTXO 的开销比例从大约 1:4.5 变成了 1:2 。一方面反激励 UTXO 的生成,一方面激励 UTXO 的花费,这样做也许能稍微改变使 UTXO 集膨胀的激励机制。

缓解措施

  • 因为单区块可以容纳的数据量依然有上限,而且不会超过当前的四倍,应该还是能够在相对直接的工程范围内开发缓解措施。进一步来说,因为预期每个区块的实际数据量只有当前水平的两倍,所以缓解措施的必要强度可以进一步放松。
  • 有一些正在开展中的工作可以优化交易和区块在硬盘和网络中的序列化性能,这可以进一步降低运行全节点的存储和带宽要求。

与低手续费相关的风险

比特币区块链的安全性是由哈希算力(hashpower)来提供的,而哈希算力又是奔着固定的区块奖励和浮动的交易手续费而来的。因此,手续费收入的下降有可能使挖掘比特币区块链的算力减少,从而降低比特币区块链的安全性。

因为单体笔交易的手续费是由市场压力(供给和需求)决定的,隔离见证引入的变化可能会提高供给量从而降低价格(假设需求不变,要么因为隔离见证的部署而发生,要么至少会跟隔离见证的部署同步发生),而降低单体交易的价格(手续费水平)又有可能导致整体挖矿收益下降(如果这时候的需求价格弹性恰好处在没有弹性的阶段的话)。

此外,隔离见证带来的变更,可能会让 “layer 2” 解决方案(比如闪电网络)变得更加吸引人。如果这导致用户将 layer 2 解决方案视作链上交易的替代品,那会显著降低对链上交易的需求、对交易的手续费水平产生额外的下行压力。

规避措施

当前的手续费水平大致是每个区块 0.5 BTC,同时固定的区块收入是 12.5 BTC,大约占矿工收入的 4%,所以对矿工收入(和网络安全性)的潜在影响从短期来看是不大的。

此外,在过去 12 个月里,以 BTC 计量的手续费一直在上涨(从每个区块 0.2 BTC 涨到现在的水平),而且按实际价值计也是如此(一年前 1 BTC 的价格是 300 美元,现在是 600 美元),所以,手续费水平的下降可能只是等同于回到了 12 个月以前的手续费水平,这应该不会产生很大的影响。

缓解措施

矿工可以单方面或者集体限制供给量,既可以单方面为自己挖掘的区块设置最大重量的软限制(就是 “blockmaxweight” 参数,默认是 300 万),也可以集体使用一个软分叉、通过孤立超出特定重量的区块而在事实上降低限制。这种方法也许可以防止任何因为供给量增加而产生的价格下降(实质上,就是通过减少供给量来提高单体交易的手续费,只不过总收益未必会提高),但无法防止因为替代效应(例如采用 layer 2 网络)而导致的手续费收入下降。

虽然 layer 2 网络可能是链上交易的一种替代,但它们无法完全不使用链上交易。而且,启用隔离见证之后,在某些场景下,即使是相对更少的链上交易,也很容易占满链上的吞吐量。即使这些网络的价值只有一小部分可以通过链上交易的手续费捕捉到,那也有可能大大超出当前的手续费价值。

长期扩容相关的风险

如上所述,所有交易全部采用隔离见证特性,将使链上吞吐量翻倍。这给吞吐量带来了显著的一次性提高,无论从短期还是从中期来看都是如此,只不过取决于采用速度而已。此外,通过加入一些特性来支持 layer 2 网络,中期和长期的额外扩容效果也可部分实现。因为修复了 sighash 的平方级膨胀 bug,隔离见证也降低了进一步提高吞吐量的负面影响。

但是,除了一次性的翻倍效果之外,隔离见证并没有提供任何直接的机制来进一步扩大链上交易吞吐量。

这就带来了长期扩容可能被阻止或者推迟的风险:利益相关者可能认为隔离见证已经 “够了”,并且拒绝开发和支持进一步的扩容努力。

规避措施

目前,避免这种风险的工作有:

此外,让隔离见证可以实现吞吐量提升的工作(例如 libsecp256k1 和致密区块)显然也会让进一步的扩容更容易实现。

缓解措施

无论在哪个技术层面上,隔离见证都不会让进一步的扩容变得更加困难 —— 这里的风险完全是社会层面的。因此,最有效的缓解措施可能自然也是社会层面的:例如让支持长期扩容的公司提供开发资源、助力其实现。

隔离见证让交易的吞吐量可以提高到当前的两倍,也为扩容的实际影响 —— 例如节点的性能、去中心化、交易需求,以及生态系统升级的速度 —— 提供了验证的机会。这些数据可以合理地收集并用于支持未来的扩容措施,不论是证明某些令人担心的结果比预想的可能性要低,还是证实了某些担心是有效的,未来的工作都可以更加有的放矢。

其它方法

这一部分为能够部分或者全部实现隔离见证的好处的其它方法提供了简要的比较,并说明了何以这些方法可能会改变相关的代价和风险。

硬分叉的隔离见证

隔离见证的任何硬分叉实现都会增加巨大的代价和风险,因为所有节点都必须在激活之前升级到理解新的规则,这就增加了导致链分裂成 “旧比特币” 和 “新比特币” 的风险,并导致困惑和价值损失。也因为比特币社区缺乏硬分叉的经验,意外的风险和代价也有可能发生,只不过它们在本性上就难以分析。

硬分叉的隔离见证可以通过两种方法来实现:

  1. SPV 不可见的:如果 witness 的承诺从 coinbase 移到了区块交易的默克尔树中,大部分不参与验证的节点和钱包都可以继续工作,无需升级。这会给 coinbase 交易节约 38 ~ 47 字节,但无法提供别的好处。
  2. SPV 可见的:如果交易哈希的计算改成排除签名脚本,这可能会允许更简单的实现,并降低交易单体的开销;但是,这会让所有的比特币软件都必须升级才能处理这样的交易。此外,管理旧类型交易的专门代码路径将需要持续维护,因此会提高代码复杂性和出错的概率。BIP 134(灵活的交易格式)就是一种另类方法,可以通过一次 SPV 可见的硬分叉获得隔离见证的部分好处。

无论哪一种方法,硬分叉都可以同时大幅改变共识对区块体积的限制。

简化的隔离见证

从逻辑上来说,隔离见证的大部分好处都可以分离为相互独立的变更,并分别评估和部署。但是,许多特性的实现要求是紧密相关的:

  • sighash 操作的线性增长:需要替换 CHECKSIG 和 CHECKMULTISIG 操作码。
  • 输入值的签名:需要替换 CHECKSIG 和 CHECKMULTISIG 操作码。
  • 通过 P2SH 提高多签名的安全性:需要改变 P2SH 支付格式。
  • 脚本的版本控制:需要改变 P2SH 支付格式。

逐项修复这些问题会提高比特币代码库的复杂性,因为需要处理在不同时间激活的不同特性;而同时部署它们则可以消除这种复杂性。

因为当前的 CHEKCSIG 和 CHECKMULTISIG 操作码存在 sighash 操作的平方级增长问题,所以提高吞吐量是危险的,而且必须有针对这些操作的限制。因为隔离见证只允许通过升级后的操作码使用优化后的签名操作,旧的操作码将保持天然的限制。所以,如果吞吐量增加是专门部署的,那就需要实现额外的限制来保证这种增加是安全地,可能也会给挖矿和手续费估计增加复杂性。

(完)

https://www.btcstudy.org/2022/10/04/segregated-witness-costs-and-risks/

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇