http://www.7klian.com

以太坊:基本概念梳理及智能合约运行机制

以太坊:基本概念梳理及智能合约运行机制


世界状态

世界状态是地址(160位标志符)和账户状态(序列化为RLP的数据结构)间的映射,区块链不直接存储世界状态,而是在区块头中存储相关Merkle Patricia树根节点的哈希值。

账户

以太坊引入了账户的概念取代比特币UTXO模型。以太坊中有两类账户,外部账户和合约账户,两类账户对于EVM来说没有区别。每个账户都有一个与之关联的账户状态和一个20字节地址,都可以存储以太币。

外部账户:由私钥控制,没有代码与之关联,地址由公钥决定。私钥可用于对交易签名从而主动向其他账户发起交易(transaction)进行消息传递,

合约账户:由合约代码控制,有代码与之关联,其地址由合约创建者的地址和该地址发出过的交易数量nonce共同决定。不可以主动向其他账户发起交易,但可以“响应”其他账户进行消息调用(message call)。

外部账户之间的消息传递是价值转移的过程,外部账户到合约账户的交易或合约账户到合约账户的消息会激发合约账户代码的执行,允许它执行如转移代币,写入内部存储,执行运算,创建合约等各种操作。

账户状态

不论账户类型,账户状态都包含以下四个字段:

nonce:随机数,账户发出的交易数及创建的合约数量之和。

Balance:余额,账户拥有以太币数量,单位为Wei,1Ether=10^18Wei。

storageRoot:存储根节点,账户内容的MerklePatricia 树根节点的哈希编码。

codeHash:代码哈希,与账户关联的EVM代码的哈希值,外部账户的codeHash为一个空字符串的哈希,创建后不可更改。状态数据库中包含所有代码片段哈希, 以便后续使用。

以太坊:基本概念梳理及智能合约运行机制


以太坊:基本概念梳理及智能合约运行机制


 

交易(Transaction)

外部账户向其他账户发送签名数据包。每一笔交易都会改变以太坊的状态,都将被序列化,经矿工验证广播后记入区块链,因此,交易是异步的,可以即时返回的值只有transaction hash。交易可以分为创建合约和传递消息两类。一个交易的完成可能会需要触发多条消息及消息调用。

交易包含:

∙交易的接收者

∙可识别交易发送者、证明这是一笔发送者通过区块链发送到接收者的交易的签名

∙ VALUE,需转移的以太币数量(wei)

∙ Gas Limit(有时被称为StartGas),允许交易执行时消耗的最大gas数量

∙ Gas Price,交易发送者指定的单位gas的价格(用以太币计算)

消息(Message)

两个账户间传递的数据和值(以太币)。不一定会改变以太坊的状态,只存在于以太坊执行环境的虚拟对象,不会被序列化也不会被记入区块链,消息是同步的,可以即时得到返回值。

消息调用(Message Call)

将消息从一个帐户传递到另一个帐户的行为,调用形式类似Transaction,但是只存在于以太坊执行环境的虚拟对象不会被记入区块链,可以类比函数调用。如果目标账户是合约账户,则合约账户的EVM代码被激发执行,如果两个账户都是合约账户,则调用中可以传递所有虚拟机的返回值。

消息包含:

∙消息的发送者(隐式的)

∙消息的接收者

∙ VALUE,随消息传递到合约地址的以太币数量(wei)

∙可选数据字段,作为合约的输入

∙ STARTGAS,用来限制这个消息触发的代码执行能消耗的最大gas数量

消息调用和消息通常同义,没有必要严格区分。

交易和消息不是包含关系,而是部分重合关系:交易发送者不经过合约直接发送交易到以太坊指定地址创建合约的操作,没有消息调用的过程,只属于交易;交易发送者通过调用合约从一个账户向另一个账户转账的操作,既属于交易又属于消息调用;合约账户受到外部账户激发而进行创建合约的操作,只属于消息调用不属于交易。

交易一定是由外部账户发起,一个交易可能会引发一系列“消息调用”,合约账户为“响应”来自其他账户的“消息调用”而执行代码继而激发新的“消息调用”,因此,本质上所有“消息调用”及以太坊的状态改变都是由外部账户激发,即,以太坊在整体上可以看作一个基于交易的状态机:起始于一个创世块(Genesis)状态,然后随着交易的执行状态逐步改变一直到最终状态, 这个最终状态是以太坊世界的权威版本。

燃料和支付(Gas)

以太坊的交易需要考虑到很多消耗因素, 包括带宽消耗, 存储消耗, 计算消耗等,为了避免网络被滥用及回避由于图灵完备性而带来的一些问题,在以太坊中所有的程序执行都需要费用。各种操作费用以gas为单位计算。任意的程序片段(包括合约创建、信息调回、利用及访问账户存储、在虚拟机上执行操作等)都可以根据规则计算出消耗的燃料数量。

每一笔交易都有燃料上限(Gas Limit),交易发送者发送交易时会指定燃料上限和燃料价格GasPrice,执行交易前这些指定的燃料费用将从交易发送者账户余额中扣除,扣除额度 =GasLimit*GasPrice,交易完成后,剩余的燃料以购买时的价格退回到交易发送者账户,未退回的费用作为挖出包含此交易区块的矿工的奖励。若交易执行过程中发生燃料不足异常(out-of-gas, OOG),交易会被当作无效交易,已消耗gas不会退回,仍作为矿工贡献计算资源的奖励。燃料价格相当于以太币和gas之间的汇率,可以由交易者任意设定,高价格的燃料将花费交易发送者更多的以太币, 并奖励矿工更多的以太币,因此这个交易会被更多的矿工选择。通常,矿工会通知他们执行交易最低燃料价格, 交易发送者们会选择一个高过燃料价格下限的价格,从而产生一个(加权的)最低可接受燃料价格分布。

GasPrice只能在交易中由原始交易发送者设置,消息调用中没有GasPrice字段,一个交易引发一系列“消息调用”时,原始交易发起者需支付所有执行费用,交易和消息调用都可以限制消耗gas的数量,不同的是消息调用时若消息发送者限制了gas消耗的子执行出现OOG异常,只回滚该子执行的操作,父执行没必要回滚。

以太坊:基本概念梳理及智能合约运行机制

合约创建

当外部账户主动发起交易(交易可以包含二进制数据(payload)和以太币),或合约账户因被外部账户激发进行消息调用,接收者为以太坊指定空集⌀时,创建合约。新合约账户地址由合约创建者的地址和该地址发出过的交易数量(被称为nonce)计算得到,被保存的合约代码体为执行附带初始化EVM代码后得到的最终字节码(创建合约交易的payload被当作EVM字节码执行,执行的输出做为合约代码被永久存储)。完整交易经矿工广播验证后和新的世界状态一起存入区块链。完整交易的发起者支付创建过程消耗的gas,挖出包含该交易区块的矿工得到这些gas作为奖励。若合约创建期间因燃料耗尽、堆栈溢出、无效指令等异常中止,所有操作回滚,被改变状态恢复,已消耗gas不返还,仍作为矿工贡献计算资源的奖励。

Note:合约账户也可以创建合约,合约账户由外部账户发起的交易激发进行创建合约的消息调用时,此合约账户即为消息发送者(Solidity中记为msg.sender,意为当前函数的调用者),新合约地址由此合约账户的地址和nonce确定,创建合约的费用由发起完整交易的外部账户支付。

合约调用

当外部账户主动发起交易,或合约账户因被外部账户激发进行消息调用,接收者为合约账户时,合约账户内EVM代码被激发在本地EVM中执行,执行结束后,返回执行结果,完整交易经矿工广播验证后和新的世界状态一起存入区块链。完整交易的发起者支付执行过程消耗的gas,挖出包含该交易区块的矿工得到这些gas作为奖励。若合约执行过程中抛出异常,所有操作回滚,被改变状态恢复,已消耗gas不返还,仍作为矿工贡献计算资源的奖励。

Note:合约账户不能自发的检查外部条件是否满足预先设置的情形,从而触发代码的自动执行,只能通过外部账户发起交易激发合约账户执行检查操作。作为替代的是,可以调用Ethereum Alarm Clock合约间接实现如预定一段时间后的合约执行条件检查。(平行区块链)

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读