北大肖臻老师《区块链技术与应用》系列课程学习笔记[23]以太坊-智能合约-3

智能合约-1

智能合约-2

一、思考

1.假设某个全节点要打包一些交易到一个区块里,这些交易里有一些是对智能合约的调用,那么这个全节点应该先执行完智能合约再挖矿,还是先挖矿获得记账权再执行这些智能合约?

        在区块链中,如果有一笔转账交易发布上去,需要所有的全节点都执行的,这不是一种浪费也不是出了某种问题,因为所有的全节点要同步状态,大家都要在本地执行这个转账交易,如果一个全节点不执行那就出问题了,他的状态跟别人的状态是不一样的。比特币系统也一样,比特币发布一个交易到区块链上,也需要所有全节点都得执行这个转账交易,以便更新UTXO。

        全节点收到一个对合约的调用的时候,要一次性的先把这个调用,可能花掉的最大汽油费从发起这个调用的账户上扣掉。以太坊系统中存在三棵树,即状态树、交易树和收据树,这三棵树都是全节点在本地维护的数据结构,状态树记录了每个账户的状态包括账户余额。汽油费是怎么扣的?全节点收到调用时,从本地维护的数据结构中将账户余额减掉就可以,若余额不够,则这个交易不能执行,一次性要按GasLimit把余额减掉。如果执行完之后如果有剩余,再把其余额再加回去。

        智能合约执行过程中任何对状态的修改都是在改本地的数据结构,只有在合约执行完了,而且发布到区块链上之后,本地的修改才会变成外部可见的,才会变成区块链上的共识。以太坊存在很多全节点,每个全节点都在本地做这个事情,执行的智能合约可能不完全一样(因为收到的交易可能执行不完全一样),如果某个全节点发布一个区块,收到这个区块之后,其他节点本地执行的就扔掉了,要将这个新发布区块里的交易再执行一遍,更新本地的三棵树。如果本来已经执行一遍了,但没有挖到矿,发布新区块了还得执行一遍,因为其他节点组装的在本地候选区块中包含的交易跟刚发布的那个交易中区块里包含的交易不一定完全一样,至少给出块奖励的那个地方肯定不一样,所以没有办法,都是得要重新执行一遍。    

        以太坊挖矿是尝试各种Nonce找到一个符合要求的,计算哈希的时候要用到Block Header的内容:Root,TxHash,ReceiptHash,是那三棵树的根哈希值。所以得先执行完这个区块中的所有交易包括智能合约的交易,这样才能更新这三棵树,这样才能知道这三个根哈希值,这样这个Block Header的内容才能确定然后才能尝试各个Nonce。

        假设一个矿工费了半天劲执行这些智能合约,消耗了本地的很多资源,最后我挖矿没挖到,那该矿工能得到什么补偿,能得到汽油费吗?汽油费是给那些获得记账权发布区块的那个矿工没有挖到矿,得不到汽油费也得不到任何补偿,不仅如此,还要把别人发布的区块里的交易在本地执行一遍,以太坊中规定要验证发布区块的正确性,每个全节点要独立验证。别人发布一个交易区块,把那个区块里的所有交易执行完一遍,更新三棵树的内容,算出根哈希值,再跟他发布的那个根哈希值比较一下看是否一致,所有这些都是免费的,没有人给你补偿。所以呢,这种机制下,挖矿慢的矿工就特别吃亏,设置汽油费的目的是对于矿工执行这些智能合约所消耗的这些资源的一种补偿,但是这种补偿只有挖到矿的矿工才能得到,其他的矿工相当于陪跑。

2.会不会有的矿工不给汽油费,就不验证?挖半天没有挖到矿,你发布一个区块,按照协议需要验证一下这个区块的正确性,验证又不给我汽油费,大家直接认为新区块正确,直接接着往后挖就行,会不会出现这种情况?

        如果这样做会导致的最直接的后果是危害区块链的安全,为保障区块链的安全,要求所有全节点要独立验证发布的区块的合法性,这样少数有恶意的节点没法篡改区块链上的内容。如果某个矿工想不通,不给钱我就不验证了,这样的风气蔓延开来就会危及区块链的安全,但是这样的事情会不会存在呢?跳过验证这个步骤,以后就没法再挖矿了,因为验证的时候是要把区块的交易再执行一遍,更新本地的三棵树,如果不去验证的话,本地三棵树的内容没有办法更新(本地的这些状态就不对了,算出的根哈希值发布出去之后别人认为是错的),所以根本没办法继续挖矿为什么要执行才能更新状态?因为发布的区块里没有这三棵树的内容,只是块头里有了根哈希值,这三棵树的账户状态具体是余额等的东西,发布出来是没有的,之前学习过,不能将状态树的整个状态发布到区块链上,那太多了,而且很多是重复的,状态都不改了,所以不会跳过验证这个步骤。以太坊的安全还是有保证的。

        在一个矿池中,存在验证阶段的“抄作业”情况,也就是全节点负责统一验证,其他矿工就负责相信全结点的验证情况。就是说,全节点分配给矿工的只是Pullze的内容,Pullze是根据区块链更新得到的,矿工则不需要考虑这部分内容。

3.发布到区块链上的交易是否都是成功执行的?如果智能合约执行过程中出现了错误,要不要也发布到区块链上去?

        执行发生错误的交易也要发布到区块链上去,否则汽油费扣不掉,光是在本地的数据结构上把他的账户扣了汽油费,是没用的,拿不到钱,你得把区块发不上去之后形成共识扣掉的汽油费才能成为你账户上的钱。所以发布到区块链上的交易不一定都是成功执行的,而且要告诉大家为什么扣汽油费,而且别人得验证一遍,也要把这个交易执行完一遍,看扣的是不是对的。

        前面说过那三棵树,每个交易执行完后形成一个收据,这个是这个收据的内容,Status这个域就是告诉你交易执行的情况如何,如下图1-1所示。

图1-1

 4.智能合约是不是支持多线程?现在多核处理器很普遍,一个计算器有十几核,几十个核,都是正常的,那么智能合约支不支持多核并行处理?

        Solidity不支持多线程,他根本没有支持多线程的语句,原因是以太坊是一个交易驱动的状态机,这个状态机必须是完全确定性的,即给定一个智能合约。面对同一组输入,产生的输出或者说转移到的下一个状态必须是完全确定的为什么要求这个?因为所有全节点都得执行同一组操作到达同一个状态,要进行验证,如果状态不确定的话,三棵树的根哈希值根本对不上,所以必须完全确定才行。

        多线程的问题是什么?多个核对内存访问顺序不同的话,执行结果有可能是不确定的,感兴趣的话,可以看看北京大学肖臻老师的论文。以前肖老师研究过的就是在多核环境下如何实现确定性重演,这是一个难度很大的课题。除了多线程之外,其他可能造成执行结果不确定的操作,智能合约也都不支持,最简单的会导致执行结果不确定的操作:产生随机数,这个操作就是不确定性的,而且这个操作必须得是不确定的,如果不同的机器产生的随机数不一样那不叫随机数了。所以以太坊的智能合约没有办法产生真正意义下的随机数,他用的是一些伪随机数,不能是真的随机数,否则的话,又会出现前面的问题,每个全节点执行完一遍得到的结果都不一样。

猜你喜欢

转载自blog.csdn.net/YSL_Lsy_/article/details/126561816