Evm7种重要指令的实现原理:

Evm的所有指令定义都在core/vm/jump_table.go里实现的,而每个指令对应的操作函数都是在core/vm/instructions.go里实现的。

如果一个节点并发调用智能合约,那么对memory的操作是否有线程安全问题。不会,因为每执行一个交易,都会创建一个新的evm对象。只有最终写入statedb的数据会有线程安全问题。

基本原理:一个指令占一个字节,也就是8为,16进制从0x01到0xff,10进制从1到255。最多255个指令,如果加上0的话,就256个指令。evm执行指令的主要载体是栈。

栈里的dup函数实现把栈上的某个值存入intpool中。

1.Mload和Mstore指令( 这里的m是memory的意思)

mload:花费32gas*数据大小,用途:取出栈顶的元素作为key,从memory中取出该key对应的value,存入initpoll中最新元素,并且把该值压入栈中。

Mstore:取出栈上的最新的两个数据,一个作为key,一个作为value,写入memory,并且存入initpoll中。initpoll也是一个栈的结构

func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {offset := stack.pop()val := interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))stack.push(val)interpreter.intPool.put(offset)return nil, nil}func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {// pop value of the stackmStart, val := stack.pop(), stack.pop()memory.Set32(mStart.Uint64(), val)interpreter.intPool.put(mStart, val)return nil, nil}// intPool is a pool of big integers that// can be reused for all big.Int operations.type intPool struct {pool *Stack}

2.sload和sstore指令( 这里的s是statedb的意思)

sload:从statedb中取出合约地址下面的某个key对应的value值,存入栈的最新元素里。sload固定是200gas

Sstore:从栈中取中两个值作为key和value,然后在statedb中存入刚才取出的key和value,并且在initpool中放入该value。

func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {loc := stack.peek()val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))loc.SetBytes(val.Bytes())return nil, nil}func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {loc := common.BigToHash(stack.pop())val := stack.pop()interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))interpreter.intPool.put(val)return nil, nil}

3.push1,push2… push32指令集,对应调用的是makePush(1,1)…makePush(32,32) 。gas费用都是3

实现的功能是:从字节指令代码数据中取出从pc计数器到x个指令出来,压入栈中。x为1到32。

// make push instruction functionfunc makePush(size uint64, pushByteSize int) executionFunc {return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {codeLen := len(contract.Code)startMin := codeLenif int(*pc+1) < startMin {startMin = int(*pc + 1)}endMin := codeLenif startMin+pushByteSize < endMin {endMin = startMin + pushByteSize}integer := interpreter.intPool.get()stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize)))*pc += sizereturn nil, nil}}

4.dup1,dup2… dup16指令,对应调用的是makeDup(1)…makeDup(16) 。gas费用都是3

dump是转存的意思,主要实现的是把栈中的某个元素压入栈顶

具体实现的功能是:从栈顶开始算起,把栈上第x个元素存入intpool的栈顶,并且把该元素也存入栈的栈顶。

// make dup instruction functionfunc makeDup(size int64) executionFunc {return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {stack.dup(interpreter.intPool, int(size))return nil, nil}}func (st *Stack) dup(pool *intPool, n int) {st.push(pool.get().Set(st.data[st.len()-n]))}

5.swap1,swap2… swap16指令,对应调用的是makeSwap(1)…makeSwap(16) 。gas费用都是3

实现的功能是:把栈上的第x个元素和栈顶元素进行交换

// make swap instruction functionfunc makeSwap(size int64) executionFunc {// switch n + 1 otherwise n would be swapped with nsize++return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {stack.swap(int(size))return nil, nil}}func (st *Stack) swap(n int) {st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]}

6.log1,log2… log4指令,对应调用的是makeLog(1)…makeLog(4) 。gas费用是 8gas* 字节大小

实现的功能是:根据栈的前两个元素作为key和size,从内存里取出相应的数据,存入statedb的journal(日志)里。1,2,3,4代表的是日志的主题,一次最多可以存入4个主题。

如果有多个主题,取数据的时候从data里切分出不同主题的数据。

// make log instruction functionfunc makeLog(size int) executionFunc {return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {topics := make([]common.Hash, size)mStart, mSize := stack.pop(), stack.pop()for i := 0; i < size; i++ {topics[i] = common.BigToHash(stack.pop())}d := memory.Get(mStart.Int64(), mSize.Int64())interpreter.evm.StateDB.AddLog(&types.Log{Address: contract.Address(),Topics:  topics,Data:    d,// This is a non-consensus field, but assigned here because// core/state doesn't know the current block number.BlockNumber: interpreter.evm.BlockNumber.Uint64(),})interpreter.intPool.put(mStart, mSize)return nil, nil}}func (self *StateDB) AddLog(log *types.Log) {self.journal.append(addLogChange{txhash: self.thash})log.TxHash = self.thashlog.BlockHash = self.bhashlog.TxIndex = uint(self.txIndex)log.Index = self.logSizeself.logs[self.thash] = append(self.logs[self.thash], log)self.logSize++}

7.create,call,callcode,return

(1) Create指令实现的是创建合约,将会调用

res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value)

(2)call指令实现的是调用合约,将会调用

 ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value)

(3)callcode指令实现的是一个合约调用其他合约,最终将会调用callcode方法,和call方法最大不同的是执行合约的上下文是调用者,而不是将要执行的合约。

ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value)

callcode一般发生在定义了多个合约,其中一个合约调用了其他合约的方法。

(4)return指令实现的是:从内存中,以栈顶的前两个元素作为偏移量和size,取出相应的数据放入intpool中,并返回数据

 func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {offset, size := stack.pop(), stack.pop()ret := memory.GetPtr(offset.Int64(), size.Int64())interpreter.intPool.put(offset, size)return ret, nil}

Evm7种重要指令的实现原理相关推荐

  1. Vue 3 中 v-if 和 v-show 指令实现的原理(源码分析)

    前言 又回到了经典的一句话:"知其然,而后使其然".相信大家对 Vue 提供 v-if 和 v-show 指令的使用以及对应场景应该都滚瓜烂熟了.但是,我想仍然会有很多同学对于 v ...

  2. Vue中常用的8种v指令

    Vue中常用的8种v指令 根据官网的介绍,指令 是带有 v- 前缀的特殊属性.通过指令来操作DOM元素 指令 功能 v-text="变量/表达式" 文本的设置 字符串变量+数字可以 ...

  3. Vue自定义指令介绍及原理

    Vue自定义指令 Vue指令: 在使用Vue框架进行前端开发时,我们经常会使用一些特殊指令来快速实现一些效果或功能. 常见指令如:v-bind.v-if (v-else).v-show.v-html等 ...

  4. 赵英时遥感原理分析和应用课件_细数5种停车场防砸车技术原理分析与应用

    原标题:细数5种停车场防砸车技术原理分析与应用 一.压力波防砸装置 也叫遇阻防砸,主要是安装遇阻返回装置,当道闸杆下落过程中接触到车辆或者行人(接触力度是可以调节的),装置道闸杆底下的橡胶条受到阻力, ...

  5. raid0 raid1 raid5 三种工作模式的工作原理及特点

    简述raid0 raid1 raid5 三种工作模式的工作原理及特点 RAID,可以把硬盘整合成一个大磁盘,还可以在大磁盘上再分区,放数据还有一个大功能,多块盘放在一起可以有冗余(备份).RAID整合 ...

  6. Vue-Router前端路由的两种模式、区别、原理?

    vue路由有⼏种模式?有什么区别?原理是什么? 一.vue路由有几种模式? 二.两者区别 三.原理 一.vue路由有几种模式? vue的路由模式⼀共有两种,分别是哈希和history 二.两者区别 哈 ...

  7. java鉴权_3种常用鉴权方法原理与实现

    学生一枚,作为学习和总结.如果有哪些不对的地方,还请指教 cookie 诞生 HTTP协议是无状态的协议.一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接. 为解决这个问 ...

  8. 6种肤色检测方法的原理及实现(opencv, C++)

    6种肤色检测方法的原理及实现(opencv, C++) Mr Qin 分类:机器视觉 个人专栏:图像处理 发布时间 2021.06.18 阅读数 2024 评论数 0 0 简介: 本博文首发csdn链 ...

  9. git缓冲区查看_git原理学习记录:从基本指令到背后原理,实现一个简单的git

    好家伙~ 实操可以考虑点击阅读原文跳转到博客地址,博客可以点超链接可能会方便一些. 一开始我还担心 git 的原理会不会很难懂,但在阅读了官方文档后我发现其实并不难懂,似乎可以动手实现一个简单的 gi ...

最新文章

  1. eclipse 和 google拼音输入法冲突问题
  2. 5G前夜 运营商如何实现网络创新?
  3. vmstat - Linux系统性能监控工具
  4. 用Alpha生成Trimp图的方法(python)
  5. 【量化投资】策略七(聚宽)
  6. 评《认知红利》 谢春霖著
  7. 张文宏又爆“金句”:上班开会,要和关系最差的人坐一起……
  8. 幕乔美化版音乐网站源码
  9. c语言二维数组 ppt,C语言二维数组与指针.ppt
  10. [BZOJ2850]巧克力王国
  11. Bend Labs弯曲传感器介绍
  12. 使用ollyodb破解AspriseOCR.dll
  13. 2012r2备域控服务器搭建,Windows Server 2012 R2域控制器部署
  14. w7计算机开机密码怎么设置,如何设置电脑开机密码,图文教你怎么设置开机密码(winxp/win7)...
  15. 洛谷:P哥的桶(线段树 + 线性基)
  16. /usr/bin/ld cannot find -lGL
  17. PDF如何删除页面?批量删除不连续页的方法
  18. 【anaconda】彻底解决windows下anaconda3占用C盘问题(改了envs、pkgs安装路径依旧占用C盘)
  19. 企业级项目分享:购物车模块(一)2021-06-08
  20. 字符表单验证与正则表单验证

热门文章

  1. input textarea 宽度设置100%不超出父元素
  2. 如何获取与下载ASF的源文件?
  3. 公有链七大超级难题:建立点对点的分享社区(二)
  4. DOM基础,classList属性提供的方法和属性,DOM中节点的操作,追加节点
  5. 关于fontawesome-webfont93e3.ttf加载不到的解决办法
  6. IIS网站报错targetFramework特性仅作用于目标.NET Framework4.0或更高版本
  7. 一种基于三维块匹配滤波(BM3D)算法的散斑噪声抑制的仿真与实例分析
  8. 3DLC系列之:图像窗口
  9. 写一个虚拟摄像头驱动3
  10. 洛谷P4933 大师