// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import (
	"fmt"
	"math/big"

	"github.com/33cn/chain33/common/log/log15"
	"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
	"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
	"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/mm"
	"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/model"
	"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/params"
)

// 加法操作
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	common.U256(y.Add(x, y))

	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 减法操作
func opSub(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	//x, y := stack.Pop(), stack.Pop()
	//stack.Push(common.U256(x.Sub(x, y)))
	//
	//evm.Interpreter.IntPool.Put(y)
	//
	//return nil, nil
	x, y := stack.Pop(), stack.Peek()
	common.U256(y.Sub(x, y))

	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 乘法操作
func opMul(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Pop()
	stack.Push(common.U256(x.Mul(x, y)))

	evm.Interpreter.IntPool.Put(y)

	return nil, nil
}

// 除法操作
func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	if y.Sign() != 0 {
		common.U256(y.Div(x, y))
	} else {
		y.SetUint64(0)
	}
	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 除法操作（带符号）
func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := common.S256(stack.Pop()), common.S256(stack.Pop())
	res := evm.Interpreter.IntPool.GetZero()

	if y.Sign() == 0 || x.Sign() == 0 {
		stack.Push(res)
	} else {
		if x.Sign() != y.Sign() {
			res.Div(x.Abs(x), y.Abs(y))
			res.Neg(res)
		} else {
			res.Div(x.Abs(x), y.Abs(y))
		}
		stack.Push(common.U256(res))
	}
	evm.Interpreter.IntPool.Put(x, y)
	return nil, nil
}

// 两数取模
func opMod(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Pop()
	if y.Sign() == 0 {
		stack.Push(x.SetUint64(0))
	} else {
		stack.Push(common.U256(x.Mod(x, y)))
	}
	evm.Interpreter.IntPool.Put(y)
	return nil, nil
}

// 两数取模（带符号）
func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := common.S256(stack.Pop()), common.S256(stack.Pop())
	res := evm.Interpreter.IntPool.GetZero()

	if y.Sign() == 0 {
		stack.Push(res)
	} else {
		if x.Sign() < 0 {
			res.Mod(x.Abs(x), y.Abs(y))
			res.Neg(res)
		} else {
			res.Mod(x.Abs(x), y.Abs(y))
		}
		stack.Push(common.U256(res))
	}
	evm.Interpreter.IntPool.Put(x, y)
	return nil, nil
}

// 指数操作
func opExp(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	base, exponent := stack.Pop(), stack.Pop()
	stack.Push(common.Exp(base, exponent))

	evm.Interpreter.IntPool.Put(base, exponent)

	return nil, nil
}

// 带符号扩展
func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	back := stack.Pop()
	if back.Cmp(big.NewInt(31)) < 0 {
		bit := uint(back.Uint64()*8 + 7)
		num := stack.Pop()
		mask := back.Lsh(common.Big1, bit)
		mask.Sub(mask, common.Big1)
		if num.Bit(int(bit)) > 0 {
			num.Or(num, mask.Not(mask))
		} else {
			num.And(num, mask)
		}

		stack.Push(common.U256(num))
	}

	evm.Interpreter.IntPool.Put(back)
	return nil, nil
}

// 取非
func opNot(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x := stack.Peek()
	common.U256(x.Not(x))
	return nil, nil
}

// 小于判断
func opLt(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	if x.Cmp(y) < 0 {
		y.SetUint64(1)
	} else {
		y.SetUint64(0)
	}
	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 大于判断
func opGt(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	if x.Cmp(y) > 0 {
		y.SetUint64(1)
	} else {
		y.SetUint64(0)
	}
	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 小于判断（带符号）
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()

	xSign := x.Cmp(common.TT255)
	ySign := y.Cmp(common.TT255)

	switch {
	case xSign >= 0 && ySign < 0:
		y.SetUint64(1)

	case xSign < 0 && ySign >= 0:
		y.SetUint64(0)

	default:
		if x.Cmp(y) < 0 {
			y.SetUint64(1)
		} else {
			y.SetUint64(0)
		}
	}
	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 判断两数是否相等（带符号）
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()

	xSign := x.Cmp(common.TT255)
	ySign := y.Cmp(common.TT255)

	switch {
	case xSign >= 0 && ySign < 0:
		y.SetUint64(0)

	case xSign < 0 && ySign >= 0:
		y.SetUint64(1)

	default:
		if x.Cmp(y) > 0 {
			y.SetUint64(1)
		} else {
			y.SetUint64(0)
		}
	}
	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 判断两数是否相等
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	if x.Cmp(y) == 0 {
		y.SetUint64(1)
	} else {
		y.SetUint64(0)
	}
	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 判断指定数是否为0
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x := stack.Peek()
	if x.Sign() > 0 {
		x.SetUint64(0)
	} else {
		x.SetUint64(1)
	}
	return nil, nil
}

// 与操作
func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Pop()
	stack.Push(x.And(x, y))

	evm.Interpreter.IntPool.Put(y)
	return nil, nil
}

// 或操作
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	y.Or(x, y)

	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 异或操作
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y := stack.Pop(), stack.Peek()
	y.Xor(x, y)

	evm.Interpreter.IntPool.Put(x)
	return nil, nil
}

// 获取指定数据中指定位的byte值
func opByte(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	th, val := stack.Pop(), stack.Peek()

	// 只处理不超过32位整数的值，否则直接设置0
	if th.Cmp(common.Big32) < 0 {
		b := common.Byte(val, model.WordByteSize, int(th.Int64()))
		val.SetUint64(uint64(b))
	} else {
		val.SetUint64(0)
	}
	evm.Interpreter.IntPool.Put(th)
	return nil, nil
}

// 两数相加，并和第三数求模
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
	if z.Cmp(common.Big0) > 0 {
		x.Add(x, y)
		x.Mod(x, z)
		stack.Push(common.U256(x))
	} else {
		stack.Push(x.SetUint64(0))
	}
	evm.Interpreter.IntPool.Put(y, z)
	return nil, nil
}

// 两数相乘，并和第三数求模
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
	if z.Cmp(common.Big0) > 0 {
		mul := x.Mul(x, y)
		mul.Mod(mul, z)
		stack.Push(common.U256(mul))
	} else {
		stack.Push(new(big.Int))
	}

	evm.Interpreter.IntPool.Put(y, z)
	return nil, nil
}

// 左移位操作：
// 操作弹出x和y，将y向左移x位，并将结果入栈
func opSHL(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 注意，这里y值并没有弹出，后面的操作直接改变其值，不需要再次入栈
	shift, value := common.U256(stack.Pop()), common.U256(stack.Peek())

	// 将x放入整数池
	defer evm.Interpreter.IntPool.Put(shift)

	// 如果移动范围超过256位整数的长度，则直接置零
	if shift.Cmp(common.Big256) >= 0 {
		value.SetUint64(0)
		return nil, nil
	}

	// 执行移位操作
	n := uint(shift.Uint64())
	common.U256(value.Lsh(value, n))

	return nil, nil
}

// 右移位操作：
// 操作弹出x和y，将y向右移x位，并将结果入栈 （左边的空位用0填充）
func opSHR(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 注意，这里y值并没有弹出，后面的操作直接改变其值，不需要再次入栈
	shift, value := common.U256(stack.Pop()), common.U256(stack.Peek())

	// 将x放入整数池
	defer evm.Interpreter.IntPool.Put(shift)

	// 如果移动范围超过256位整数的长度，则直接置零
	if shift.Cmp(common.Big256) >= 0 {
		value.SetUint64(0)
		return nil, nil
	}

	// 执行移位操作
	n := uint(shift.Uint64())
	common.U256(value.Rsh(value, n))

	return nil, nil
}

// 右移位操作：
// 操作弹出x和y，将y向右移x位，并将结果入栈 （左边的空位用左边第一位的符号位填充）
func opSAR(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 注意，这里y值弹出了，后面计算出结果后需要入栈
	shift, value := common.U256(stack.Pop()), common.S256(stack.Pop())
	// 将x放入整数池
	defer evm.Interpreter.IntPool.Put(shift)

	// 如果移动范围超过256位整数的长度，正数置零，负数置-1
	if shift.Cmp(common.Big256) >= 0 {
		if value.Sign() > 0 {
			value.SetUint64(0)
		} else {
			value.SetInt64(-1)
		}
		stack.Push(common.U256(value))
		return nil, nil
	}

	// 正常移位操作（注意这里需要将结果入栈）
	n := uint(shift.Uint64())
	value.Rsh(value, n)
	stack.Push(common.U256(value))

	return nil, nil
}

//使用keccak256进行哈希运算
func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	offset, size := stack.Pop(), stack.Pop()
	data := memory.Get(offset.Int64(), size.Int64())
	hash := crypto.Keccak256(data)

	if evm.VMConfig.EnablePreimageRecording {
		evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
	}

	stack.Push(evm.Interpreter.IntPool.Get().SetBytes(hash))

	evm.Interpreter.IntPool.Put(offset, size)
	return nil, nil
}

// 获取合约地址
func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(contract.Address().Big())
	return nil, nil
}

// 获取指定地址的账户余额
func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	slot := stack.Peek()
	slot.SetUint64(evm.StateDB.GetBalance(common.BigToAddress(slot).String()))
	return nil, nil
}

// 获取合约调用者地址
func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Origin.Big())
	return nil, nil
}

// 获取合约的调用者（最终的外部账户地址）
func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(contract.Caller().Big())
	return nil, nil
}

// 获取调用合约的同时，进行转账操作的额度
func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	amount := common.BigMax(big.NewInt(0), big.NewInt(int64(contract.value)))
	stack.Push(evm.Interpreter.IntPool.Get().Set(amount))
	return nil, nil
}

// 从调用合约的入参中获取数据
func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Interpreter.IntPool.Get().SetBytes(common.GetDataBig(contract.Input, stack.Pop(), big32)))
	return nil, nil
}

// 获取调用合约时的入参长度
func opCallDataSize(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Interpreter.IntPool.Get().SetInt64(int64(len(contract.Input))))
	return nil, nil
}

// 将调用合约时的入参写入内存
func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	var (
		memOffset  = stack.Pop()
		dataOffset = stack.Pop()
		length     = stack.Pop()
	)
	if merr := memory.Set(memOffset.Uint64(), length.Uint64(), common.GetDataBig(contract.Input, dataOffset, length)); merr != nil {
		return nil, merr
	}
	evm.Interpreter.IntPool.Put(memOffset, dataOffset, length)
	return nil, nil
}

// 获取合约执行返回结果的大小
func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Interpreter.IntPool.Get().SetUint64(uint64(len(evm.Interpreter.ReturnData))))
	return nil, nil
}

// 将合约执行的返回结果复制到内存
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	var (
		memOffset  = stack.Pop()
		dataOffset = stack.Pop()
		length     = stack.Pop()

		end = evm.Interpreter.IntPool.Get().Add(dataOffset, length)
	)
	defer evm.Interpreter.IntPool.Put(memOffset, dataOffset, length, end)

	if end.BitLen() > 64 || uint64(len(evm.Interpreter.ReturnData)) < end.Uint64() {
		return nil, model.ErrReturnDataOutOfBounds
	}
	err := memory.Set(memOffset.Uint64(), length.Uint64(), evm.Interpreter.ReturnData[dataOffset.Uint64():end.Uint64()])
	if err != nil {
		panic(err)
	}

	return nil, nil
}

// 获取指定合约地址的合约代码大小
func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	a := stack.Pop()

	addr := common.BigToAddress(a)
	a.SetInt64(int64(evm.StateDB.GetCodeSize(addr.String())))
	stack.Push(a)

	return nil, nil
}

// 获取合约代码大小
func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	l := evm.Interpreter.IntPool.Get().SetInt64(int64(len(contract.Code)))
	stack.Push(l)
	return nil, nil
}

// 蒋合约中指定位置的数据复制到内存中
func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	var (
		memOffset  = stack.Pop()
		codeOffset = stack.Pop()
		length     = stack.Pop()
	)
	codeCopy := common.GetDataBig(contract.Code, codeOffset, length)
	if merr := memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy); merr != nil {
		return nil, merr
	}
	evm.Interpreter.IntPool.Put(memOffset, codeOffset, length)
	return nil, nil
}

// 蒋指定合约中指定位置的数据复制到内存中
func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	var (
		addr       = common.BigToAddress(stack.Pop())
		memOffset  = stack.Pop()
		codeOffset = stack.Pop()
		length     = stack.Pop()
	)
	codeCopy := common.GetDataBig(evm.StateDB.GetCode(addr.String()), codeOffset, length)
	if merr := memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy); merr != nil {
		return nil, merr
	}
	evm.Interpreter.IntPool.Put(memOffset, codeOffset, length)
	return nil, nil
}

// 获取当前区块的GasPrice
func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	gasPrice := common.BigMax(big.NewInt(0), big.NewInt(int64(evm.GasPrice)))
	stack.Push(evm.Interpreter.IntPool.Get().Set(gasPrice))
	return nil, nil
}

// 获取区块哈希
func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	num := stack.Pop()

	n := evm.Interpreter.IntPool.Get().Sub(evm.BlockNumber, common.Big257)
	if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
		stack.Push(evm.GetHash(num.Uint64()).Big())
	} else {
		stack.Push(evm.Interpreter.IntPool.GetZero())
	}
	evm.Interpreter.IntPool.Put(num, n)
	return nil, nil
}

// 获取区块打包者地址
func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 需要注意coinbase可能为空的情况，这时将返回合约的创建者作为coinbase
	if evm.Coinbase == nil {
		stack.Push(contract.CallerAddress.Big())
	} else {
		stack.Push(evm.Coinbase.Big())
	}
	return nil, nil
}

// 获取区块打包时间
func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(common.U256(evm.Interpreter.IntPool.Get().Set(evm.Time)))
	return nil, nil
}

// 获取区块高度
func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(common.U256(evm.Interpreter.IntPool.Get().Set(evm.BlockNumber)))
	return nil, nil
}

// 获取区块难度
func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(common.U256(evm.Interpreter.IntPool.Get().Set(evm.Difficulty)))
	return nil, nil
}

// 获取GasLimit
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(common.U256(evm.Interpreter.IntPool.Get().SetUint64(evm.GasLimit)))
	return nil, nil
}

// 弹出栈顶数据
func opPop(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	evm.Interpreter.IntPool.Put(stack.Pop())
	return nil, nil
}

// 加载内存中的数据
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	offset := stack.Pop()
	val := evm.Interpreter.IntPool.Get().SetBytes(memory.Get(offset.Int64(), 32))
	stack.Push(val)

	evm.Interpreter.IntPool.Put(offset)
	return nil, nil
}

// 写内存操作，每次写一个字长（32个字节）
func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 从栈中分别弹出内存偏移量和要设置的值
	mStart, val := stack.Pop(), stack.Pop()
	if merr := memory.Set32(mStart.Uint64(), val); merr != nil {
		return nil, merr
	}

	evm.Interpreter.IntPool.Put(mStart, val)
	return nil, nil
}

// 写内存操作，每次写一个字节
func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	off, val := stack.Pop().Int64(), stack.Pop().Int64()
	memory.Store[off] = byte(val & 0xff)

	return nil, nil
}

// 加载合约状态数据
func opSload(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	loc := stack.Peek()
	val := evm.StateDB.GetState(contract.Address().String(), common.BigToHash(loc))
	loc.SetBytes(val.Bytes())

	return nil, nil
}

// 写合约状态数据
func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	loc := common.BigToHash(stack.Pop())
	val := stack.Pop()
	evm.StateDB.SetState(contract.Address().String(), loc, common.BigToHash(val))

	evm.Interpreter.IntPool.Put(val)
	return nil, nil
}

// 无条件跳转操作
func opJump(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	pos := stack.Pop()
	if !contract.Jumpdests.Has(contract.CodeHash, contract.Code, pos) {
		nop := contract.GetOp(pos.Uint64())
		return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
	}
	*pc = pos.Uint64()

	evm.Interpreter.IntPool.Put(pos)
	return nil, nil
}

// 有条件跳转操作
func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	pos, cond := stack.Pop(), stack.Pop()
	if cond.Sign() != 0 {
		if !contract.Jumpdests.Has(contract.CodeHash, contract.Code, pos) {
			nop := contract.GetOp(pos.Uint64())
			return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
		}
		*pc = pos.Uint64()
	} else {
		*pc++
	}

	evm.Interpreter.IntPool.Put(pos, cond)
	return nil, nil
}

// 跳转目标位置
func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	return nil, nil
}

// 将指令计数器指针当前的值写入整数池
func opPc(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Interpreter.IntPool.Get().SetUint64(*pc))
	return nil, nil
}

// 获取内存大小
func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Interpreter.IntPool.Get().SetInt64(int64(memory.Len())))
	return nil, nil
}

// 获取可用Gas
func opGas(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	stack.Push(evm.Interpreter.IntPool.Get().SetUint64(contract.Gas))
	return nil, nil
}

// 合约创建操作
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 从栈和内存中分别获取操作所需的参数
	var (
		value        = stack.Pop()
		offset, size = stack.Pop(), stack.Pop()
		inPut        = memory.Get(offset.Int64(), size.Int64())
		gas          = contract.Gas
	)

	contract.UseGas(gas)

	// 调用合约创建逻辑
	addr := crypto.RandomContractAddress()
	res, _, returnGas, suberr := evm.Create(contract, *addr, inPut, gas, "innerContract", "", "")

	// 出错时压栈0，否则压栈创建出来的合约对象的地址
	if suberr != nil && suberr != model.ErrCodeStoreOutOfGas {
		log15.Error("evm contract opCreate instruction error", suberr)
		stack.Push(evm.Interpreter.IntPool.GetZero())
	} else {
		stack.Push(addr.Big())
	}

	// 剩余的Gas再返还给合约对象
	contract.Gas += returnGas

	// 其它参数写入整数池
	evm.Interpreter.IntPool.Put(value, offset, size)

	if suberr == model.ErrExecutionReverted {
		return res, nil
	}
	return nil, nil
}

// 合约调用操作
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	// 弹出可用的gas，并放入整数池
	evm.Interpreter.IntPool.Put(stack.Pop())
	// CallGasTemp中存储的是当前操作需要消耗的Gas
	gas := evm.CallGasTemp

	// 从栈中一次弹出其它参数
	addr, value, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop()
	toAddr := common.BigToAddress(addr)
	value = common.U256(value)

	// 从内存中读取调用合约时需要的输入参数，
	// 注意，这里使用栈中弹出的内存偏移量和存储长度从内存中获取参数，
	// 之所以这样通过间接的方式获取，主要是因为参数的大小可能比较大，放在栈中不方便组织，
	// 所以通过store操作提前写入内存，在这里再读出来使用
	args := memory.Get(inOffset.Int64(), inSize.Int64())

	if value.Sign() != 0 {
		// 如果有转账操作，这里给予一定的Gas赠送
		gas += params.CallStipend
	}

	// 调用合约执行逻辑
	ret, _, returnGas, err := evm.Call(contract, toAddr, args, gas, value.Uint64())

	// 调用结果压栈，
	// 注意，这里的处理比较特殊，出错情况下0压栈，正确情况下1压栈
	if err != nil {
		stack.Push(evm.Interpreter.IntPool.GetZero())
		log15.Error("evm contract opCall instruction error", "error", err)
	} else {
		stack.Push(evm.Interpreter.IntPool.Get().SetUint64(1))
	}

	// 如果正确执行，将结果写内存
	if err == nil || err == model.ErrExecutionReverted {
		if merr := memory.Set(retOffset.Uint64(), retSize.Uint64(), ret); merr != nil {
			return ret, merr
		}
	}

	// 剩余的Gas再返还给合约对象
	contract.Gas += returnGas

	// 其它参数写入整数池
	evm.Interpreter.IntPool.Put(addr, value, inOffset, inSize, retOffset, retSize)
	return ret, nil
}

// 合约调用操作，
// 逻辑同opCall大致相同，仅调用evm的方法不同
func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	evm.Interpreter.IntPool.Put(stack.Pop())
	gas := evm.CallGasTemp
	addr, value, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop()
	toAddr := common.BigToAddress(addr)
	value = common.U256(value)
	args := memory.Get(inOffset.Int64(), inSize.Int64())

	if value.Sign() != 0 {
		gas += params.CallStipend
	}

	ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value.Uint64())
	if err != nil {
		stack.Push(evm.Interpreter.IntPool.GetZero())
		log15.Error("evm contract opCallCode instruction error", err)
	} else {
		stack.Push(evm.Interpreter.IntPool.Get().SetUint64(1))
	}
	if err == nil || err == model.ErrExecutionReverted {
		if merr := memory.Set(retOffset.Uint64(), retSize.Uint64(), ret); merr != nil {
			return ret, merr
		}
	}
	contract.Gas += returnGas

	evm.Interpreter.IntPool.Put(addr, value, inOffset, inSize, retOffset, retSize)
	return ret, nil
}

// 合约委托调用操作，
// 逻辑同opCall大致相同，仅调用evm的方法不同
func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	evm.Interpreter.IntPool.Put(stack.Pop())
	gas := evm.CallGasTemp
	addr, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop()
	toAddr := common.BigToAddress(addr)
	args := memory.Get(inOffset.Int64(), inSize.Int64())

	ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
	if err != nil {
		log15.Error("evm contract opDelegateCall instruction error", err)
		stack.Push(evm.Interpreter.IntPool.GetZero())
	} else {
		stack.Push(evm.Interpreter.IntPool.Get().SetUint64(1))
	}
	if err == nil || err == model.ErrExecutionReverted {
		if merr := memory.Set(retOffset.Uint64(), retSize.Uint64(), ret); merr != nil {
			return ret, merr
		}
	}
	contract.Gas += returnGas

	evm.Interpreter.IntPool.Put(addr, inOffset, inSize, retOffset, retSize)
	return ret, nil
}

// 合约调用操作，
// 逻辑同opCall大致相同，仅调用evm的方法不同
func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	evm.Interpreter.IntPool.Put(stack.Pop())
	gas := evm.CallGasTemp
	addr, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop()
	toAddr := common.BigToAddress(addr)
	args := memory.Get(inOffset.Int64(), inSize.Int64())

	ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
	if err != nil {
		log15.Error("evm contract opDelegateCall instruction error", err)
		stack.Push(evm.Interpreter.IntPool.GetZero())
	} else {
		stack.Push(evm.Interpreter.IntPool.Get().SetUint64(1))
	}
	if err == nil || err == model.ErrExecutionReverted {
		if merr := memory.Set(retOffset.Uint64(), retSize.Uint64(), ret); merr != nil {
			return ret, merr
		}

	}
	contract.Gas += returnGas

	evm.Interpreter.IntPool.Put(addr, inOffset, inSize, retOffset, retSize)
	return ret, nil
}

// 返回操作
func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	offset, size := stack.Pop(), stack.Pop()
	ret := memory.GetPtr(offset.Int64(), size.Int64())

	evm.Interpreter.IntPool.Put(offset, size)
	return ret, nil
}

// 恢复操作
func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	offset, size := stack.Pop(), stack.Pop()
	ret := memory.GetPtr(offset.Int64(), size.Int64())

	evm.Interpreter.IntPool.Put(offset, size)
	return ret, nil
}

// 停止操作
func opStop(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	return nil, nil
}

// 自毁操作
func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
	balance := evm.StateDB.GetBalance(contract.Address().String())
	// 合约自毁后，将剩余金额返还给创建者
	evm.StateDB.AddBalance(common.BigToAddress(stack.Pop()).String(), (*contract.CodeAddr).String(), balance)

	evm.StateDB.Suicide(contract.Address().String())
	return nil, nil
}

// 生成创建日志的操作的方法：
// 生成的方法允许在合约执行时，创建N条日志写入StateDB；
// 在合约执行完成后，这些日志会打印出来（目前不会存储）
func makeLog(size int) ExecutionFunc {
	return func(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.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())
		evm.StateDB.AddLog(&model.ContractLog{
			Address: contract.Address(),
			Topics:  topics,
			Data:    d,
		})

		evm.Interpreter.IntPool.Put(mStart, mSize)
		return nil, nil
	}
}

// 生成PUSHN操作的方法，支持PUSH1-PUSH32
// 此操作可以讲合约中的数据进行压栈
func makePush(size uint64, pushByteSize int) ExecutionFunc {
	return func(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
		codeLen := len(contract.Code)

		startMin := codeLen
		if int(*pc+1) < startMin {
			startMin = int(*pc + 1)
		}

		endMin := codeLen
		if startMin+pushByteSize < endMin {
			endMin = startMin + pushByteSize
		}

		integer := evm.Interpreter.IntPool.Get()
		stack.Push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize)))

		*pc += size
		return nil, nil
	}
}

// 生成DUP操作，可以讲栈中指定位置数据复制并压栈
func makeDup(size int64) ExecutionFunc {
	return func(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
		stack.Dup(evm.Interpreter.IntPool, int(size))
		return nil, nil
	}
}

// 生成SWAP操作，将指定位置的数据和栈顶数据互换位置
func makeSwap(size int64) ExecutionFunc {
	size++
	return func(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *mm.Stack) ([]byte, error) {
		stack.Swap(int(size))
		return nil, nil
	}
}
