比特币区块链纯粹是一个关于交易的列表,而以太坊的基础单元是账户,区块链跟踪每个账户的状态,以太坊的状态转换是账户之间价值与信息的转移。
账户分为两类
外有账户:由私人密钥控制
有以太币余额
可以发送交易(以太币交易或引发合约代码)
没有相关代码
合约账户:有它们的合约代码控制,只能由外部账户“激活”
有以太币余额
有相关代码
代码执行由从其他合约接收的交易或信息触发
以太坊上所有的行为都是由外有账户引发的交易变动。每次合约账户接收到交易时,他的代码都会按照输入的参数进行执行,并作为交易的一部分进行发送。
交易:在以太坊中用来指代签署的数据包,数据包中储存着从外有账户发送到区块链另一账户的信息。包括以下内容:
信息接收人
签名(确认发送方身份)
value(金额)
可选数据域(发送到合约的信息)
等等。。
消息:合约向其他合约发送的内容。
消息发送方(内含的)
消息接收方
value域
可选数据域(发送到合约的实际数据)
等等。。。
本质上说 一个消息就像一个交易,只不过消息是由合约而不是由外在因素创造的。和交易一样,消息可能会导致接收方账户运行代码。
每个用户可以通过外有账户发送交易来触发行动,启动以太坊。如果交易的目的地是其他外有账户,那么交易可能会转移一些以太币。如果目的地是个合约的话,合约会激活,自动运行代码。
智能合约可以理解成一段可执行的程序片段,具体的代码由发布人使用特定的语言来编写,本地编译成功后可以发布到区块链上,被发布的交易会被矿工打包记录在某个区块上,调用这个智能合约的方法只需要向这个智能合约的地址发送一笔交易即可。
以太坊区块头包括以下内容:
- ParentHash:父块的哈希值
- Number:块编号
- Timestamp:块产生的时间戳
- GasUsed:交易消耗的Gas
- GasLimit:Gas限制
- Difficulty:POW的难度值
- Beneficiary:块打包手续费的受益人,也称矿工
- Nonce:一个随机数,使得块头哈希满足POW需求
- 账户发起交易需要花费一些gas,作为手续费归矿工所占有。在POW模式下,矿工在打包块的时候,需要不停的调整Nonce,使得整个块头的哈希值满足一定的条件(比如头几位都是0)
- StateRoot:状态树的根哈希值
- TransactionsRoot:交易树的根哈希值
- ReceiptsRoot:收据树的根哈希值
每个矿工在把交易打包成块的时候,会组织三颗树:
-
- 交易树,树叶里是交易
- 收据树,树叶里是交易生成的收据
- 状态树,树叶里是交易影响到的账户状态
三棵树求取根哈希,可以得到 区块头中的StateRoot,TransactionsRoot,ReceiptsRoot三个字段。这样就建立了交易和区块头字段的映射。当其他用户收到块,根据块里的交易可以计算出收据和状态,计算三个根哈希后和区块头的三个字段进行验证,判断这是否为合法的块。
多个块的MPT树共享了账户状态,子块状态树和父块状态树的差别在于它指向了在子区块中被改变了的账户。这样节省了总的存储空间,方便了块的回滚操作。
收据(Receipt)
账户创建交易并向其它节点广播后,会被其它节点执行并放入准备打包的区块。在这个过程中会生成一个收据。收据的主要字段有:
- blockHash: 交易所在块的哈希值
- blockNumber: 交易在块的序号
- transactionHash: 交易的哈希值
- transactionIndex: 交易在块中的序号
- from: 发送者地址
- to: 接受者地址,为空时候表示创建合约
- cumulativeGasUsed: 执行完此交易时候,块内消耗的总的gas值
- gasUsed:本交易所消耗的gas
- contractAddress: 当此交易为创建合约时,表示所创建合约的地址,否则为空
- logs: 此交易的日志
需要注意的是,在不同的节点之间并不会发送状态和收据,后两者在可以通过交易计算得到。