与BTC不同,ETH使用的是基于账户的账本(account-based ledger),账本中记录了各个用户的的余额,交易时不必追溯币的来源。
基于账户的账本对双花攻击(duoble spending attack)有着天然的防御作用,账户余额是系统中全节点维护的一个状态,称为balance,交易发生时余额随机改变,但与之而来的问题便是重放攻击(reply attack):若将已发布的交易再一次进行广播发布,造成支付者多次支付,接收者将因此获利。
ETH中使用nonce解决这一问题,nonce作为账户状态中的一个字段,有着计数器的功能,记录了账户有史以来交易的次数,转账时,nonce成为交易内容的一部分,受支付者的签名保护。
ETH有两类账户:
由于ETH支持智能合约,要求参与者有比较稳定的身份,这与BTC的设计有所不同。
ETH的账户地址是160bits,共20个字节,账户地址到账户状态为一对映射,账户状态为前述的包括balance,nonce,code,storage等。所有的账户组织成一个改进的Merkle Patricia Tree。
存储账户状态的结构为状态树,其基本数据结构为Merkle Patricia Tree。MPT是一种融合了merkle tree和patricia tree两种树结构优点的数据结构,用路径压缩提高效率,可计算出一个账户状态的根哈希值, 保存于block header中。
MPT丰富了节点类型,共有如下4个类型的节点:
ETH对MPT做了略微的改进:
具体以官方的下图为例:
MPT作用如下:
用于记录交易的数据信息,其结构也为MPT,其键值为交易在发布的区块中交易的序号。
每笔交易完成后形成一个收据,用于记录交易的相关信息与执行结果,其数据结构也为MPT,其键值为交易在发布的区块中交易的序号,与交易树中的节点一一对应,。由于ETH智能合约执行过程比较复杂,增加收据树有利于快速查询执行结果。
bloom filter可以比较高效的查找某个元素是否包含在比较大的集合之内。直观的说,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。
算法:
- 首先需要k个hash函数,每个函数可以把key散列成为1个整数
- 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
- 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
- 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。
在查找某一交易时可快速过滤掉大量无关的区块
header
// Header represents a block header in thr Ethereum blockchain.
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner" gencodec:"required"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time *big.Int `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
Nonce BlockNonce `json:"nonce" gencodec:"required"`
}
block
// Block represents an entire block in the Ethereum blockchain.
type Block struct {
header *Header //区块头
uncles []*Header //叔块
transactions Transactions //区块打包的一批交易数据
// caches
hash atomic.Value
size atomic.Value
// Td is used by package core to store the total difficulty
// of the chain up to and including the block.
td *big.Int //总难度值
// These fields are used by package eth to track
// inter-peer block relay.
ReceivedAt time.Time
ReceivedFrom interface{}
}
extblock
// "external" block encoding. used for eth protocol, etc.
type extblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
}
extblock为真正发布的区块信息,即为block结构的前三项。
新区块发布
多个区块的状态树共享节点,每次发布新区块,MPT树中部分节点状态会改变,但改变并非在原地修改,而是新建一些分支,保留原本状态。当仅仅有新发生改变的节点才需要修改,其他未修改节点直接指向前一个区块中的对应节点。而交易树与收据树只将当前区块内发布的交易组织起来,如图所示:
由于以太坊中出块时间15s左右,会产生很多的分叉,保持历史记录的一个好处是,当某些分叉需要回滚时可以更好的查看历史记录。
ETH为一个交易驱动的状态机,其状态为状态树中账户的状态,通过执行交易树的交易,可驱动系统由当前状态转移到下一个状态,其状态转移时确定性的,即通过给定的当前状态和交易,能确定性的转移到下一个状态。
在大三的时候,一直就想搭建属于自己的一个博客,但由于各种原因,最终都不了了...
目录 读者基础 ?微服务架构梳理 https://www.coder4.com/homs_online/ ? ? 读者...
本文实例为大家分享了vue实现按钮切换图片的具体代码,供大家参考,具体内容如下...
今天看到个不错的网页播放器,感觉不错,大家可以测试 我写的一个播放器网页: ...
本文实例为大家分享了javascript实现倒计时提示框的具体代码,供大家参考,具体...
这5个PHP编程中的不良习惯,一定要改掉 PHP世界上最好的语言! 测试循环前数组是...
由于固态驱动器(SSD)的速度比传统的硬盘驱动器(HDD)快得多,并且价格越来越便宜...
MFC项目在vs2017编译正常无报错,但是升级vs2019后一打开项目就报如下错误。 项...
首先到这里下载其源码。里面东西挺多的,我们基本上可以把它放到两个文件夹就是...
目录 1. C语言文件接口(库函数) 1.1 fopen 1.2 fclose 1.3 fread 1.4 fwrite 1.5...