区块链的本质是一个分布式的数据库。因此不同时刻的用户数据的写入对应着不同的状态。比特币使用UTXO来表示状态的转移,而以太坊使用账来表示状态的转移。
以太坊中存在两种账户,分别是外部账户和合约账户。
账户在源码中的定义如下:
typeAccountstruct{
Nonce uint64
Balance *big.Int
Root common.Hash//merklerootofthestoragetrie
CodeHash[]byte }
EOA账户只能发起交易,例如转移以太币或者触发合约代码。CA账户不能发起交易,可以被触发执行合约代码。
外部账户对应转账地址,由用户创建;合约账户在以太坊中由EVM根据合约地址创建(在代码vm文件夹下evm.go文件中)。
typeTransactionstruct{
datatxdata
//caches
hashatomic.Value
sizeatomic.Value
fromatomic.Value
}
typetxdatastruct{
AccountNonceuint64
Price *big.Int
GasLimit uint64
Recipient *common.Address
Amount *big.Int
Payload []byte
//Signaturevalues
V*big.Int`json:"v"gencodec:"required"`
R*big.Int`json:"r"gencodec:"required"`
S*big.Int`json:"s"gencodec:"required"`
//ThisisonlyusedwhenmarshalingtoJSON.
Hash*common.Hash`json:"hash"rlp:"-"`
}
typeHeaderstruct {
ParentHash common.Hash //Hp,上一区块全部内容的hash
UncleHash common.Hash //Ho,本区块的所有叔块列表的hash
Coinbase common.Address //Hc,成功挖出本区块的矿工地址
Root common.Hash //Hr,本区块所有交易的状态tree的根hash
TxHash common.Hash //Ht,本区块所有交易tree的根hash
ReceiptHash common.Hash //He,本区块所有交易收据tree的根hash
Bloom Bloom //Hb,交易收据日志组成的Bloom过滤器
Difficulty *big.Int //Hd,本区块难度级别
Number *big.Int //Hi,区块序号,从创世块0递增
GasLimit uint64 //Hl,每个区块当前的gas limit
GasUsed uint64 //Hg,本区块交易消耗的总gas
Time *big.Int //Hs,本区块创建时的Unix时间戳
Extra []byte //Hx,区块附加数据,<=32字节
MixDigest common.Hash //Hm,256位的hash
Nonce BlockNonce //Hn,64位的hash
}
图2 此图片来自网络
Root(状态hash):整个系统状态的hash,也就是所有账户状态树的根hash。
TxHash(交易列表hash):本区块中所有交易默克尔树的根hash。
ReceiptHash(收据列表hash):收据默克尔树的根hash。
三棵树允许轻客户端轻松地进行并核实以下类型的查询答案:
1) 这笔交易被包含在特定的区块中了么?
2) 告诉我这个地址在过去30天中,发出X类型事件的所有实例(例如,一个众筹合约完成了它的目标)
3) 目前我的账户余额是多少?
4) 这个账户是否存在?
5) 假装在这个合约中运行这笔交易,它的输出会是什么?
第一种是由交易树(transaction tree)来处理的;第三和第四种则是由状态树(state tree)负责处理,第二种则由收据树(receipt tree)处理。计算前四个查询任务是相当简单的。服务器简单地找到对象,获取梅克尔分支,并通过分支来回复轻客户端。第五种查询任务同样也是由状态树处理,但它的计算方式会比较复杂。