00:00
好,那我们继续来介绍白皮书里边的内容,接下来这一部分呢,前面我们已经说到了,整个这一个交易的过程当中,也就是状态转换是怎么做的,这其实就是我们的交易对吧,交易发生的过程,以太坊的虚拟机EVM怎么样去处理交易,那接下来这一部分呢,就是要真正的说到EVM它在代码级别是怎么样去处理的,这就涉及到EVM的一些原理性的东西了,那我们这个也是需要去看一下的,就是微生他为什么把这个东西想的很清楚,就是在他构想这个事情的时候,E em这样的东西怎么样去设计,怎么样去运作,他其实脑子里面都有一个很完整的蓝图在里面了啊,所以这样的东西大家一看就会,尽管他写的很简单,但是我们如果要是细细的去琢磨琢磨的话,就会就会发现啊,这个确实是得。
01:00
方方面面都了解,对吧,又又知道这个比特币的特性,又知道这种分布式系统的特性,然后还得知道像这种编译,编译原理方面的东西啊,对吧,虚拟机um字解码这样的东西还也也得了解,好,那我们看一下代码执行这一部分。以探考合约代码使用低级的基于堆栈的自解码语言写成,也就是说EVM上执行的就是字节码,EVM它识别的语言就是字节码啊,所以这个被称为。呃,合约的代码就被称为以太坊虚拟机代码,或者是EVM代码,所以这都是一回事,代码呢,就是由一系列字节构成了,每一个字节代表一种操作,比如说啊,这里大家看到啊,就像这个stop return,这就是一个字节码的一个操作,或者大家如果要是之前我们编译完了之后,会看到有那个op code对吧,编译完了的文件里面。
02:07
Op code其实就代表呃,它不是自解码,但是代表了自解码的操作服务,大家如果感兴趣可以去看看那个op op code都是一些什么样的东西,呃,一般而言呢,代码执行它是无限循环的,所以它在执行的过程当中,相当于就是说如果听不到指令。那就一直执行,所以这就是所谓的图灵机,对吧,大家大家想到那个图灵机的那个过程,如果要是程序允许的话,它就一直在前后左右来回移动,对吧?只有当我们有这样的命令让它停止的时候,它才会停止,而且里边大家看到是有一个程序计数器的程序计,计数器每增加一,当然它初始值是零啊,就开始计数,每增加一就执行一次操作,去找到下一个需要做的操作,直到代码执行完毕,或者遇到错误,那代代码执行完毕呢,遇到的就是stop这个指令,错误的话那就是return。
03:13
操作可以分可以访问三种数据类型的存储啊存存储数据的空间,这就是我们之前讲EDM的时候给大家提到的,一个是堆栈stack。呃,大家可能知道,就是我们一般的这种。临时的这些状态变,呃临时变量啊,应该叫呃这样的一些临时定义的一些变量,还有就是我们的一些函数调用的一些信息,一些操作都会放到堆栈这个数据结构里面来,呃,大家对对栈应该比较熟了,这是一个后进先出的存储类型,对吧?就是先进来的压到站底去,然后后进来的往上面对。出战的时候也是上面的先出去,所以是后进先出,那32个字节,以太网虚拟机里边操作字操作的对象都是32字节,32字节的数值,它可以入站,然后出站,可以做这样的操作。
04:17
呃,然后就是内存内存了,我们所说的memory对吧,这是一个可无限扩展的字节队列啊,那这个其实说的比较就是不太好理解,其实大家简单想的话,它其实就是我们平常电脑的内存,大家理解成这样就可以了,就是比较快,可以快速访问的,但是就是说执行完了之后会清空,会完全初始化到最初状态的这样的一个空间,它不可以长期的保存数据,与之对应的另外一个就是合约的长期存储storage storage这个是一个k value的一个存储了,那它的K和value都是32个字节的大小。啊,这里写的是密钥啊,这个不应该是密钥,见对吧,见只对。
05:04
与计算结束及重置的堆栈和内存,也就是说堆栈和内存它都是计算完了之后就重置,就清空了,之前的东西都不存着,所以它速度比较快,但是这个存储也会就是不能长期存储,也会比较宝贵,那跟它不同,长期存储storage,这是一个持久化的一个存储,所以我们整个区块链上所有的信息,有效的这些状态信息,状态变量都会保存在storage里面去。那我们的代码呢,可以像访问区块头的数据一样访问数值,也就是说这里所有的数据都可以在代码里面能访问的到,我们可以访问,也可以访问内存里面的数据,也可以直接从story里面去拿数据,这个大家在写合约的时候都很熟悉了啊。另外还可以访问发送者和接收到的消息中的数据。
06:04
也就是啊,Mes send对吧,Mes value,包括我们拿到的消息里边的data都是可以拿得到的。另外就是代码还可以返回数据的字节队列作为输出,那就是我们在消息调用的时候还可以获取它的返回值,对吧?它可以有一个返回,呃,接下来他是简单的说了一下这个EVM代码执行啊。他说执行正式的执行模型令人惊讶的简单,但事实上大家可以看一下,这里说的好像简单,事实上也不简单啊。当以太宝虚拟机VM运行的时候,它的完整的计算状态由一个元组来定义,也就是由这么多东西,所有的这些东西就表明了EVM的计算状态,哪些东西呢?一个叫block state block state其实就是所有的状态,也就是大家看后面的解释啊,包含了所有账户、余额和存储的全局状态,大家可以认为就是世界状态block,然后transaction。
07:15
那就是状,既然是em要执行嘛,执行的时候带来状态转换,引发状态转换的是什么呢?Transaction交易,当然还有可能是message,对吧?有message,另外还有code code就是当前执行的代码,还有就是memory和sta。Memory和stack,那是当前执行过程当中。就是当前运行环境里边的存储内存还有占,呃,另外呢,还有PCPC是一个就是program。Counter对吧,就是一个计数器,就是呃,程序计数器,大家看下面啊,每轮执行的时候,通过调出代码的这个程序计数器DPC的自己,然后当前指令就被找到,这是什么意思呢?这是说。
08:08
程序计数器,它本身我们知道整个系统里面都会有一个时钟,对吧,那它本身程序计数器就是每一次过来的时候,一个周期就会加一,就会记一个记一个数,那它增加之后这这一轮执行它。就是要执行的这个代码去哪里找呢?就是由这个程序计数器指定的位置去找的,比方说现在是十,那么就要找到代码的第十个自己,然后看看到底是什么指令,看看那个out到底是什么,找到了当前指令之后。那这个指令就有一套定义的规则,它用什么样的方式去影响到,就是前面所说的这个元组,就这些元组就代表整个EVM的计算状态吗?那每一个操作都会改变这个状态,举个例子,就是比如说这个A,这是一个操作。
09:06
一个auto code叫A,那就是加了对吧?它会引发EVM的什么变化呢?它的操作是将两个元素出站,并将它们的合入站。啊,大家如果之前简单的实现过一个就是加法器,或者是一个计算器这样的东西的话,大家肯定知道他说的是什么,呃,为什么呢?因为A加这个直观的讲,它就是一个二元的操作符,对吧。就是输入两个数,输出一个结果,所以我们计算机里面它怎么样去做这件事情呢?它的做法怎么样保存我们之前的变量呢?那么它其实是读到前面输入的两个数的时候,对读到一个进站压进去,又读到一个又进站把它压进去,然后这个时候又读到了一个ADD。
10:00
这样一个操作符,那么就会把压进去的这两个数对弹出来,然后加起来,做完这个操作之后再把它压进去,对把结果再入战,那大家可以想到他为什么还要结果再入战的,因为有时候不是你艾特完了就完了对吧,那结果肯定是要用的吧,有时候那如果咱们是一个复杂运算,你加完了之后还要减呢,那它的操作是什么?其实就是说把操作数。一个一个都压进去,然后呢,最上面的两个是加,这就是第一步操作加完了之后压进去的结果,然后下边应该还有一个操作数,就是要减的那个操作数,对吧?那得到的结果再跟下面的这个操作数都弹出来,如果碰到一个M的一个操作数减,那把他俩再减完再压回去,下面有可能还要乘,还要除,对吧?这就是整个这个,呃,计算机指令在做这些操作的时候发生的一些事情,那除了他把这个两个元素出战,然后把它加起来再入战,除了这个操作他还干什么呢?他要把GA减掉。
11:14
啊,这就是前面我们忘记说了,就是这个状态元素里面还包括GA,就当前的GA,所以他会把对应I的这个操作的GA消耗掉,然后把PC我们的程序计数器加一。这就是整个这个APP的操作,他要做什么事情好像很简单,但是呃,大家如果要是之前学过,呃,编辑原理,或者是一些就是计算机底层的东西,可能会觉得好理解,如果要是就是第一次接触的话,可能还觉得挺挺绕对吧?呃,那他后面又举了一个例子,就是比方说sto s store这个东西是什么呢?就相当于是要把我们的一个元素要存入到storage里面,对吧?Storage store存入我们的永久存储,这个怎么做呢?
12:04
它的做法是将顶部,哎大家先想一下,如果说我们想要做一个存储存储操作的时候,假如我们认为这个存储操作是我们的一个函数,我们要调用的时候,我们应该给他什么样的输入参数?存,存一个数。首先应该把这个数给他,对吧,就就是我们要存什么数,这个数应该给他,这是一个操作参数,那还需要别的参数吗?是不是有了这个数就可以可以操作了。啊,对,大家就想到了,你对于我们在这个函数调用的时候,我们不考虑那么多,对吧,你要存什么,我直接传什么就完了,但对于计算机来说,他是很蠢的,他不知道啊,你告诉我要存往哪存,你得告诉我。所以这里。S store本身这个操作也是有两个元素的,两个什么元素呢?一个就是往哪里存,一个就是存什么,所以这两个东西都告诉我。
13:10
计算机了之后,那这两个元素就应该是先压到站里面了,对吧,然后这个时候em又读到一个操作符叫做sto,那他就知道了,把刚刚压进去的这两个操作符我就要,呃,操作的数我就要拿出来,然后做什么动作呢?我把第二个元素,这是我要插入的。值,那么插入的位置是第一个元素,所以我会把第二个元素弹出来的这两个元素,第二个元素的值插入到第一个元素指定的位置当中去,这就是S。啊,当然了,同样他还要减掉对应的这个GA,然后把PPC加一对吧?啊,那这里还专门说了一句,就是最多200的盖,也就是说你去存一个东西的话,大家知道你存的话。
14:02
存的东西越长,肯定消耗的GA就越多嘛,他这里是给了一个限制的,说减少最多是二元的GA,只是给了一个限制,你如果超过这个的话,那就行了,好,呃,所以说就是大家可以看到这里就是白皮书里面,其实是简单的把EVM的整个原型都已经列出来了,呃,这其实是,呃,大家如果感兴趣的话,就可以就是好好的看一看黄皮书,然后看一看我们那个源码,然后看看这个EVM这么样一个东西,它是怎么样实现这么这么复杂的一堆东西的,呃,这部分可能会比较深,但大家如果真要感兴趣的话,把这个琢磨透了,呃,那那真的是很厉害,真的就是应该是大神级别的了啊。好,那么我们接下来再。呃,刚才这一部分是EVM,可能会相对的比较比较难,比较深一点啊,我们简单做个了解,接下来我们来说这个区块链和挖矿这一部分,其实大家就很熟悉了,对吧?呃,我们这里呢,其实就主要的不是说它怎么样去挖矿,而是说就是我们要去说一下以太坊的区块确认的算法,他怎么样去确认一个区块是有效的呢?
15:23
呃,那大家看一下啊,呃,这里就是说以太坊这个区块链在很多方面类似于比特币,所以大家已经学过了比特币,以太坊基本上。概念和一些定义,其实它的方法都是差不多的,那以太坊呢,架构跟跟这个比特币不一样的一点,很大的一点主要就是说以太坊它的区块里面的信息不不仅仅包括交易记录和这个最近状态,而且它还包括了区块序号和难度值,所以它是难度值也是直接写在里面的,就是每个区块的难度是随时调整的,也就是说。
16:05
这个跟比特币,跟比特币的调整是两两周调整一次,对吧?呃,而且就是说诶大家之前有。影响吗?比特币的难度调整。取款就是啊哦,大家说的是就是那个整体的那个,呃,难难度调整对吧,整如如果说是就是大家这个两两。对,如果说是说每一个区块的这个矿工奖励的话,那是四年会调整一次,对吧,但是它的本身比特币的这个区块的难度,那是两周会调整一次的。呃,那比特币的话,这个就是为了系统的稳定,它整个这个周期都拉的比较长,那以太坊就会不太一样,以太坊是就是每个块都可以去调整的,好,那么我们看一下这个以太坊的区块确认算法啊,首先第一步。
17:07
检查区块引用的上一个区块是否存在和有效啊,那这个就不用说了,因为我们知道,呃,首先就是我们区块链要求的就是你要引用上一个区块的哈希,所以说只有这个方式才能够让它形成一个链条,我们才能保证它朝着一个方向去找,你如果上一个区块的不存在,那这个区块它再有效的没用,所以这是肯定的第一步,第二步这个好像平常一般很少说到啊,就是他会说检查区块时间出是否比引用的上一个区块大,而且小于15分钟。检查时间,说这个大家可能容易想到这个,就是你不能说我这个区块产生的时间比上个区块还要还要早,那这个其实是。就明显是不合理的,对吧,就是即使是说我挖出来的早,那你就不应该能包含上一个区块的交易状态啊,你不应该能基于上一个区块状态,你最多是跟他是竞争关系对吧,是兄弟关系,你不可能是他的子关系,所以时间说是不能比上一个区块大的,而且它还有一个限制,说要小于15分钟。
18:15
这个是什么意思呢?那其实也就是说,因为默认是十几秒出一个块,如果说你间隔的时间比15分钟钟都大的话,那我们其实是有理由认为你可能人为的做了一些改动或者是调整,对吧,或者说就是在这个过程当中,呃,你的这个区块就本来就不应该接受,就是被我现在的这个区块接受,我接受了你这个区块,可能是因为我没有连接到其他周围的节点,其他周围的节点肯定有比它更前面的区块进来,所以可能是这样对吧,所以就直接会拒绝掉这样的一个就是。呃,间隔大于15分钟的这样时间出的区块,所以他这个平常很少会提到,大家可以看到设计的时候有很多这些小细节,然后还有就是会检查区块的序号,难度值,还有交易根,那这些东西呢。
19:12
首先就是说区块序号你自己的这个高度是不是对的对吧,接着前一个区号高度一定是加一的,然后难度值是不是符合仪态方里面规定的计算标准啊,这也是必须要有的,还有就是交易的,呃,交易的根其实就是我们所说的交易数的数根。就是transaction trade的哈希transaction route,那之后我们会给大家在就是详细的讲一下,就是以太坊里边的它的区块里边包含三棵树的树根吧,之前跟大家说过对吧,就交易树,收据树和状态树,那这个交易数的数根,这个是一定要去检查的,那这个是否合,是否正确,然后这里还会去检查一个书根,就是这其实说的是就是对书书块里边的交易树的树根,所以他会检查书块。
20:16
然后还会检查这个GA limit gas limit,这个其实就是说你是否里边的所有交易加起来GA超超过了这个GA limit,包括我们整个现在这个,呃,以太坊系统里面设定的GA limit,你是不是给的超出了这个标准,这些都是要提前判定。呃,第四步啊,终于到了工作量证明了,那就是啊,这个大家都很熟悉对吧,你算的很麻烦,我这里校验是很容易的,我看一下就知道了,然后第五步,将S0赋值为上一个区块的root。这是什么意思呢?就是当前我要去验证一个区块的时候,我得有一个初始状态,这个初始状态被命名为S0。
21:07
那么这个初始状态是什么呢?这个初始状态就应该是上一个区块已经尽快被确认完成之后的状态,对吧?那它完成之后的状态是什么呢?就是它的。状态数的书本state。所以也就是说,把上一个区块里边的状态拿过来,作为当前区块确认开始的状态,这是第一步,确认第一步啊,真正确认的第一步,好,接下来第六步。是按照交易。一笔一笔去确认,那我们前面已经知道状态转换函数是前面我们已经说了,就是一个交易进来之后会怎么样状态转换对吧?啊,它会验证各种交易这个余额是不是充分啊,然后去扣盖啊,一笔一笔做这件事情,那现在就会拿到区块的交易列表,一笔一笔交易做我们上面讲过的那个状态转换的过程。
22:09
每一步状态转换完了之后,就从上一个这是S0对吧,那第一笔交易完了之后就变成S1,第二笔交易之后变成S2,所以就一个一个状状态转换到下一个状态。最终肯定就会,假如说有N笔交易的话,那最终就一定会转换到SN,对吧,大家能够想象得到,所以如果其中任何一个转化发生错误,或者执行到这里。花费的GA超过了GA limit,那就返回错误,那大家注意啊,这个所谓的这个错误和这里的auto of gas,这个说的是区块,区块层级的错误和out of gas。呃,这个其实不应该是auTo Ga,不是说这个交易GA不够了,而是总共的GA消耗超过了GA limit对吧,区块的GA limit,那这个时候。
23:10
这一次区块确认那就失效,就认为我们这个是无效的一个区块。所以是这样的一个概念,好,那最后一步,如果所有的交易状态转换都没问题,都是有效的,所有的都成立,那最终的状态SN。就给s final赋值,也就是说这是我们最终状态。然后就会向矿工支付区块奖励,就是所谓的这个,呃,就是我们的这个手续费,对吧,还有这个区块每一次挖矿的这个奖励,那这些奖励呢,其实不是确认。一个区块所要做的,但是这里是放在一起来说的,就是这一步是是同时在这里做的,对吧,就是因为我们确认的时候是要把本地的矿工的那个balance也要改掉的,对不对?所以这里所谓的奖励区块,其实就是把本地的那个balance状态改变一下。
24:09
最后一步就是检查我们的final的状态,是不是跟我们当前的这个星块。区块头里边写着的那个状态数的数根一致,所以大家会发现所谓的那个state root状态数的树根是什么呢?啊,就是这么一步一步算出来。就是每一个交易他们的这个一步一步状态转换,转换完了之后的这个数根,当然我们知道这是一个梅克尔树的树根,对吧,所以它是两两两的,这个计算完了之后拼在一起的,那这个之后再说,如果说这两个相同的话,那到这一步区块才能说是真正有效的。如果不相同,那之前全部都成立,那也没用,这个还是无效的一句话,所以大家可以看到就是这就是整个验证区块有效性的一个过程啊,从前面我们对这个状态转移,校验一笔交易是否有效,然后现在把交易打包起来之后,再校验一个区块是否有效,对吧,就是一个矿工挖块出块之后,别的区块,别的节点怎么样去校验这个是否有效。
25:22
呃,下面有一些分析啊,就是说他说这个这个确认方法呢,乍看起来似乎效率很低,为什么呢。因为大家可以看到,在这个过程当中,我们是需要把所有的状态都搞清楚的,对吧,所以就相当于我们是需要存储每个区块的所有状态的,我们每个账户的所有的信息都得在里面,它的余额,它的代码,它的存储状态,所有的东西都必须有。那要这样的话,我确认了一个区块,下一个区块又来了,来了之后我又得把它所有的那些状态全弄一遍,这个真的是很,就是他觉得好像是效率太低了,对吧?嗯,所有的状态数据那么多,这里白皮书里边他解释了,他说事实上。
26:18
以太坊的确认效率是可以跟比特币相相提并论,什么原因呢?原因是它的状态是存储在数结构当中的。每增加一个序号的时候,它只需要改变数结构的一小部分。哎,大家想象一下这个他是怎么怎么做到的呢?其实简单来说的话就是啊,大家看下面它的这个解释啊,就是一般而言,相邻的两个区块里边树结构,也就是状态大部分应该是相同的。什么意思?就是说你这里边来了一个新的区块,确认了一系列的交易,这些交易能够涉及到的账户肯定是有限的,那大部分的那些账户其实是没变的,所以这些账户的状态不变,那他们在数结构里面的存储对应的那些东西,对那些值,那些哈希也是不变的,那这些东西不变的话。
27:21
在下一个存储里边,下一个区块过来的时候,就可以不把它直接做这个直拷贝,全拷贝过来,我们是不是直接有一个引用拷贝,有一个指针指过去就可以了。啊,所以大家可以注意,就是这里呢,就是只需要存储一次数据,然后呢,我们只要在下一个区块来了,发现它没变,我们只要有一个指针指过去就可以了。啊,所以这就是一次存储,然后指针引用就可以引用多次,它这里写的是两次,那如果再下一个还没变的话,那它跟上一个比,发现又可以引用过来,就继续引用对吧?呃,这里就提到了这个判断比下数啊,就是说它比下树可以实现这一点,但事实上他这里说的应该是就是煤克判断一下数,因为他说是包括了对煤克数概念的修改,它是。
28:19
不仅允许改变节点,而且还可以就是插入和删除节点啊,这样。就是用维克判断一下数,这样的一个结结构,就实现了非常方便的存储和查询,插入和删除啊,这样就是以太坊的底层的数据,明天我们给大家再详细讲这一部分吧,啊,这里它还有一个数据啊,就是说。如果这个方法能够用到比特币系统里面,经过计算可以对存储空间有十到20倍的节省,也就是他说他提出来的这个煤克尔帕特以下数,假如比特币能用这个方式的话,节省十到20倍的空间,呃,当然说是这么说啊,这个我也不知道威神这个是到底怎么计算的啊,他也没有公开这个这个计算的过程,但是我们从直观上来讲的话,确实他说的还是有道理的,对吧?好,那接下来我们来讲一下,接下来这又是一大部分啊,就是整个以太以太坊上的应用。
29:23
啊,应用这一部分的话,大家可以看,就是以太网上有三种应用,一般来讲啊,这是微神总结出来的,第一类就是金融,金融方面的应用,其实很好理解,就是呃,本身它就是一套货币系统吧,本身就是一套数字货币,所以说本身默认内置的方法里边就有账户的概念,就有互相转币的这样的概念,就有balance余额这样的概念,所以说理财宝系统天生就支持金融应用,所以可以看到。
30:00
在以太网上开发的这个D或者说合约,可以为用户提供更强大的用他们的钱来管理和参与合约的方法,就是说你想怎么管你的钱,你写个合约就可以,你可以去构建你的账户,你可以要求你的账户必须是一个多重签名的地址,你可以用另外的签名算法去构建自己的钱包,你想要做什么都可以有合约,什么都可以做,这里包括就是子货币,还可以有金融衍生品,对冲合约,还有储蓄钱包、遗嘱,甚至一些种类全面的雇佣合约啊,这其实就是都涉及到的就是钱,跟钱相关的都可以。金融方面的应用,包括金融衍生品,对吧,股票啊,证券啊一类的东西都可以放在上面,第二类就是半金融应用。这什么意思呢?这里包括就是说它里面有钱的存在,但是呢,也有很重要的不是钱的方面这样的结合的领域。比方说什么呢?完美的例子是为了解决计算问题而设的自我强制悬赏。
31:08
这是一个什么东西呢?大大家还记得我们之前讲的时候讲过一个一个猜数字的一个游戏吗?啊,他当然那个是一个陷阱合约啊,就是我们当时是给大家当一个陷阱来讲的,就是呃,他这个扫里面默认的这个变长数组会就是临时变量会会存在storage里边对吧?会如果不复数值的话,它就是指向storage这空间的一个引用,呃,这个问题是另外一回事,但是事实上大家看到很多合约就可以做成这个样子。如果要是他做的正常的话,那其实就是说我们定制一个悬赏机制,比方说我里边就提供一个猜数字,或者说我就让大家去解决一个难题,你解决出来之后发对应的结果到这个合约就能够把它解锁,然后我的合约里边的那个方法就固定的把这笔钱转到你的账户里面,所以这就是一个悬赏的功能,对吧。
32:13
呃,网上也有对吧,对对对,解三道题解三道题是吧?对啊哦对,现在其实很多种玩法就是这样的,对吧,就是呃,我记得之前好像有人发布的那个悬赏的,还还数额挺高的呢,对吧,他好像还是分不同的过关,好像是前几关好像已经被人破解出来了,但是后面那个就非常非常的难,就像解一个这种达芬奇密码一样的东西,涉及到方方面面的知识去解决,大家如果感兴趣的话,也可以去搜一搜啊,看看自己有没有这个这个本事和运气,能把那个一大笔比特币能提出来,或者说以太坊,呃,就是以太币能提出来,那这样就是一个悬赏合约啊,当然就是说它其实也是很好玩的一个东西,除了这样的应用,就是金融的应用和半金融应用呢,那最后就还有就是在线投票,还有区中心化治理DOS对吧。
33:14
在线投票,那我们都已经实现过这个简单投票了,其实非常容易能实现这样一套东西,它跟钱没有关系,但是就是我们它相当于这就是一个社会领域的应用了,就是更像一个社会组织形式,所以以太坊它构建的最初其实就能涉及到就是金融、经济、社会组织各个方方面,所以它是一个很大的平台,这也是他的一个初衷。
我来说两句