bsc/core/vm/opcodes.go
gary rong b9df7ecdc3
all: seperate consensus error and evm internal error (#20830)
* all: seperate consensus error and evm internal error

There are actually two types of error will be returned when
a tranaction/message call is executed: (a) consensus error
(b) evm internal error. The former should be converted to
a consensus issue, e.g. The sender doesn't enough asset to
purchase the gas it specifies. The latter is allowed since
evm itself is a blackbox and internal error is allowed to happen.

This PR emphasizes the difference by introducing a executionResult
structure. The evm error is embedded inside. So if any error
returned, it indicates consensus issue happens.

And also this PR improve the `EstimateGas` API to return the concrete
revert reason if the transaction always fails

* all: polish

* accounts/abi/bind/backends: add tests

* accounts/abi/bind/backends, internal: cleanup error message

* all: address comments

* core: fix lint

* accounts, core, eth, internal: address comments

* accounts, internal: resolve revert reason if possible

* accounts, internal: address comments
2020-04-22 11:25:36 +03:00

546 lines
10 KiB
Go

// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm
import (
"fmt"
)
// OpCode is an EVM opcode
type OpCode byte
// IsPush specifies if an opcode is a PUSH opcode.
func (op OpCode) IsPush() bool {
switch op {
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
return true
}
return false
}
// IsStaticJump specifies if an opcode is JUMP.
func (op OpCode) IsStaticJump() bool {
return op == JUMP
}
// 0x0 range - arithmetic ops.
const (
STOP OpCode = iota
ADD
MUL
SUB
DIV
SDIV
MOD
SMOD
ADDMOD
MULMOD
EXP
SIGNEXTEND
)
// 0x10 range - comparison ops.
const (
LT OpCode = iota + 0x10
GT
SLT
SGT
EQ
ISZERO
AND
OR
XOR
NOT
BYTE
SHL
SHR
SAR
SHA3 OpCode = 0x20
)
// 0x30 range - closure state.
const (
ADDRESS OpCode = 0x30 + iota
BALANCE
ORIGIN
CALLER
CALLVALUE
CALLDATALOAD
CALLDATASIZE
CALLDATACOPY
CODESIZE
CODECOPY
GASPRICE
EXTCODESIZE
EXTCODECOPY
RETURNDATASIZE
RETURNDATACOPY
EXTCODEHASH
)
// 0x40 range - block operations.
const (
BLOCKHASH OpCode = 0x40 + iota
COINBASE
TIMESTAMP
NUMBER
DIFFICULTY
GASLIMIT
CHAINID OpCode = 0x46
SELFBALANCE OpCode = 0x47
)
// 0x50 range - 'storage' and execution.
const (
POP OpCode = 0x50 + iota
MLOAD
MSTORE
MSTORE8
SLOAD
SSTORE
JUMP
JUMPI
PC
MSIZE
GAS
JUMPDEST
)
// 0x60 range.
const (
PUSH1 OpCode = 0x60 + iota
PUSH2
PUSH3
PUSH4
PUSH5
PUSH6
PUSH7
PUSH8
PUSH9
PUSH10
PUSH11
PUSH12
PUSH13
PUSH14
PUSH15
PUSH16
PUSH17
PUSH18
PUSH19
PUSH20
PUSH21
PUSH22
PUSH23
PUSH24
PUSH25
PUSH26
PUSH27
PUSH28
PUSH29
PUSH30
PUSH31
PUSH32
DUP1
DUP2
DUP3
DUP4
DUP5
DUP6
DUP7
DUP8
DUP9
DUP10
DUP11
DUP12
DUP13
DUP14
DUP15
DUP16
SWAP1
SWAP2
SWAP3
SWAP4
SWAP5
SWAP6
SWAP7
SWAP8
SWAP9
SWAP10
SWAP11
SWAP12
SWAP13
SWAP14
SWAP15
SWAP16
)
// 0xa0 range - logging ops.
const (
LOG0 OpCode = 0xa0 + iota
LOG1
LOG2
LOG3
LOG4
)
// unofficial opcodes used for parsing.
const (
PUSH OpCode = 0xb0 + iota
DUP
SWAP
)
// 0xf0 range - closures.
const (
CREATE OpCode = 0xf0 + iota
CALL
CALLCODE
RETURN
DELEGATECALL
CREATE2
STATICCALL OpCode = 0xfa
REVERT OpCode = 0xfd
SELFDESTRUCT OpCode = 0xff
)
// Since the opcodes aren't all in order we can't use a regular slice.
var opCodeToString = map[OpCode]string{
// 0x0 range - arithmetic ops.
STOP: "STOP",
ADD: "ADD",
MUL: "MUL",
SUB: "SUB",
DIV: "DIV",
SDIV: "SDIV",
MOD: "MOD",
SMOD: "SMOD",
EXP: "EXP",
NOT: "NOT",
LT: "LT",
GT: "GT",
SLT: "SLT",
SGT: "SGT",
EQ: "EQ",
ISZERO: "ISZERO",
SIGNEXTEND: "SIGNEXTEND",
// 0x10 range - bit ops.
AND: "AND",
OR: "OR",
XOR: "XOR",
BYTE: "BYTE",
SHL: "SHL",
SHR: "SHR",
SAR: "SAR",
ADDMOD: "ADDMOD",
MULMOD: "MULMOD",
// 0x20 range - crypto.
SHA3: "SHA3",
// 0x30 range - closure state.
ADDRESS: "ADDRESS",
BALANCE: "BALANCE",
ORIGIN: "ORIGIN",
CALLER: "CALLER",
CALLVALUE: "CALLVALUE",
CALLDATALOAD: "CALLDATALOAD",
CALLDATASIZE: "CALLDATASIZE",
CALLDATACOPY: "CALLDATACOPY",
CODESIZE: "CODESIZE",
CODECOPY: "CODECOPY",
GASPRICE: "GASPRICE",
EXTCODESIZE: "EXTCODESIZE",
EXTCODECOPY: "EXTCODECOPY",
RETURNDATASIZE: "RETURNDATASIZE",
RETURNDATACOPY: "RETURNDATACOPY",
EXTCODEHASH: "EXTCODEHASH",
// 0x40 range - block operations.
BLOCKHASH: "BLOCKHASH",
COINBASE: "COINBASE",
TIMESTAMP: "TIMESTAMP",
NUMBER: "NUMBER",
DIFFICULTY: "DIFFICULTY",
GASLIMIT: "GASLIMIT",
CHAINID: "CHAINID",
SELFBALANCE: "SELFBALANCE",
// 0x50 range - 'storage' and execution.
POP: "POP",
//DUP: "DUP",
//SWAP: "SWAP",
MLOAD: "MLOAD",
MSTORE: "MSTORE",
MSTORE8: "MSTORE8",
SLOAD: "SLOAD",
SSTORE: "SSTORE",
JUMP: "JUMP",
JUMPI: "JUMPI",
PC: "PC",
MSIZE: "MSIZE",
GAS: "GAS",
JUMPDEST: "JUMPDEST",
// 0x60 range - push.
PUSH1: "PUSH1",
PUSH2: "PUSH2",
PUSH3: "PUSH3",
PUSH4: "PUSH4",
PUSH5: "PUSH5",
PUSH6: "PUSH6",
PUSH7: "PUSH7",
PUSH8: "PUSH8",
PUSH9: "PUSH9",
PUSH10: "PUSH10",
PUSH11: "PUSH11",
PUSH12: "PUSH12",
PUSH13: "PUSH13",
PUSH14: "PUSH14",
PUSH15: "PUSH15",
PUSH16: "PUSH16",
PUSH17: "PUSH17",
PUSH18: "PUSH18",
PUSH19: "PUSH19",
PUSH20: "PUSH20",
PUSH21: "PUSH21",
PUSH22: "PUSH22",
PUSH23: "PUSH23",
PUSH24: "PUSH24",
PUSH25: "PUSH25",
PUSH26: "PUSH26",
PUSH27: "PUSH27",
PUSH28: "PUSH28",
PUSH29: "PUSH29",
PUSH30: "PUSH30",
PUSH31: "PUSH31",
PUSH32: "PUSH32",
DUP1: "DUP1",
DUP2: "DUP2",
DUP3: "DUP3",
DUP4: "DUP4",
DUP5: "DUP5",
DUP6: "DUP6",
DUP7: "DUP7",
DUP8: "DUP8",
DUP9: "DUP9",
DUP10: "DUP10",
DUP11: "DUP11",
DUP12: "DUP12",
DUP13: "DUP13",
DUP14: "DUP14",
DUP15: "DUP15",
DUP16: "DUP16",
SWAP1: "SWAP1",
SWAP2: "SWAP2",
SWAP3: "SWAP3",
SWAP4: "SWAP4",
SWAP5: "SWAP5",
SWAP6: "SWAP6",
SWAP7: "SWAP7",
SWAP8: "SWAP8",
SWAP9: "SWAP9",
SWAP10: "SWAP10",
SWAP11: "SWAP11",
SWAP12: "SWAP12",
SWAP13: "SWAP13",
SWAP14: "SWAP14",
SWAP15: "SWAP15",
SWAP16: "SWAP16",
LOG0: "LOG0",
LOG1: "LOG1",
LOG2: "LOG2",
LOG3: "LOG3",
LOG4: "LOG4",
// 0xf0 range.
CREATE: "CREATE",
CALL: "CALL",
RETURN: "RETURN",
CALLCODE: "CALLCODE",
DELEGATECALL: "DELEGATECALL",
CREATE2: "CREATE2",
STATICCALL: "STATICCALL",
REVERT: "REVERT",
SELFDESTRUCT: "SELFDESTRUCT",
PUSH: "PUSH",
DUP: "DUP",
SWAP: "SWAP",
}
func (op OpCode) String() string {
str := opCodeToString[op]
if len(str) == 0 {
return fmt.Sprintf("opcode 0x%x not defined", int(op))
}
return str
}
var stringToOp = map[string]OpCode{
"STOP": STOP,
"ADD": ADD,
"MUL": MUL,
"SUB": SUB,
"DIV": DIV,
"SDIV": SDIV,
"MOD": MOD,
"SMOD": SMOD,
"EXP": EXP,
"NOT": NOT,
"LT": LT,
"GT": GT,
"SLT": SLT,
"SGT": SGT,
"EQ": EQ,
"ISZERO": ISZERO,
"SIGNEXTEND": SIGNEXTEND,
"AND": AND,
"OR": OR,
"XOR": XOR,
"BYTE": BYTE,
"SHL": SHL,
"SHR": SHR,
"SAR": SAR,
"ADDMOD": ADDMOD,
"MULMOD": MULMOD,
"SHA3": SHA3,
"ADDRESS": ADDRESS,
"BALANCE": BALANCE,
"ORIGIN": ORIGIN,
"CALLER": CALLER,
"CALLVALUE": CALLVALUE,
"CALLDATALOAD": CALLDATALOAD,
"CALLDATASIZE": CALLDATASIZE,
"CALLDATACOPY": CALLDATACOPY,
"CHAINID": CHAINID,
"DELEGATECALL": DELEGATECALL,
"STATICCALL": STATICCALL,
"CODESIZE": CODESIZE,
"CODECOPY": CODECOPY,
"GASPRICE": GASPRICE,
"EXTCODESIZE": EXTCODESIZE,
"EXTCODECOPY": EXTCODECOPY,
"RETURNDATASIZE": RETURNDATASIZE,
"RETURNDATACOPY": RETURNDATACOPY,
"EXTCODEHASH": EXTCODEHASH,
"BLOCKHASH": BLOCKHASH,
"COINBASE": COINBASE,
"TIMESTAMP": TIMESTAMP,
"NUMBER": NUMBER,
"DIFFICULTY": DIFFICULTY,
"GASLIMIT": GASLIMIT,
"SELFBALANCE": SELFBALANCE,
"POP": POP,
"MLOAD": MLOAD,
"MSTORE": MSTORE,
"MSTORE8": MSTORE8,
"SLOAD": SLOAD,
"SSTORE": SSTORE,
"JUMP": JUMP,
"JUMPI": JUMPI,
"PC": PC,
"MSIZE": MSIZE,
"GAS": GAS,
"JUMPDEST": JUMPDEST,
"PUSH1": PUSH1,
"PUSH2": PUSH2,
"PUSH3": PUSH3,
"PUSH4": PUSH4,
"PUSH5": PUSH5,
"PUSH6": PUSH6,
"PUSH7": PUSH7,
"PUSH8": PUSH8,
"PUSH9": PUSH9,
"PUSH10": PUSH10,
"PUSH11": PUSH11,
"PUSH12": PUSH12,
"PUSH13": PUSH13,
"PUSH14": PUSH14,
"PUSH15": PUSH15,
"PUSH16": PUSH16,
"PUSH17": PUSH17,
"PUSH18": PUSH18,
"PUSH19": PUSH19,
"PUSH20": PUSH20,
"PUSH21": PUSH21,
"PUSH22": PUSH22,
"PUSH23": PUSH23,
"PUSH24": PUSH24,
"PUSH25": PUSH25,
"PUSH26": PUSH26,
"PUSH27": PUSH27,
"PUSH28": PUSH28,
"PUSH29": PUSH29,
"PUSH30": PUSH30,
"PUSH31": PUSH31,
"PUSH32": PUSH32,
"DUP1": DUP1,
"DUP2": DUP2,
"DUP3": DUP3,
"DUP4": DUP4,
"DUP5": DUP5,
"DUP6": DUP6,
"DUP7": DUP7,
"DUP8": DUP8,
"DUP9": DUP9,
"DUP10": DUP10,
"DUP11": DUP11,
"DUP12": DUP12,
"DUP13": DUP13,
"DUP14": DUP14,
"DUP15": DUP15,
"DUP16": DUP16,
"SWAP1": SWAP1,
"SWAP2": SWAP2,
"SWAP3": SWAP3,
"SWAP4": SWAP4,
"SWAP5": SWAP5,
"SWAP6": SWAP6,
"SWAP7": SWAP7,
"SWAP8": SWAP8,
"SWAP9": SWAP9,
"SWAP10": SWAP10,
"SWAP11": SWAP11,
"SWAP12": SWAP12,
"SWAP13": SWAP13,
"SWAP14": SWAP14,
"SWAP15": SWAP15,
"SWAP16": SWAP16,
"LOG0": LOG0,
"LOG1": LOG1,
"LOG2": LOG2,
"LOG3": LOG3,
"LOG4": LOG4,
"CREATE": CREATE,
"CREATE2": CREATE2,
"CALL": CALL,
"RETURN": RETURN,
"CALLCODE": CALLCODE,
"REVERT": REVERT,
"SELFDESTRUCT": SELFDESTRUCT,
}
// StringToOp finds the opcode whose name is stored in `str`.
func StringToOp(str string) OpCode {
return stringToOp[str]
}