Evm7种重要指令的实现原理
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种重要指令的实现原理相关推荐
- Vue 3 中 v-if 和 v-show 指令实现的原理(源码分析)
前言 又回到了经典的一句话:"知其然,而后使其然".相信大家对 Vue 提供 v-if 和 v-show 指令的使用以及对应场景应该都滚瓜烂熟了.但是,我想仍然会有很多同学对于 v ...
- Vue中常用的8种v指令
Vue中常用的8种v指令 根据官网的介绍,指令 是带有 v- 前缀的特殊属性.通过指令来操作DOM元素 指令 功能 v-text="变量/表达式" 文本的设置 字符串变量+数字可以 ...
- Vue自定义指令介绍及原理
Vue自定义指令 Vue指令: 在使用Vue框架进行前端开发时,我们经常会使用一些特殊指令来快速实现一些效果或功能. 常见指令如:v-bind.v-if (v-else).v-show.v-html等 ...
- 赵英时遥感原理分析和应用课件_细数5种停车场防砸车技术原理分析与应用
原标题:细数5种停车场防砸车技术原理分析与应用 一.压力波防砸装置 也叫遇阻防砸,主要是安装遇阻返回装置,当道闸杆下落过程中接触到车辆或者行人(接触力度是可以调节的),装置道闸杆底下的橡胶条受到阻力, ...
- raid0 raid1 raid5 三种工作模式的工作原理及特点
简述raid0 raid1 raid5 三种工作模式的工作原理及特点 RAID,可以把硬盘整合成一个大磁盘,还可以在大磁盘上再分区,放数据还有一个大功能,多块盘放在一起可以有冗余(备份).RAID整合 ...
- Vue-Router前端路由的两种模式、区别、原理?
vue路由有⼏种模式?有什么区别?原理是什么? 一.vue路由有几种模式? 二.两者区别 三.原理 一.vue路由有几种模式? vue的路由模式⼀共有两种,分别是哈希和history 二.两者区别 哈 ...
- java鉴权_3种常用鉴权方法原理与实现
学生一枚,作为学习和总结.如果有哪些不对的地方,还请指教 cookie 诞生 HTTP协议是无状态的协议.一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接. 为解决这个问 ...
- 6种肤色检测方法的原理及实现(opencv, C++)
6种肤色检测方法的原理及实现(opencv, C++) Mr Qin 分类:机器视觉 个人专栏:图像处理 发布时间 2021.06.18 阅读数 2024 评论数 0 0 简介: 本博文首发csdn链 ...
- git缓冲区查看_git原理学习记录:从基本指令到背后原理,实现一个简单的git
好家伙~ 实操可以考虑点击阅读原文跳转到博客地址,博客可以点超链接可能会方便一些. 一开始我还担心 git 的原理会不会很难懂,但在阅读了官方文档后我发现其实并不难懂,似乎可以动手实现一个简单的 gi ...
最新文章
- eclipse 和 google拼音输入法冲突问题
- 5G前夜 运营商如何实现网络创新?
- vmstat - Linux系统性能监控工具
- 用Alpha生成Trimp图的方法(python)
- 【量化投资】策略七(聚宽)
- 评《认知红利》 谢春霖著
- 张文宏又爆“金句”:上班开会,要和关系最差的人坐一起……
- 幕乔美化版音乐网站源码
- c语言二维数组 ppt,C语言二维数组与指针.ppt
- [BZOJ2850]巧克力王国
- Bend Labs弯曲传感器介绍
- 使用ollyodb破解AspriseOCR.dll
- 2012r2备域控服务器搭建,Windows Server 2012 R2域控制器部署
- w7计算机开机密码怎么设置,如何设置电脑开机密码,图文教你怎么设置开机密码(winxp/win7)...
- 洛谷:P哥的桶(线段树 + 线性基)
- /usr/bin/ld cannot find -lGL
- PDF如何删除页面?批量删除不连续页的方法
- 【anaconda】彻底解决windows下anaconda3占用C盘问题(改了envs、pkgs安装路径依旧占用C盘)
- 企业级项目分享:购物车模块(一)2021-06-08
- 字符表单验证与正则表单验证
热门文章
- input textarea 宽度设置100%不超出父元素
- 如何获取与下载ASF的源文件?
- 公有链七大超级难题:建立点对点的分享社区(二)
- DOM基础,classList属性提供的方法和属性,DOM中节点的操作,追加节点
- 关于fontawesome-webfont93e3.ttf加载不到的解决办法
- IIS网站报错targetFramework特性仅作用于目标.NET Framework4.0或更高版本
- 一种基于三维块匹配滤波(BM3D)算法的散斑噪声抑制的仿真与实例分析
- 3DLC系列之:图像窗口
- 写一个虚拟摄像头驱动3
- 洛谷P4933 大师