EVM分析

EVM不能被重用,非线程安全

Context结构体:为EVM提供辅助信息。一旦提供,不应更改。

  1. // Context 为EVM提供辅助信息。一旦提供,不应更改。
  2. type Context struct {
  3. // CanTransfer 返回 账户是否拥有足够的以太币以执行转账 CanTransfer CanTransferFunc
  4. // Transfer 转账函数,将以太币从一个账户转到另一个账户
  5. Transfer TransferFunc
  6. // GetHash 返回n对应的哈希
  7. GetHash GetHashFunc
  8. // Message information
  9. Origin common.Address // Provides information for ORIGIN
  10. GasPrice *big.Int // Provides information for GASPRICE
  11. // Block information
  12. Coinbase common.Address // Provides information for COINBASE
  13. GasLimit uint64 // Provides information for GASLIMIT
  14. BlockNumber *big.Int // Provides information for NUMBER
  15. Time *big.Int // Provides information for TIME
  16. Difficulty *big.Int // Provides information for DIFFICULTY
  17. }

state_processor.Process开始执行交易处理,就是在那里为入口进入到evm的执行的,具体见core-state-process-analysis.md

EVM的实现

以太坊的EVM整个完全是自己实现的,能够直接执行Solidity字节码,没有使用任何第三方运行时。
运行过程是同步的,没有启用go协程。

  1. evm最终是调用Interpreter运行字节码;
  2. Interpreter.go实现运行处理;解析出操作码后,通过JumpTable获取操作码对应的函数运行,并维护pc计数器、处理返回值等;
  3. jump_table.go定义了操作码的跳转映射;
  4. instructions.go实现每一个操作码的具体的处理;
  5. opcodes.go中定义了操作码常量

对于EVM的测试,以太坊将测试代码放在了core\vm\runtime目录下,提供了供测试用的运行时及测试用例。 测试用例的示例如:

  1. func TestExecute(t *testing.T) {
  2. ret, _, err := Execute([]byte{
  3. byte(vm.PUSH1), 10,
  4. byte(vm.PUSH1), 0,
  5. byte(vm.MSTORE),
  6. byte(vm.PUSH1), 32,
  7. byte(vm.PUSH1), 0,
  8. byte(vm.RETURN),
  9. }, nil, nil)
  10. if err != nil {
  11. t.Fatal("didn't expect error", err)
  12. }
  13. num := new(big.Int).SetBytes(ret)
  14. if num.Cmp(big.NewInt(10)) != 0 {
  15. t.Error("Expected 10, got", num)
  16. }
  17. }

合约数据的存储

参考:分享 | 来自10年经验的大咖对以太坊数据存储的思考与解读