账户结构
以太坊基本数据单元(Metadata):
Account
不同于Bitcoin 基于 UTXO 的 Blockchain/Ledger 系统,Ethereum是以 Account/State 模型为核心的基于交易驱动的状态机(Transaction-based State Machine),我们常说的世界状态(State),其根本是反应了某一账户(Account)在某一时刻下的属性。
其中,State 对应的基本数据结构,称为 stateObject(内部维护,不可导出)。当 stateObject 的值由Transaction 的执行而触发数据更新/删除/创建而发生了变化时,我们称为状态转移。
即stateObject 的状态从当前的 State 转移到另一个 State
1)EOA账户
的创建:包含本地创建和链上注册(stateDB进行链上账户管理),入口函数NewAccount
passphrase
入参仅用于加密本地保存私钥的Keystore文件(使用对称加密算法来加密私钥生成),与生成账户的私钥、地址的生成无关。私钥泄露、助记词泄露、Keystore+密码泄露都会导致账户控制权丢失
账号创建:
这里实际上只进行了ecdsa计算和keystore存储,实际账户在以太坊世界状态中存储,只需要等待有相关联的Transaction发生,若不存在就会自动通过
newObject() //core/state/state_object.go
创建算法生成过程:
第一步:32字节,私钥 (private key)
伪随机数产生的256bit私钥示例(256bit)
18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725
第二步:64字节,公钥 (public key)
采用椭圆曲线数字签名算法ECDSA-secp256k1将私钥(32字节)映射成公钥(算上前缀65字节)
(前缀04+X公钥+Y公钥),公钥是椭圆曲线上的一点,故有
(X, Y)
04
50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6
(去掉
04
前缀)计算公钥的 Keccak-256 哈希值(32bytes):fc12ad814631ba689f7abe67 1016f75c54c607f082ae6b0881fac0abeda21781
第三步:20字节,地址 (address)
取上一步hash值的后20bytes,加上前缀0x,即以太坊地址:
0x 1016f75c54c607f082ae6b0881fac0abeda21781
比特币地址生成过程,在上述第三步之后还有其他操作:
计算RIPEMD-160哈希: 对上一步得到的SHA-256哈希值执行RIPEMD-160哈希运算。这将会得到一个20字节的值。
添加地址版本前缀: 为了区分主网和测试网的地址,会在RIPEMD-160哈希的前面添加一个字节的版本。例如,比特币主网地址的版本前缀是0x00。
计算双重SHA-256哈希校验和: 对前一步得到的结果执行两次SHA-256哈希,并取哈希的前4个字节作为校验和。
组合并进行Base58编码: 将前缀、RIPEMD-160哈希和校验和组合在一起,然后使用Base58编码得到比特币地址。
签名Sign(65字节)
虽然以太坊签名算法也采样了 secp256k1(与比特币相同) ,但是在签名的格式上有所差异,比特币在 BIP66中对签名数据格式采用严格的DER(Distinguished Encoding Rules,可辨别编码规则)编码格式。
ECDSA.spec256k1椭圆曲线签名算法
使用公钥叫加密数据,使用私钥叫签名,签名通过公钥验签
以太坊的签名格式是r+s+v
。r
和s
是ECDSA签名的原始输出,而末尾的一个字节为恢复id(recovery id简称recid) ,在以太坊中用v
表示,是签名的最后一个字节。 65 字节的序列:r 有 32 个字节,s 有 32 个字节,v 有一个字节。
recid称为恢复标识符。因为我们使用的是椭圆曲线算法,仅凭 r 和 s 可计算出曲线上的多个点,因此会恢复出两个不同的公钥(及其对应地址)。v 会告诉我们应该使用这些点中的哪一个(也可以理解为查找次数)。在大多数实现中,v =recid,在内部只是 0 或 1。
在以太坊中区块中的数据需要签名的仅有交易Transaction
注意:EIP-155后,在交易签名时,v值不再是recid, 而是 v = recid+ chainID*2+ 35(旧为v = recid+27)
2)CA账户
Storage是一个 key 和 value 都是common.Hash
类型的 map 结构,account code 实际存储位置,与EOA账户相比合约账户额外保存了一个存储层(Storage)用于存储合约代码中持久化的变量的数据
对应solidity智能合约的状态变量
Storage 层的基本组成单元称为槽 (Slot)。若干个 Slot 按照Stack的方式顺序集合在一起就构造成了 Storage 层。每个 Slot 的大小是 256 bits(32 bytes)的数据。
Slot 作为基本的存储单元,通过地址索引的方式被上层函数访问。Slot的地址索引的长度同样是32 bytes(256 bits),寻址空间从 0x0000000000000000000000000000000000000000000000000000000000000000
到 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
。因此在理论状态下,一个 合约 可以最多保存 2^256 bytes (0 - 2^256-1) 的数据,这是个相当大的数字。
可观测宇宙中约有2^272个原子
为了更好的管理数据,Contract 同样使用 MPT(会对slot[key] = value
中key值(即slot position)进行hash存储) 作为索引树(Account stroage trie)来管理 Storage 层的Slot。
值得注意的是,合约 Storage 层的数据并不会跟随交易一起,被打包进入 Block 中。只有Account storage Trie root 被保存在 account state 结构体中,而account state构成世界状态state。
因此,当某个 Contract 的 Storage 层的数据发生变化时,任一叶子结点account state的改变会使account storage tire root改变,进而使世界状态state其中的一个叶子结点发生改变,进而改变state root,从而记录到Chain链上(包含在block header中)。
Storage 的数据读取和修改,具体是在执行相关 Transaction 的时候,通过 EVM opcodes中sload和sstore来实际执行的
Last updated