【源码阅读】EVMⅢ

参考[link](https://blog.csdn.net/weixin_43563956/article/details/127725385
大致流程如下:
编写合约 > 生成abi > 解析abi得出指令集 > 指令通过opcode来映射成操作码集 > 生成一个operation

以太坊虚拟机的工作流程:
由solidity语言编写的智能合约,通过编译器编译成bytecode,之后发到以太坊上,以太坊底层通过evm模块支持合约的执行和调用,调用时根据合约获取代码,即合约的字节码,生成环境后载入到 EVM 执行。

1、操作码opcodes.go

合约编译出来的bytecode中,一个OpCode就是上面的一位。opcodes按功能分为9组,以第一位十六进制数来分类,例如0x1x,0x2x。

opCodeRange 对应操作
0x0 arithmetic ops算数操作
0x10 comparison ops比较操作
0x20 crypto加密操作
0x30 closure state状态闭包
0x40 block operations区块操作
0x50 ‘storage’ and execution存储和执行操作
0x60 pushes压栈操作
0x80 dups克隆操作
0x90 swaps交换操作
0xa0 logging ops日志操作
0xf0 closures闭包

2、合约contract.go

NewContract函数构造了新的合约,且如果是被合约调用,则复用该合约的 jumpdests。
validJumpdest函数用于验证给定的目标地址是否为有效的跳转目标。通过获取目标地址对应的操作码,判断是否为JUMPDEST类型。如果不是,则返回false,表示无效的跳转目标。调用c.isCode(udest)方法来进一步验证目标地址是否为有效的代码位置。如果是有效的代码位置,则返回true,表示有效的跳转目标;否则返回false

func (c *Contract) validJumpdest(dest *uint256.Int) bool {
	udest, overflow := dest.Uint64WithOverflow()
	// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
	// Don't bother checking for JUMPDEST in that case.
	if overflow || udest >= uint64(len(c.Code)) {
		return false
	}
	// Only JUMPDESTs allowed for destinations
	if OpCode(c.Code[udest]) != JUMPDEST {
		return false
	}
	return c.isCode(udest)
}

isCode函数判断给定的地址是否为有效的代码段。

3、jump_table.go

这是跳转表。在不同的以太坊版本中,会填充不一样的字段。对指令的真正的解释函数是在这个部分里面,而不是在解释器当中。
版本
其中frontierInstructionSet 这个对象包含了最基本的指令信息,其它是对这个集合的扩充,最全的一个是 constantinopleInstructionSet
operation使用的时候以指令的opcode值为索引。其中包括指令的解释执行函数、要消耗的gas值、栈空间大小和消耗的内存空间大小函数(在memory.go中实现)。

type operation struct {
	// execute is the operation function
	execute     executionFunc
	constantGas uint64
	dynamicGas  gasFunc
	// minStack tells how many stack items are required
	minStack int
	// maxStack specifies the max length the stack can have for this operation
	// to not overflow the stack.
	maxStack int

	// memorySize returns the memory size required for the operation
	memorySize memorySizeFunc
}

针对不同的jump-table有不同的函数,里面有不同的解释执行函数。
类型
在每一种类型中,实现不同的operation对象。
validate函数用来检查jump_table中的操作是否为空。

func validate(jt JumpTable) JumpTable {
	for i, op := range jt {
		if op == nil {
			panic(fmt.Sprintf("op %#x is not set", i))
		}
		if op.memorySize != nil && op.dynamicGas == nil {
			panic(fmt.Sprintf("op %v has dynamic memory but not dynamic gas", OpCode(i).String()))
		}
	}
	return jt
}

4、其它文件

gas.go和gas_table.go
这两个文件是用来计算所消耗的gas值,在具体的gas_table.go文件中,针对不同的操作有不同的函数来进行不同的计算。例如
例子
contracts,go文件用于存放预编译好的合约
common.go用于存放一些常用的工具方法

相关推荐

  1. 阅读evm

    2024-03-19 23:04:04       19 阅读
  2. FutureTask阅读

    2024-03-19 23:04:04       41 阅读
  3. kubelet阅读

    2024-03-19 23:04:04       20 阅读
  4. Milvus部分阅读

    2024-03-19 23:04:04       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-19 23:04:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-19 23:04:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-19 23:04:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-19 23:04:04       20 阅读

热门阅读

  1. 网页的制作

    2024-03-19 23:04:04       19 阅读
  2. 关于我的经历

    2024-03-19 23:04:04       22 阅读
  3. 【笔记】Linux常用命令

    2024-03-19 23:04:04       17 阅读
  4. PHP使用AES进行加解密

    2024-03-19 23:04:04       19 阅读
  5. 面试宝典:MySQL 索引优化

    2024-03-19 23:04:04       22 阅读
  6. 杂题——1187: 假币问题

    2024-03-19 23:04:04       23 阅读
  7. js iframe获取documen中的对象为空问题

    2024-03-19 23:04:04       18 阅读
  8. 计算机网络技术基础知识

    2024-03-19 23:04:04       20 阅读
  9. el-input添加keyup事件无响应

    2024-03-19 23:04:04       18 阅读
  10. 掘根宝典之c++标识符,命名

    2024-03-19 23:04:04       20 阅读