区块链端对端交易性能分析

2023-01-09 08:57:29

区块链端到端交易性能分析

区块链从微观上来说就是一个不可篡改的可溯源系统,从宏观上来说具有三个特点:共识机制(这个被很多人所研究,包括改进,例如POW、POS、BPFT等等)、分布式存储(每个节点对于链信息的存储,也是个比较有意思的方向,例如RS编码)、P2P。对于区块链端对端交易性能的分析,我想从P2P网络讲起,交易的基础都是基于搭建的网络进行的,在网络上信息传输的延迟对于性能的影响是巨大的。然后对共识机制的改进就没有做过多的涉及,因为这一部分比较常见。当然后面讲到的像fabric、分片都是比较基础的讲到,如果每一部分要细讲的话,感觉篇幅会较长,所以也就没有再深入写下去。

1、P2P网络模型(路由查询分类模型)

P2P网络不同于传统的客户端\服务端的C\S结构,在P2P的网络结构中,每一个节点都是一个客户端以及服务端的存在,同时它们就不再适用HTTP,而是采用Socket进行网络编程。

在P2P网络模型分类中一般有:集中式、纯分布式、混合式以及结构化四种模型,不过在这里需要注意的是这些分了模型是路由查询模型,也就是不同节点之间怎么建立连接,而至于它们连接之后的交易内容就不是分类模型关注的问题了。

**集中式:**对于第一种模型集中式,就是存在一个中心节点保存网络中每一个节点的索引信息,一般这样的索引信息包括IP地址、端口、节点资源等等,也就是说一个节点存储所有节点的路由信息,当普通节点要访问其他节点时,都是通过这个中心节点来得到信息,这样做的缺点就是节点规模扩大后,出现性能瓶颈,也存在单点故障。

**纯分布式:**第二种模型就是纯分布式,也就是说网络中没有中心节点,节点之间都是随机建立的拓扑网络,如果有一个新节点要加入网络中,最简单的就是随机选择一个存在的节点建立邻居关系,例如在比特币网络中,就是使用DNS的方式查询节点,DNS一般使用硬编码到代码中,它可以提供比特币节点的IP地址列表,从而新节点要找到其他节点就可以通过DNS服务器查询建立连接。但是新节点加入网络后要进行全网广播,也就是泛洪机制。纯分布式的模型没有单点性能瓶颈问题,但是因为泛洪机制,因此容易出现泛洪循环,同时也会出现消息风暴,也就是例如节点要求的资源有很多个节点拥有,那么大量这些节点同时发送给这个节点导致消息请求的节点瘫痪。

**混合式:**混合式就是集合了集中式和分布式结构,网络中存在多个超级节点组成分布式网络,而每个超级节点拥有自己的集中式网络,也就是它连着自己管理的多个普通节点。如果有一个节点要加入,那么它首先与一个超级节点通信,得到其他超级节点的列表,然后选择要加入哪个超级节点的网络,这样就把泛洪广播限制在超级节点之间,避免大规模泛洪循环,比特币网络也是类似这种架构。

**结构化:**相比于纯分布式网络的随机网络,结构化分布式网络就是让所有节点都按照某种结构进行有序组织,例如一个环状网络,基本它们的实现都是根据DHT思想:在网络中,可以抽象出来两种空间:资源空间、节点空间,资源空间是代表了所有节点保存的资源集合,节点空间就是所有节点的集合,首先我们对资源和节点都进行编号,,例如把资源名称或者它的内容取一个Hash变成一个数值ID,这样就可以对资源ID和节点ID进行一个映射关系,例如把资源n的索引信息放到节点n上,搜索的时候就是按照这个映射关系进行查找,避免了泛洪广播,这种模型的有点是更加的快捷以及准确,但是事实上映射中是很难一一对应的,尽管如此还是可以通过一定的大小关系进行映射,和就是DHT思想。

2、比特币网络

对于比特币的网络系统中,节点的主要功能是:钱包、挖矿、区块链数据库、网络路由;不同类型的节点具有不同的部分功能,但是每一个节点都有路由功能,一般只有比特币核心才包含了四大功能。所有节点都会参与校验以及广播交易以及区块的信息,同时会发现并且维持其他节点的连接,而那些包含了完整的区块链数据库的就称为全节点,而相比之下,只包含了区块头而没有交易数据的节点被称为轻节点,例如钱包。还有一部分的节点是独立矿工节点,这里强调独立矿工是为了与矿池,也就是所谓的集体挖矿区分开来,独立矿工节点则是全节点包含了挖矿功能的节点,至于矿池矿工节点,它们是分布在一个局部的集中式矿池网络,中心节点式一个矿池挖服务器,其他节点连接到这个服务器,它们之间依据的式矿池挖矿协议,也就是中心节点作为一个全节点与它的下属节点形成一个网络与主网按照比特币协议进行通信。

所以综上所述,在整个比特币网络中,除了那些节点使用比特币协议进行通信外,还包含了矿池里面的矿池协议,此外因为挖矿创建出新的区块后,需要广播到全网节点,如果区块使用上面所述的比特币协议网络,有很高的网络延迟,所以需要一个专门的传播网络来加快区块在矿工之间的同步传播,这个网络叫做比特币传播网络或者比特币中继网络。**比特币传播网络:**为了最小化矿工之间的传输延迟,原始的比特币传播网络由几个专门的组成,并且连接大多数的矿工和矿池,也就是类似于混合式的网络模型,降低了同步延迟。

**节点间:**下面比较具体的介绍节点之间的连接,对于一个新的节点的加入,首先会发现至少一个网络中存在的节点进行连接,并且记住最近成功连接的网络节点,当重新启动后,会快速与这个节点连接,如果失去了连接会尝试发现新的节点,建立连接后节点会将自己的IP地址发送给相邻节点,这些节点又进行广播,保证信息被多个节点知道,当然这个节点也可以请求相邻节点把他们知道的其他节点的IP发送给它自己,同时客户端会维护一个长期稳定运行的节点提供连接,和BT下载类似。细节如下:比特币核心部分维护一个节点列表,当一个节点第一次启动时,会被自举到网络,通过DNS获取可连接IP连接到网络,然后如果要进行块传播,节点之间会互相发送最新区块哈希值的消息,如果某个节点坚信自己有更长链,它会发送inv信息,包含至多500个最新块的哈希值来证明更长,收到的节点进行验证确认。

**交易池:**具体到交易方面,节点之间的交易通过inv消息来实现,如果收到了getdata信息,那么交易通过发送tx实现,节点收到有效的交易的信息后会通过类似的方式将其扩散,如果交易的信息在一段时间内没有被放进块中,那么交易将被从内存池中清除,而原节点将重新发送交易信息。比特币网络中几乎每个节点都会维护一份未确认交易的临时列表,这就是内存池或交易池,节点们利用这个池来记录被网络知道但是没有被区块包含的交易,例如,保存用户钱包的节点会利用这个交易池来记录那些网络已经接收但还未被确认的、属于该用户钱包的预支付信息。随着交易被接收和验证,它们被添加到交易池并通知到相邻节点处,从而传播到网络中。有些节点的实现还维护一个单独的孤立交易池。如果一个交易的输入与某未知的交易有关,如与缺失的父交易相关,该 孤立交易就会被暂时储存在孤立交易池中直到父交易的信息到达,当一个交易被添加到交易池中,会同时检查孤立交易池,看是否有某个孤立交易引用了此交易的输出(子交易)。任何匹配的孤立交易会被进行验证。如果验证有效,它们会从孤立交易池中删除,并添加到交易池中,使以其父交易开始的链变得完整。对新加入交易池的交易来说,它不再是孤立交易。前述过程重复递归寻找进一步的后代,直至所有的后代都被找到。通过这一过程,一个父交易的到达把整条链中的孤立交易和它们的父级交易重新结合在一起,从而触发了整 条独立交易链进行级联重构。交易池和孤立交易池(如有实施)都是存储在本地内存中,并不是存储在永久性存储设备(如硬盘)里。更准确的说, 它们是随网络传入的消息动态填充的。节点启动时,两个池都是空闲的;随着网络中新交易不断被接收,两个池逐渐被填充。

有些比特币客户端的实现还维护一个UTXO数据库,也称UTXO池,是区块链中所有未支付交易输出的集合。“UTXO 池”的名字听上去与交易池相似,但它代表了不同的数据集。UTXO池不同于交易池和孤立交易池的地方在于,它在初始 化时不为空,而是包含了数以百万计的未支付交易输出条目,有些条目的历史甚至可以追溯至2009年。UTXO池可能会被安置在本地内存,或者作为一个包含索引的数据库表安置在永久性存储设备中。交易池和孤立交易池代表的是单个节点的本地视角。取决于节点的启动时间或重启时间,不同节点的两池内容可能有很 大差别。相反地,UTXO池代表的是网络的突显共识,因此,不同节点间UTXO池的内容差别不大。此外,交易池和孤立交易池只包含未确认交易,而UTXO池之只包含已确认交易。

3、对于比特币网络交易以及块传播的论文记录:

Information Propagation in the Bitcoin Network

在这篇文章里面主要分析了区块以及交易信息在比特币网络中的传输性能,同时提出了可能存在的优化方案。正如前面我们所说的,节点发布的区块信息或者交易信息是通过发出inv信息来实现的,这个信息包含了自己最新块或者交易的哈希值,接受到的节点通过发送getdata信号来获取自己所需要的那部分区块或者交易,基于上面的这个流程,在广播中的每一跳,消息都会产生传播延迟,传播延迟是传输时间和块或事务的局部验证的结合,传输时间包括以inv消息、来自接收方的请求和信息交付。虽然inv和getdata消息的大小相对较小(多数情况下为61b,如果即时广播只包含正在宣布的单个块或事务),但文章中提到的块消息可能非常大–高达500 kb。而验证部分是指在向节点的邻居宣布该块之前,将对其进行验证,块的验证包括对块中每个事务的验证,事务验证反过来又需要对磁盘的随机访问。

性能特点:

**传输延迟时间分布:**文章中提到网络中节点接受信息的模型呈现两个阶段:首先是初始指数增长阶段,其中接收inv消息的大多数节点将请求相应的数据项,因为它们还没有数据;之后是指数收缩阶段,在该阶段中,接收通知的大多数节点已经具有相应的数据项。在实验中,他们测试得到的传输延迟性能是:节点收到块的中值时间为6.5秒,而平均值为12.6秒。分布的长尾意味着即使在40秒之后,仍有5%的节点尚未接收到块。(如图一)

在这里插入图片描述

**区块影响:**同时文章对于传输延迟与区块大小的关系进行了讨论,(如图二),在这里的讨论使用了一个指标–每千字节的延迟时间,在统计中发现,大于20KB的区块的每千字节延迟基本不变,而对于小区块而言,因为他们的传输块压力很小,但是需要同样进行inv信息、请求信息等流程,所以每千字节延迟显得很大。

在这里插入图片描述

**分叉:**文章还通过建模证明了分叉是由较长的传播时间引起的。

优化传播性能:

文章提出的加快传播性能的措施主要是三点:减小验证时间、流水线块传播、增加连通性。

**减小验证时间:**对于验证时间,一般分为困难检查以及事物验证,困难检查包括通过所接收的块并将其哈希与当前目标难度进行比较来验证工作证明,此外,它检查该块不是最近块的副本,并将最近的块引用为其前身,以验证该块不是旧块的重新提交。大部分的验证是在事务验证中完成的,事务验证检查块中每个事务的有效性。一旦检查了困难情况,并且在必须对事务进行验证之前,可以将该块转发给邻居。因此,改进的方案就是一旦完成困难检查,节点就可以更改为发送inv消息,而不是等待相当长的事务验证时间。

流水线块传播则是再困难检查之前就进行inv信息的传播。而最有影响的问题是事务或块的起源与节点之间的距离,也就是增加连通性,为了最小化两个节点之间的距离,文章创建一个用作中心通信的星型子图,从而加快inv消息、块和事务的传播速度。

4、比特币网络与容量及改进

根据TradeBlock的数据参考,只要节点连接到的其他节点达到3000个以上,它能赢得孤块竞赛的概率将高到90%,也就是在孤块竞赛中获胜的区块通常是第一个被广播到网络中的那一个,这也证实了传输延迟对于分叉的影响,同时区块的大小也很大程度上影响了传输时间,这也从数据可以看出,参与孤块竞赛的区块大小平均要比非孤块竞赛的区块大20%(约100kb),这可能由于大区块需要广播的时间更长,这也是区块扩容的争论之一,所以如果要扩容可能孤块的概率会更高,因此矿工会选择打包更少的交易,因此需要更好的改善,例如挖矿骨干网、交易缓存更新及可逆布卢姆查找表。

可逆布卢姆查找表

可逆布卢姆查找表:更大的区块,允许比特币网络可以承载更多的交易,但也会带来问题,它需要更多的时间来传播交易,这将有利于大矿工和矿池,同时增加的数据传递对于用户运行全节点而言,也是一种打击。为了增加比特币网络的效率,并减少更大区块会产生的风险,就出现了可逆式布鲁姆查找表,简称为IBLT。后面会提到的闪电网络就是根据这个思想进行设计的。

可逆式布鲁姆查找表解决的是一个冗余的问题:在比特币交易中,都是通过节点到节点来完成对等式网络的交易,然后通过个人节点的内存池进行存储。当一位矿工发现一个区块时,它包括区块中的交易,随后在同一对等网络中广播该区块,这意味着,区块中所有的交易,都有效地在网络上发送了两次:一次作为一笔交易,另一次则作为区块的一部分。更通俗地说法就是:在区块中已经有了冗余,大多数节点已知道该区块包含的一些内容了,因为他们已经看到过了,如果我们能够优化它,那我们就可以加快区块的广播速度,这也降低了中心化的压力,因为矿工们可以更快地将他们的区块弄出来,同时网络也可以更好地运行。

它的基本原理: 首先,在一个区块中包含的所有交易,都会写入一个表(table)中,每一笔交易会始于表上每一个不同的点,然而,存在的交易数远多于表的空间(room),所以它会导致重叠结果,这使得IBLT显得非常地密集。当然还有一点,对于那些无法访问任何交易数据的人而言,IBLT是无法读取的,也是无法破译的;而那些拥有交易数据的人,可通过使用类似的逻辑,将他自己的交易填充到一个IBLT,然后比较IBLT上的重叠交易数据。如果两个IBLT最终看起来完全一样,这意味着所有的交易,是完全匹配的,即使这两个IBLT,最终看起来并不是完全相同,但只要交易集是非常相似的,这可能仍然是有用的。这种情况下,这两个IBLT可以进行比较,用这种方式,所有相同的交易就可以抵消掉一方。而IBLT中“剩余的”交易,往往可以用于重构丢失的交易。 因此没必要在对等式网络上广播完整的区块,节点可以广播更小的IBLT。这需要的数据也就更少了,速度也就更快了。

闪电网络:

比特币交易网络性能只能是每秒7笔的交易速度,远远不能满足金融交易系统,同时要等待6个块的确认,也就是1小时的时间,因此为了提高网络性能,有了闪电网络,也就是把大量的交易放到比特币区块链之外进行。闪电网络使用智能合约来完善交易性能,主要用到的两个概念是RSMC和HTLC;

RSMC就是可撤销的顺序成熟度合同,类似于准备金机制,先假定交易双方之间存在一个“微支付通道”(资金池)。双方都预存一部分资金到“微支付通道”里,之后每次交易,就对交易后的资金分配方案共同进行确认,同时签字作废旧的版本。当需要提现时,将最终交易结果写到区块链网络中,被最终确认。可以看到,只有在提现时候才需要通过区块链。任何一个版本的方案都需要经过双方的签名认证才合法。任何一方在任何时候都可以提出提现,提现需要提供一个双方都签名过的资金分配方案(意味着肯定是某次交易后的结果)。在一定时间内,如果另外一方提出证明表明这个方案其实之前被作废了(非最新的交易结果),则资金罚没给质疑成功方。这就确保了没人会拿一个旧的交易结果来提现。另外,即使双方都确认了某次提现,首先提出提现一方的资金到账时间要晚于对方,这就鼓励大家尽量都在链外完成交易。

HTLC:微支付通道是通过 Hashed Timelock Contract 来实现的,也就是“哈希的带时钟的合约”。这个其实就是限时转账。理解起来其实也很简单,通过智能合约,双方约定转账方先冻结一笔钱,并提供一个哈希值,如果在一定时间内有人能提出一个字符串,使得它哈希后的值跟已知值匹配(实际上意味着转账方授权了接收方来提现),则这笔钱转给接收方。不太恰当的例子,约定一定时间内,有人知道了某个暗语(可以生成匹配的哈希值),就可以拿到这个指定的资金。推广一步,甲想转账给丙,丙先发给甲一个哈希值。甲可以先跟乙签订一个合同,如果你在一定时间内能告诉我一个暗语,我就给你多少钱。乙于是跑去跟丙签订一个合同,如果你告诉我那个暗语,我就给你多少钱。丙于是告诉乙暗语,拿到乙的钱,乙又从甲拿到钱。最终达到结果是甲转账给丙。这样甲和丙之间似乎构成了一条完整的虚拟的“支付通道”。

通俗一点地讲,基于上面的支付通道与合约实现,我们在区块链上增加了另外的一层,使得用户在额外的这一层上创建支付渠道,交易几乎是即时的,费用极低,而不是每一笔交易都需要记录在区块链上,只有最后的提现涉及的交易才会记录上链。

整体来说,闪电网络的优点就是交易速度可以与visa、Paypal相当了,同时交易的费用也是很低的,当然因为建立在支付通道的交易没有写到链上,所以微支付是无法追踪的,是安全而匿名的。当然也有缺点,那就是微支付渠道建立的复杂性,还有通道交易数量的上限,当然还有路由集中,违背去中心化的问题。

区块链交易缓冲与加速方法(一个专利):

基于区块链的交易缓冲、加速方法与处理系统

这个专利讲的是:当用户通过区块链网络层的一个节点在应用层发起一个带有交易参数的交易请求时,区块链上的智能合约对该请求的交易参数进行参数合法性的校验,当参数合法性校验完成后,智能合约将交易请求发送给交易缓冲\加速子系统进行交易处理,再通过异步方式写入区块链存储层中的存储区块,这个步骤具体是:定时将所有待入链的交易处理结果按照生成时间的先后顺序进行排序,当所有待入链的交易处理结果数量小于或者等于第一阈值时,按照顺序,将待入链存储的交易结果写入存储层中的存储区块,当交易数量大于第一阈值时,将排序在前面的第一阈值数量的交易处理并写进区块,而剩余的交易进行缓存,以此来提高区块链的TPS,并且对需要入链存储的交易异步入链,实现平稳性。

5、区块链的交易性能分析:

ripple:号称转账神器,1500tps;eth:15.6;使用DAG的iota:1000tps而且节点越多,交易越多,tps反而越大;btc:5.68tps;总的来说,限制了tps的因素很多,包括共识算法、广播和验证时间、交易确认等等,现在也有很多试图解决这个问题的方案,比如说fabric可以达到数千的tps,而比特币和以以太坊的off-chain方案理论上支持无限的tps;按照VB的一个理论,这些东西都可以用CAP理论来解释:

“比如说:联盟链通过准入机制,控制了验证节点的数量,通过牺牲Decentralization提升了Scalability;石墨烯系列的DPOS,RippleNet的共识也是同理;比特币通过提高每个区块的容量,也可以达到扩容的目的,但结果是对矿机提出了更高的要求,形成自然的准入门槛,实际上也是牺牲了Decentralization;比特币和以太坊挖矿难度都可以调整,降低挖矿难度实际上也可以提升Scalability,但付出的代价是抗攻击能力下降了,牺牲的是Security。”

比较不同的是off-chain,这个方案对于CAP无效,但是它的缺点上面我也讲过,就是闪电网络的缺点,这里再扩展:1、闪电网络中锁定的比特币只能用在闪电网络中,只有交易通道关闭的时候才能真正成为链上承认的货币,这在理论上会出现类似银行挤兑的情况。如果大家对闪电网络失去信心,集中关闭通道,会拖垮比特币网络。但这个似乎也不是很大的问题,只要闪电网络没有爆出什么漏洞,比如说签名算法被攻破之类的。2、交易是在链外执行,链上无法验证提交的交易是否最新版本,虽然脚本保证了提交旧版本交易的攻击者有被罚没准备金的风险,但前提是要防御者监控网络并提交更新版本交易的证据。也就是说从原来比特币的被动防御(私钥不丢失就能保证资金安全)转变成主动防御。从这个角度看也算是降低了Security吧。这个主动防御的操作交给用户也不太现实,最终必然会衍生出一些服务公司,代替用户保存链外交易凭证,并防止作弊。某种意义上面又从“去中介化的信任”转变为需要信任中介了。这个角度看,似乎也是牺牲了Decentralization。3、闪电网络中只有保存最终的资金状态保存,中间的交易细节全部被忽略,支持者认为是保护了用户的隐私,反对者认为是损失了交易数据。4、因为通道需要准备金维持,不可能任意两个用户间都存在交易通道,用户之间转账可以通过中转的方法,最终很可能会有大资金形成中心化的中转节点。

总的来看,解决交易性能的尝试方案很多,主要有:分片、子链和侧链、链下扩容、DPOS等不同共识机制。

提高tps的几种已有方法以及分析:

1、以太坊的二次性分片技术

对于二次分片技术的理解大概就是将原先一本固定A4账本记录交易数据的方式打破,产生多本A4账本,其中有多本子账本及一本主账本,子账本作为记录验证交易数据为主,多本账本可以同时进行并行记账,互不影响,主账本一般只有一本,主要用做分配记录各个子账本的是谁在记录的,子账本们的分布位置以便于后期查找,子账本记录的奖励及惩罚是什么,因为有可能存在恶意记错的账本。这时候设立子账本越多,代表每秒可同时记录的交易数据就越多,的确理论上可以达到百万级别的吞吐量,较比只有一本账本的比特币,以太坊的重心已经慢慢由记录完整账本过渡到如何让记录账本的人尽可能的协同合作记账,让记录数据速度更快。分片主要要解决的问题是跨片交易,包括普通的跨片转账和跨片合约,另一个问题就是动态分片,根据网络总体节点的数量,业务量和安全性等级要求的变化动态增减分片数。

但是分片也有一定问题:它是提高公链性能的一把双刃剑。在网络规模一定时,分片越多,则分配给单个分片的节点也会越少,抗攻击能力也会相应用减弱,这样整个网络的安全性也会随之线性衰减。因此,在去中心化思想主导的区块链世界里,单纯强调分片数量或性能均不具备太大意义,效率与安全的最优协调才能促进区块链生态的良性发展。

2、 EOS采用BFT-DPoS机制技术

EOS采用的股份授权证明(BFT-DPoS)机制的石墨烯技术,选出可信任的记账人进行记账,单条链可以做到每秒1万至10万笔交易,在通过并行链记账的方式,理论上可以达到百万级的TPS。对比比特币的记账方式pow算力竞争模式,演变成大矿池之间的竞争,其他小型的基本没有太大得到记账的机会,鉴于此干脆放弃算力堆积模式,改用投票方式,投出记账人(超级节点),不需要在像比特币一样算出特定解去竞选记账人的权利,由此省出了不少时间,然后在引入BFT协议,也就是记账人在生产区块的同时马上对该区块签名确认,并让别的记账人也过来签名确认,并行验证交易数据将不可逆区块确认的时间缩短,但这种确认的时间官方给出的数据是1秒内完成,加上EOS生产块的时间是0.5秒,所以大概是3秒内完成不可逆区块的确认。在EOS系统上,发现其最大化的去除了随机的成份,如当节点的规则,连续生产区块的更换的规则,改用固定的规则加速记账的进行,就好比用了固定的记账人,固定的奖励方式,记账方式,去除交易费用,将精力全部用在记账上。

EOS比较多的诟病是中心化已经太明显了。

3、 DAG有向无环图

最知名的DAG有三架马车 ----IOTA、字节雪球、Nano以及最近的xdag,早期的如IOTA将记账人去除,只需要验证前俩个有效单元即可,去除块的概念,也就是不需要记账页的概念了,是一张无限大的纸,任何人随时都可以在上面任何一处记录交易数据,并且交易的人就是记账的人(交易的人需要运行交易钱包软件等待交易完成),这种方式不需要费用,而且随着使用的人越多,其验证速度就越快,tps也可以达到1000以上级别。

交易性能:

影响到交易性能的一个因素很主要是共识机制,例如EOS的签名机制直接让自己的出块速度缩减到0.5秒,所以通过对于POW、POS、DPOS、PBFT等等共识机制的研究与改进是解决性能瓶颈的一种方法;然后还有一种是p2p的通信协议,例如fabric利用gRPC库与Gossip消息协议构建p2p通信机制,以太坊使用基于RLP编码以及认证的加密P2P协议,这些都是是适应与它们应用场景的网络机制的设计。最后就是很多机制的改进,例如分片、消息机制等等。

  • 作者:Beta_King
  • 原文链接:https://blog.csdn.net/qq_41566923/article/details/103534706
    更新时间:2023-01-09 08:57:29