From a944cee9a5d33e6698adbb4a88a8b65683158a12 Mon Sep 17 00:00:00 2001 From: technicallyty <48813565+tytech3@users.noreply.github.com> Date: Sat, 21 Nov 2020 23:46:22 -0800 Subject: [PATCH 1/4] Set Indestructable Added an indestructable property to a contract instance --- core/vm/contract.go | 2 + core/vm/eips.go | 24 ++- core/vm/jump_table.go | 9 ++ core/vm/opcodes.go | 333 +++++++++++++++++++++--------------------- 4 files changed, 200 insertions(+), 168 deletions(-) diff --git a/core/vm/contract.go b/core/vm/contract.go index 915193d137b3..b2f808590cb9 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -58,6 +58,8 @@ type Contract struct { CodeAddr *common.Address Input []byte + Indestructable bool + Gas uint64 value *big.Int } diff --git a/core/vm/eips.go b/core/vm/eips.go index 962c0f14b162..f270d96e8ea0 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -83,8 +83,20 @@ func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx return nil, nil } +// enable2937 applies EIP-2937 (SET_INDESRUCTIBLE Opcode) +// - Adds an opcode that prevents contract from calling SELFDESTRUCT (0xFF) +func enable2937(jt *JumpTable) { + // New opcode + jt[SETINDESTRUCTIBLE] = &operation{ + execute: opSetIndestructible, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + } +} + // enable1344 applies EIP-1344 (ChainID Opcode) -// - Adds an opcode that returns the current chain’s EIP-155 unique identifier +// - Adds an opcode that returns the current chain's EIP-155 unique identifier func enable1344(jt *JumpTable) { // New opcode jt[CHAINID] = &operation{ @@ -95,10 +107,16 @@ func enable1344(jt *JumpTable) { } } +// opSetIndestructible implements forbidding a contract from calling SELFDESTRUCT +func opSetIndestructible(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.contract.Indestructable = true + return nil, nil +} + // opChainID implements CHAINID opcode func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { - chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID) - callContext.stack.push(chainId) + chainID, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID) + callContext.stack.push(chainID) return nil, nil } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 83fb2c1ed628..320468deac9f 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -57,11 +57,20 @@ var ( constantinopleInstructionSet = newConstantinopleInstructionSet() istanbulInstructionSet = newIstanbulInstructionSet() yoloV2InstructionSet = newYoloV2InstructionSet() + bastanchuryInstructionSet = newBastanchuryInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. type JumpTable [256]*operation +// newBastanchuryInstructionSet returns the instruction set containing +// - "EIP-2937: SET_INDESTRUCTIBLE opcode" +func newBastanchuryInstructionSet() JumpTable { + instructionSet := newIstanbulInstructionSet() + enable2937(&instructionSet) + return instructionSet +} + // newYoloV2InstructionSet creates an instructionset containing // - "EIP-2315: Simple Subroutines" // - "EIP-2929: Gas cost increases for state access opcodes" diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index da7b2ee4aa17..e87629081d60 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -199,6 +199,7 @@ const ( LOG2 LOG3 LOG4 + SETINDESTRUCTIBLE ) // unofficial opcodes used for parsing. @@ -355,27 +356,28 @@ var opCodeToString = map[OpCode]string{ 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", + 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", + SETINDESTRUCTIBLE: "SETINDESTRUCTIBLE", // 0xf0 range. CREATE: "CREATE", @@ -403,150 +405,151 @@ func (op OpCode) String() string { } 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, - "BEGINSUB": BEGINSUB, - "RETURNSUB": RETURNSUB, - "JUMPSUB": JUMPSUB, - "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, + "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, + "BEGINSUB": BEGINSUB, + "RETURNSUB": RETURNSUB, + "JUMPSUB": JUMPSUB, + "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, + "SETINDESTRUCTIBLE": SETINDESTRUCTIBLE, + "CREATE": CREATE, + "CREATE2": CREATE2, + "CALL": CALL, + "RETURN": RETURN, + "CALLCODE": CALLCODE, + "REVERT": REVERT, + "SELFDESTRUCT": SELFDESTRUCT, } // StringToOp finds the opcode whose name is stored in `str`. From 26e13378b0d39521d5f8e0de71ffdaddd608b5c5 Mon Sep 17 00:00:00 2001 From: technicallyty <48813565+tytech3@users.noreply.github.com> Date: Sun, 22 Nov 2020 00:06:52 -0800 Subject: [PATCH 2/4] lol spelling --- core/vm/contract.go | 2 +- core/vm/eips.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/contract.go b/core/vm/contract.go index b2f808590cb9..e71ae52a517b 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -58,7 +58,7 @@ type Contract struct { CodeAddr *common.Address Input []byte - Indestructable bool + Indestructible bool Gas uint64 value *big.Int diff --git a/core/vm/eips.go b/core/vm/eips.go index f270d96e8ea0..6ee80a668fb6 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -109,7 +109,7 @@ func enable1344(jt *JumpTable) { // opSetIndestructible implements forbidding a contract from calling SELFDESTRUCT func opSetIndestructible(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { - callContext.contract.Indestructable = true + callContext.contract.Indestructible = true return nil, nil } From 3e0f294b2c5e3ca2bd1708f9a96c1315044b0544 Mon Sep 17 00:00:00 2001 From: technicallyty <48813565+tytech3@users.noreply.github.com> Date: Mon, 23 Nov 2020 13:43:45 -0800 Subject: [PATCH 3/4] linter + opSuicide changes -added new EVM error for when an indestructible contract tries to self destruct -added if case in opsuicide to throw the error described above when an indestructible contract tries to opSuicide -appeased some golint stuff --- core/vm/errors.go | 1 + core/vm/instructions.go | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/vm/errors.go b/core/vm/errors.go index f6b156a02e38..d7fb1c4a49a8 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -39,6 +39,7 @@ var ( ErrGasUintOverflow = errors.New("gas uint64 overflow") ErrInvalidRetsub = errors.New("invalid retsub") ErrReturnStackExceeded = errors.New("return stack limit reached") + ErrContractIndestructible = errors.New("contract is indestructible") ) // ErrStackUnderflow wraps an evm error when the items on the stack less diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 4ded0239d970..ef7b203f1833 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -815,11 +815,14 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by } func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { - beneficiary := callContext.stack.pop() - balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address()) - interpreter.evm.StateDB.AddBalance(common.Address(beneficiary.Bytes20()), balance) - interpreter.evm.StateDB.Suicide(callContext.contract.Address()) - return nil, nil + if !callContext.contract.Indestructible { + beneficiary := callContext.stack.pop() + balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address()) + interpreter.evm.StateDB.AddBalance(common.Address(beneficiary.Bytes20()), balance) + interpreter.evm.StateDB.Suicide(callContext.contract.Address()) + return nil, nil + } + return nil, ErrContractIndestructible } // following functions are used by the instruction jump table @@ -855,7 +858,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]b codeLen = uint64(len(callContext.contract.Code)) integer = new(uint256.Int) ) - *pc += 1 + *pc++ if *pc < codeLen { callContext.stack.push(integer.SetUint64(uint64(callContext.contract.Code[*pc]))) } else { From 7d534336762acaaa85365506771a2d5f177925cd Mon Sep 17 00:00:00 2001 From: technicallyty <48813565+tytech3@users.noreply.github.com> Date: Mon, 23 Nov 2020 22:40:11 -0800 Subject: [PATCH 4/4] core/evm: more set_indestructible * added 2937 to valideip map * added comments to exported functions to appease go linter * updated bastanchury instructionset to inherit yolov2 * set opcode to 0xa8 per eip spec --- core/vm/eips.go | 4 ++++ core/vm/jump_table.go | 2 +- core/vm/opcodes.go | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 6ee80a668fb6..00e4f942fd24 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -30,6 +30,7 @@ var activators = map[int]func(*JumpTable){ 1884: enable1884, 1344: enable1344, 2315: enable2315, + 2937: enable2937, } // EnableEIP enables the given EIP on the config. @@ -44,10 +45,13 @@ func EnableEIP(eipNum int, jt *JumpTable) error { return nil } +// ValidEip checks if an eip is in the activators table func ValidEip(eipNum int) bool { _, ok := activators[eipNum] return ok } + +// ActivateableEips returns the available activatble eips func ActivateableEips() []string { var nums []string for k := range activators { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 320468deac9f..cd651d61ca82 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -66,7 +66,7 @@ type JumpTable [256]*operation // newBastanchuryInstructionSet returns the instruction set containing // - "EIP-2937: SET_INDESTRUCTIBLE opcode" func newBastanchuryInstructionSet() JumpTable { - instructionSet := newIstanbulInstructionSet() + instructionSet := newYoloV2InstructionSet() enable2937(&instructionSet) return instructionSet } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index e87629081d60..3049e00930e1 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -199,7 +199,7 @@ const ( LOG2 LOG3 LOG4 - SETINDESTRUCTIBLE + SETINDESTRUCTIBLE OpCode = 0xa8 ) // unofficial opcodes used for parsing.