没有合适的资源?快使用搜索试试~ 我知道了~
首页以太坊智能合约虚拟机(EVM)原理与实现
以太坊 EVM原理与实现 以太坊底层通过EVM模块支持合约的执行与调用,调用时根据合约地址获取到代码,生成环境后载入到EVM中运行。通常智能合约的开发流程是用solidlity编写逻辑代码,再通过编译器编译元数据,最后再发布到以太坊上。 代码结构 . ├── analysis.go //跳转目标判定 ├── common.go ├── contract.go //合约数据结构 ├── contracts.go //预编译好的合约 ├── errors.go ├── evm.go //执行器 对外提
资源详情
资源评论
资源推荐
以太坊智能合约虚拟机以太坊智能合约虚拟机(EVM)原理与实现原理与实现
以太坊以太坊 EVM原理与实现原理与实现
以太坊底层通过EVM模块支持合约的执行与调用,调用时根据合约地址获取到代码,生成环境后载入到EVM中运行。通常智能合约的开发流程
是用solidlity编写逻辑代码,再通过编译器编译元数据,最后再发布到以太坊上。
代码结构
.
├── analysis.go //跳转目标判定
├── common.go
├── contract.go //合约数据结构
├── contracts.go //预编译好的合约
├── errors.go
├── evm.go //执行器 对外提供一些外部接口
├── gas.go //call gas花费计算 一级指令耗费gas级别
├── gas_table.go //指令耗费计算函数表
├── gen_structlog.go
├── instructions.go //指令操作
├── interface.go
├── interpreter.go //解释器 调用核心
├── intpool.go //int值池
├── int_pool_verifier_empty.go
├── int_pool_verifier.go
├── jump_table.go //指令和指令操作(操作,花费,验证)对应表
├── logger.go //状态日志
├── memory.go //EVM 内存
├── memory_table.go //EVM 内存操作表 主要衡量操作所需内存大小
├── noop.go
├── opcodes.go //Op指令 以及一些对应关系
├── runtime
│ ├── env.go //执行环境
│ ├── fuzz.go
│ └── runtime.go //运行接口 测试使用
├── stack.go //栈
└── stack_table.go //栈验证
指令
OpCode
文件opcodes.go中定义了所有的OpCode,该值是一个byte,合约编译出来的bytecode中,一个OpCode就是上面的一位。opcodes按功能分为
9组(运算相关,块操作,加密相关等)。
//算数相关
const (
// 0x0 range - arithmetic ops
STOP OpCode = iota
ADD
MUL
SUB
DIV
SDIV
MOD
SMOD
ADDMOD
MULMOD
EXP
SIGNEXTEND
)
Instruction
文件jump.table.go定义了四种指令集合,每个集合实质上是个256长度的数组,名字翻译过来是(荒地,农庄,拜占庭,君士坦丁堡)估计是
对应了EVM的四个发展阶段。指令集向前兼容。
frontierInstructionSet = NewFrontierInstructionSet()
homesteadInstructionSet = NewHomesteadInstructionSet()
byzantiumInstructionSet = NewByzantiumInstructionSet()
constantinopleInstructionSet = NewConstantinopleInstructionSet()
具体每条指令结构如下,字段意思见注释。
type operation struct {
//对应的操作函数
execute executionFunc
// 操作对应的gas消耗
gasCost gasFunc
// 栈深度验证
validateStack stackValidationFunc
// 操作所需空间
memorySize memorySizeFunc
halts bool // 运算中止
jumps bool // 跳转(for)
writes bool // 是否写入
valid bool // 操作是否有效
reverts bool // 出错回滚
returns bool // 返回
}
按下面的ADD指令为例
定义
ADD: {
execute: opAdd,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
},
操作
不同的操作有所不同,操作对象根据指令不同可能影响栈,内存,statedb。
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
//弹出一个值,取出一个值(这个值依旧保存在栈上面,运算结束后这个值就改变成结果值)
x, y := stack.pop(), stack.peek()
//加运算
math.U256(y.Add(x, y))
//数值缓存
evm.interpreter.intPool.put(x)
return nil, nil
}
gas花费
不同的运算有不同的初始值和对应的运算方法,具体的方法都定义在gas_table里面。 按加法的为例,一次加操作固定耗费为3。
//固定耗费
func constGasFunc(gas uint64) gasFunc {
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gas, nil
}
}
除此之外还有两个定义会影响gas的计算,通常作为量化的一个单位。
//file go-ethereum/core/vm/gas.go
const (
GasQuickStep uint64 = 2
GasFastestStep uint64 = 3
GasFastStep uint64 = 5
GasMidStep uint64 = 8
GasSlowStep uint64 = 10
GasExtStep uint64 = 20
GasReturn uint64 = 0
GasStop uint64 = 0
GasContractByte uint64 = 200
)
//file go-ethereum/params/gas_table.go
type GasTable struct {
ExtcodeSize uint64
ExtcodeCopy uint64
Balance uint64
SLoad uint64
Calls uint64
Suicide uint64
ExpByte uint64
// CreateBySuicide occurs when the
// refunded account is one that does
// not exist. This logic is similar
// to call. May be left nil. Nil means
// not charged.
CreateBySuicide uint64
}
memorySize
因为加操作不需要申请内存因而memorySize为默认值0。
栈验证
先验证栈上的操作数够不够,再验证栈是否超出最大限制,加法在这里仅需验证其参数够不够,运算之后栈是要减一的。
func makeStackFunc(pop, push int) stackValidationFunc {
return func(stack *Stack) error {
//深度验证
if err := stack.require(pop); err != nil {
return err
}
//最大值验证
//StackLimit uint64 = 1024
if stack.len()+push-pop > int(params.StackLimit) {
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
}
return nil
}
}
智能合约
合约是EVM智能合约的存储单位也是解释器执行的基本单位,包含了代码,调用人,所有人,gas相关的信息.
type Contract struct {
// CallerAddress is the result of the caller which initialised this
// contract. However when the "call method" is delegated this value
// needs to be initialised to that of the caller's caller.
CallerAddress common.Address
caller ContractRef
self ContractRef
jumpdests destinations // result of JUMPDEST analysis.
Code []byte
CodeHash common.Hash
CodeAddr *common.Address
Input []byte
Gas uint64
value *big.Int
Args []byte
DelegateCall bool
}
EVM原生预编译了一批合约,定义在contracts.go里面。主要用于加密操作。
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
// contracts used in the Byzantium release.
var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256Add{},
common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
common.BytesToAddress([]byte{8}): &bn256Pairing{},
}
执行机
栈
EVM中栈用于保存操作数,每个操作数的类型是big.int,这就是网上很多人说EVM是256位虚拟机的原因。执行opcode的时候,从上往下弹出操
作数,作为操作的参数。
type Stack struct {
data []*big.Int
}
func (st *Stack) push(d *big.Int) {
剩余10页未读,继续阅读
weixin_38720256
- 粉丝: 4
- 资源: 947
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- stc12c5a60s2 例程
- Android通过全局变量传递数据
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论5