runtime

package
v0.0.0-...-0abe6a2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 19, 2019 License: BSD-3-Clause Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// CREATE 过程调用
	CREATE OpCode = 0xf0 + iota
	// CALL op
	CALL
	// CALLCODE op
	CALLCODE
	// RETURN op
	RETURN
	// DELEGATECALL op
	DELEGATECALL
	// STATICCALL  op
	STATICCALL = 0xfa

	// REVERT op
	REVERT = 0xfd
	// SELFDESTRUCT  op
	SELFDESTRUCT = 0xff
)

Variables

View Source
var (
	// ConstantinopleInstructionSet 对应EVM不同版本的指令集,从上往下,从旧版本到新版本,
	// 新版本包含旧版本的指令集(目前直接使用康士坦丁堡指令集)
	ConstantinopleInstructionSet = NewConstantinopleInstructionSet()
)
View Source
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{},
}

PrecompiledContractsByzantium chain33平台支持君士坦丁堡版本支持的所有预编译合约指令,并从此版本开始同步支持EVM黄皮书中的新增指令; 保存拜占庭版本支持的所有预编译合约(包括之前版本的合约); 后面如果有硬分叉,需要在此处考虑分叉逻辑,根据区块高度分别处理; 下面的8个预编译指令,直接引用go-ethereum中的EVM实现

Functions

func RunPrecompiledContract

func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error)

RunPrecompiledContract 调用预编译的合约逻辑并返回结果

Types

type AccountRef

type AccountRef common.Address

AccountRef 账户对象引用 (实现了合约对象引用ContractRef接口) 因为在合约调用过程中,调用者有可能是外部账户,也有可能是合约账户,所以两者的结构是互通的

func (AccountRef) Address

func (ar AccountRef) Address() common.Address

Address 将账户引用转换为普通地址对象

type CanTransferFunc

type CanTransferFunc func(state.EVMStateDB, common.Address, common.Address, uint64) bool

CanTransferFunc 检查制定账户是否有足够的金额进行转账

type Config

type Config struct {
	// Debug 调试开关
	Debug bool
	// Tracer 记录操作日志
	Tracer Tracer
	// NoRecursion 不允许使用Call, CallCode, DelegateCall
	NoRecursion bool
	// EnablePreimageRecording SHA3/keccak 操作时是否保存数据
	EnablePreimageRecording bool
	// JumpTable 指令跳转表
	JumpTable [256]Operation
}

Config 解释器的配置模型

type Context

type Context struct {

	// CanTransfer 是否可转账
	CanTransfer CanTransferFunc
	// Transfer 转账
	Transfer TransferFunc
	// GetHash 获取区块哈希
	GetHash GetHashFunc

	// Origin 指令返回数据, 合约调用者地址
	Origin common.Address
	// GasPrice 指令返回数据
	GasPrice uint32

	// Coinbase 指令, 区块打包者地址
	Coinbase *common.Address
	// GasLimit 指令,当前交易的GasLimit
	GasLimit uint64

	// BlockNumber NUMBER 指令,当前区块高度
	BlockNumber *big.Int
	// Time 指令, 当前区块打包时间
	Time *big.Int
	// Difficulty 指令,当前区块难度
	Difficulty *big.Int
}

Context EVM操作辅助上下文 外部在构造EVM实例时传入,EVM实例构造完成后不允许修改

type Contract

type Contract struct {
	// CallerAddress 调用者地址,应该为外部账户的地址
	// 如果是通过合约再调用合约时,会从上级合约中获取调用者地址进行赋值
	CallerAddress common.Address

	// Jumpdests 存储跳转信息,供JUMP和JUMPI指令使用
	Jumpdests Destinations

	// Code合约代码
	Code []byte
	// CodeHash 代码哈希
	CodeHash common.Hash

	// CodeAddr 合约地址
	CodeAddr *common.Address
	// Input 输入参数
	Input []byte

	// Gas 此合约对象的可用Gas(合约执行过程中会修改此值)
	Gas uint64

	// DelegateCall 委托调用时,此属性会被设置为true
	DelegateCall bool
	// contains filtered or unexported fields
}

Contract 合约对象,它在内存中表示一个合约账户的代码即地址信息实体 每次合约调用都会创建一个新的合约对象

func NewContract

func NewContract(caller ContractRef, object ContractRef, value uint64, gas uint64) *Contract

NewContract 创建一个新的合约调用对象 不管合约是否存在,每次调用时都会新创建一个合约对象交给解释器执行,对象持有合约代码和合约地址

func (*Contract) Address

func (c *Contract) Address() common.Address

Address 返回上下文中合约自身的地址 注意,当合约通过CallCode调用时,这个地址并不是当前合约代码对应的地址,而是调用者的地址

func (*Contract) AsDelegate

func (c *Contract) AsDelegate() *Contract

AsDelegate 设置当前的合约对象为被委托调用 返回当前合约对象的指针,以便在多层调用链模式下使用

func (*Contract) Caller

func (c *Contract) Caller() common.Address

Caller 返回合约的调用者 如果当前合约为委托调用,则调用它的不是外部账户,而是合约账户,所以此时的caller为调用此合约的合约的caller 这个关系可以一直递归向上,直到定位到caller为外部账户地址

func (*Contract) GetByte

func (c *Contract) GetByte(n uint64) byte

GetByte 获取合约代码中制定位置的字节值

func (*Contract) GetOp

func (c *Contract) GetOp(n uint64) OpCode

GetOp 获取合约代码中制定位置的操作码

func (*Contract) SetCallCode

func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte)

SetCallCode 设置合约代码和代码哈希

func (*Contract) SetCode

func (c *Contract) SetCode(hash common.Hash, code []byte)

SetCode 设置合约代码内容

func (*Contract) UseGas

func (c *Contract) UseGas(gas uint64) (ok bool)

UseGas 从合约的可用gas中进行gas消费

func (*Contract) Value

func (c *Contract) Value() uint64

Value 合约包含转账逻辑时,转账的金额

type ContractRef

type ContractRef interface {
	Address() common.Address
}

ContractRef 合约对象引用

type Destinations

type Destinations map[common.Hash]bitvec

Destinations 存储合约以及代码对应的位向量对象 Key为代码哈希,Value为对应的合约代码的位向量 JUMPDEST指令会使用此对象进行跳转位置判断

func (Destinations) Has

func (d Destinations) Has(codehash common.Hash, code []byte, dest *big.Int) bool

Has 检查PC只想的代码是否存在JUMPDEST指令,并且跳转目标有效

type EVM

type EVM struct {
	// Context 链相关的一些辅助属性和操作方法
	Context
	// EVMStateDB 状态数据操作入口
	StateDB state.EVMStateDB

	// VMConfig 虚拟机配置属性信息
	VMConfig Config

	// Interpreter EVM指令解释器,生命周期同EVM
	Interpreter *Interpreter

	// CallGasTemp 此属性用于临时存储计算出来的Gas消耗值
	// 在指令执行时,会调用指令的gasCost方法,计算出此指令需要消耗的Gas,并存放在此临时属性中
	// 然后在执行opCall时,从此属性获取消耗的Gas值
	CallGasTemp uint64
	// contains filtered or unexported fields
}

EVM 结构对象及其提供的操作方法,用于进行满足以太坊EVM黄皮书规范定义的智能合约代码的创建和执行 合约执行过程中会修改外部状态数据(数据操作通过外部注入) 在合约代码执行过程中发生的任何错误,都将会导致对状态数据的修改被回滚,并且依然消耗掉剩余的Gas 此对象为每个交易创建一个实例,其操作非线程安全

func NewEVM

func NewEVM(ctx Context, statedb state.EVMStateDB, vmConfig Config) *EVM

NewEVM 创建一个新的EVM实例对象 在同一个节点中,一个EVM实例对象只服务于一个交易执行的生命周期

func (*EVM) Call

func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value uint64) (ret []byte, snapshot int, leftOverGas uint64, err error)

Call 此方法提供合约外部调用入口 根据合约地址调用已经存在的合约,input为合约调用参数 合约调用逻辑支持在合约调用的同时进行向合约转账的操作

func (*EVM) CallCode

func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value uint64) (ret []byte, leftOverGas uint64, err error)

CallCode 合约内部调用合约的入口 执行逻辑同Call方法,但是有以下几点不同: 在创建合约对象时,合约对象的上下文地址(合约对象的self属性)被设置为caller的地址

func (*EVM) Cancel

func (evm *EVM) Cancel()

Cancel 调用此操作会在任意时刻取消此EVM的解释运行逻辑,支持重复调用

func (*EVM) Create

func (evm *EVM) Create(caller ContractRef, contractAddr common.Address, code []byte, gas uint64, execName, alias, abi string) (ret []byte, snapshot int, leftOverGas uint64, err error)

Create 此方法提供合约外部创建入口; 使用传入的部署代码创建新的合约; 目前chain33为了保证账户安全,不允许合约中涉及到外部账户的转账操作, 所以,本步骤不接收转账金额参数

func (*EVM) DelegateCall

func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)

DelegateCall 合约内部调用合约的入口 不支持向合约转账 和CallCode不同的是,它会把合约的外部调用地址设置成caller的caller

func (*EVM) GasTable

func (evm *EVM) GasTable(num *big.Int) gas.Table

GasTable 返回不同操作消耗的Gas定价表 接收区块高度作为参数,方便以后在这里作分叉处理

func (*EVM) SetMaxCodeSize

func (evm *EVM) SetMaxCodeSize(maxCodeSize int)

SetMaxCodeSize 设置合约代码的最大支持长度

func (*EVM) StaticCall

func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)

StaticCall 合约内部调用合约的入口 不支持向合约转账 在合约逻辑中,可以指定其它的合约地址以及输入参数进行合约调用,但是,这种情况下禁止修改MemoryStateDB中的任何数据,否则执行会出错

type ExecutionFunc

type ExecutionFunc func(pc *uint64, env *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error)

ExecutionFunc 指令执行函数,每个操作指令对应一个实现,它实现了指令的具体操作逻辑

type GetHashFunc

type GetHashFunc func(uint64) common.Hash

GetHashFunc 获取制定高度区块的哈希 给 BLOCKHASH 指令使用

type Interpreter

type Interpreter struct {

	// IntPool 整数内存池
	IntPool *mm.IntPool

	// 合约执行返回的结果数据
	ReturnData []byte
	// contains filtered or unexported fields
}

Interpreter 解释器接结构定义

func NewInterpreter

func NewInterpreter(evm *EVM, cfg Config) *Interpreter

NewInterpreter 新创建一个解释器

func (*Interpreter) Run

func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error)

Run 合约代码的解释执行主逻辑 需要注意的是,如果返回执行出错,依然会扣除剩余的Gas (除非返回的是ErrExecutionReverted,这种情况下会保留剩余的Gas)

type JSONLogger

type JSONLogger struct {
	// contains filtered or unexported fields
}

JSONLogger 使用json格式打印日志

func NewJSONLogger

func NewJSONLogger(writer io.Writer) *JSONLogger

NewJSONLogger 创建新的日志记录器

func (*JSONLogger) CaptureEnd

func (logger *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error

CaptureEnd 结束记录

func (*JSONLogger) CaptureFault

func (logger *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error

CaptureFault 目前实现为空

func (*JSONLogger) CaptureStart

func (logger *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value uint64) error

CaptureStart 开始记录

func (*JSONLogger) CaptureState

func (logger *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error

CaptureState 输出当前虚拟机状态

type OpCode

type OpCode byte

OpCode EVM操作码定义,本质上就是一个字节,所以操作码最多只支持256个

const (
	// PUSH 压栈操作
	PUSH OpCode = 0xb0 + iota
	// DUP 操作
	DUP
	// SWAP 操作
	SWAP
)

unofficial opcodes used for parsing

const (
	// STOP 0x0 算术操作
	STOP OpCode = iota
	// ADD 操作
	ADD
	// MUL op
	MUL
	// SUB op
	SUB
	// DIV op
	DIV
	// SDIV op
	SDIV
	// MOD op
	MOD
	// SMOD op
	SMOD
	// ADDMOD op
	ADDMOD
	// MULMOD op
	MULMOD
	// EXP op
	EXP
	// SIGNEXTEND op
	SIGNEXTEND
)
const (
	// LT 比较、位操作
	LT OpCode = iota + 0x10
	// GT op
	GT
	// SLT op
	SLT
	// SGT op
	SGT
	// EQ op
	EQ
	// ISZERO op
	ISZERO
	// AND op
	AND
	// OR op
	OR
	// XOR op
	XOR
	// NOT op
	NOT
	// BYTE op
	BYTE
	// SHL op
	SHL
	// SHR op
	SHR
	// SAR op
	SAR

	// SHA3 op
	SHA3 = 0x20
)
const (
	// ADDRESS 0x30 合约数据操作
	ADDRESS OpCode = 0x30 + iota
	// BALANCE op
	BALANCE
	// ORIGIN op
	ORIGIN
	// CALLER op
	CALLER
	// CALLVALUE op
	CALLVALUE
	// CALLDATALOAD op
	CALLDATALOAD
	// CALLDATASIZE op
	CALLDATASIZE
	// CALLDATACOPY op
	CALLDATACOPY
	// CODESIZE op
	CODESIZE
	// CODECOPY op
	CODECOPY
	// GASPRICE op
	GASPRICE
	// EXTCODESIZE op
	EXTCODESIZE
	// EXTCODECOPY op
	EXTCODECOPY
	// RETURNDATASIZE op
	RETURNDATASIZE
	// RETURNDATACOPY op
	RETURNDATACOPY
)
const (
	// BLOCKHASH 0x40 区块相关操作
	BLOCKHASH OpCode = 0x40 + iota
	// COINBASE op
	COINBASE
	// TIMESTAMP op
	TIMESTAMP
	// NUMBER op
	NUMBER
	// DIFFICULTY op
	DIFFICULTY
	// GASLIMIT op
	GASLIMIT
)
const (
	// POP 0x50 存储相关操作
	POP OpCode = 0x50 + iota
	// MLOAD op
	MLOAD
	// MSTORE op
	MSTORE
	// MSTORE8 op
	MSTORE8
	// SLOAD op
	SLOAD
	// SSTORE op
	SSTORE
	// JUMP op
	JUMP
	// JUMPI op
	JUMPI
	// PC op
	PC
	// MSIZE op
	MSIZE
	// GAS op
	GAS
	// JUMPDEST op
	JUMPDEST
)
const (
	// PUSH1 0x60 栈操作
	PUSH1 OpCode = 0x60 + iota
	// PUSH2 op
	PUSH2
	// PUSH3 op
	PUSH3
	// PUSH4 op
	PUSH4
	// PUSH5 op
	PUSH5
	// PUSH6 op
	PUSH6
	// PUSH7 op
	PUSH7
	// PUSH8 op
	PUSH8
	// PUSH9 op
	PUSH9
	// PUSH10 op
	PUSH10
	// PUSH11 op
	PUSH11
	// PUSH12 op
	PUSH12
	// PUSH13 op
	PUSH13
	// PUSH14 op
	PUSH14
	// PUSH15 op
	PUSH15
	// PUSH16 op
	PUSH16
	// PUSH17 op
	PUSH17
	// PUSH18 op
	PUSH18
	// PUSH19 op
	PUSH19
	// PUSH20 op
	PUSH20
	// PUSH21 op
	PUSH21
	// PUSH22 op
	PUSH22
	// PUSH23 op
	PUSH23
	// PUSH24 op
	PUSH24
	// PUSH25 op
	PUSH25
	// PUSH26 op
	PUSH26
	// PUSH27 op
	PUSH27
	// PUSH28 op
	PUSH28
	// PUSH29 op
	PUSH29
	// PUSH30 op
	PUSH30
	// PUSH31 op
	PUSH31
	// PUSH32 op
	PUSH32
	// DUP1 op
	DUP1
	// DUP2 op
	DUP2
	// DUP3 op
	DUP3
	// DUP4 op
	DUP4
	// DUP5 op
	DUP5
	// DUP6 op
	DUP6
	// DUP7 op
	DUP7
	// DUP8 op
	DUP8
	// DUP9 op
	DUP9
	// DUP10 op
	DUP10
	// DUP11 op
	DUP11
	// DUP12 op
	DUP12
	// DUP13 op
	DUP13
	// DUP14 op
	DUP14
	// DUP15 op
	DUP15
	// DUP16 op
	DUP16
	// SWAP1 op
	SWAP1
	// SWAP2 op
	SWAP2
	// SWAP3 op
	SWAP3
	// SWAP4 op
	SWAP4
	// SWAP5 op
	SWAP5
	// SWAP6 op
	SWAP6
	// SWAP7 op
	SWAP7
	// SWAP8 op
	SWAP8
	// SWAP9 op
	SWAP9
	// SWAP10 op
	SWAP10
	// SWAP11 op
	SWAP11
	// SWAP12 op
	SWAP12
	// SWAP13 op
	SWAP13
	// SWAP14 op
	SWAP14
	// SWAP15 op
	SWAP15
	// SWAP16 op
	SWAP16
)
const (
	// LOG0 生成日志
	LOG0 OpCode = 0xa0 + iota
	// LOG1 op
	LOG1
	// LOG2 op
	LOG2
	// LOG3 op
	LOG3
	// LOG4 op
	LOG4
)

func (OpCode) IsPush

func (op OpCode) IsPush() bool

IsPush 是否为压栈操作

func (OpCode) IsStaticJump

func (op OpCode) IsStaticJump() bool

IsStaticJump 是否为跳转操作

func (OpCode) String

func (op OpCode) String() string

String 打印字符串形式

type Operation

type Operation struct {
	// Execute 指令的具体操作逻辑
	Execute ExecutionFunc

	// GasCost 计算当前指令执行所需消耗的Gas
	GasCost gas.CalcGasFunc

	// ValidateStack 检查内存栈中的数据是否满足本操作执行的要求
	ValidateStack mm.StackValidationFunc

	// MemorySize 计算本次操作所需要的内存大小
	MemorySize mm.MemorySizeFunc

	// Halts   是否需要暂停(将会结束本合约后面操作的执行)
	Halts bool
	// Jumps   是否需要执行跳转(此种情况下PC不递增)
	Jumps bool
	// Writes  是否涉及到修改状态操作(在合约委托调用的情况下,此操作非法,将会抛异常)
	Writes bool
	// Valid   是否为有效操作
	Valid bool
	// Reverts 是否恢复原始状态(强制暂停,将会结束本合约后面操作的执行)
	Reverts bool
	// Returns 是否返回
	Returns bool
}

Operation 定义指令操作的结构提

func NewByzantiumInstructionSet

func NewByzantiumInstructionSet() [256]Operation

NewByzantiumInstructionSet 拜占庭 版本支持的指令集

func NewConstantinopleInstructionSet

func NewConstantinopleInstructionSet() [256]Operation

NewConstantinopleInstructionSet 康士坦丁堡 版本支持的指令集

func NewFrontierInstructionSet

func NewFrontierInstructionSet() [256]Operation

NewFrontierInstructionSet 边境 版本支持的指令集

func NewHomesteadInstructionSet

func NewHomesteadInstructionSet() [256]Operation

NewHomesteadInstructionSet 家园 版本支持的指令集

type PrecompiledContract

type PrecompiledContract interface {
	// 计算当前合约执行需要消耗的Gas
	RequiredGas(input []byte) uint64

	// 执行预编译的合约固定逻辑,input为入参
	Run(input []byte) ([]byte, error)
}

PrecompiledContract 系统内置合约实现的接口,只包含两个操作: 1 根据合约自身逻辑和入参,计算所需Gas; 2 执行合约。

type StructLog

type StructLog struct {
	// Pc pc指针
	Pc uint64 `json:"pc"`
	// Op 操作码
	Op string `json:"op"`
	// Gas gas
	Gas uint64 `json:"gas"`
	// GasCost 花费
	GasCost uint64 `json:"gasCost"`
	// Memory 内存对象
	Memory []string `json:"memory"`
	// MemorySize 内存大小
	MemorySize int `json:"memSize"`
	// Stack 栈对象
	Stack []string `json:"stack"`
	// Storage 存储对象
	Storage map[common.Hash]common.Hash `json:"-"`
	// Depth 调用深度
	Depth int `json:"depth"`
	// Err 错误信息
	Err error `json:"-"`
}

StructLog 指令执行状态信息

type Tracer

type Tracer interface {
	// CaptureStart 开始记录
	CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value uint64) error
	// CaptureState 保存状态
	CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error
	// CaptureFault 保存错误
	CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error
	// CaptureEnd 结束记录
	CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
}

Tracer 接口用来在合约执行过程中收集跟踪数据。 CaptureState 会在EVM解释每条指令时调用。 需要注意的是,传入的引用参数不允许修改,否则会影响EVM解释执行;如果需要使用其中的数据,请复制后使用。

type TransferFunc

type TransferFunc func(state.EVMStateDB, common.Address, common.Address, uint64) bool

TransferFunc 执行转账逻辑

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL