Skip to content

Commit

Permalink
core/vm: refactor instruction set to build per chain config
Browse files Browse the repository at this point in the history
This allows for the potential for opcode mechanisms to
be defined differently even if they share the same bytecode.
  • Loading branch information
whilei committed Jan 29, 2019
1 parent becb961 commit 257cf96
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 124 deletions.
38 changes: 4 additions & 34 deletions core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// the jump table was initialised. If it was not
// we'll set the default jump table.
if !cfg.JumpTable[STOP].valid {
cfg.JumpTable = baseInstructionSet
cfg.JumpTable = instructionSetForConfig(evm.ChainConfig(), evm.BlockNumber)
}

return &EVMInterpreter{
Expand All @@ -123,36 +123,6 @@ func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, st
}
}
}
switch op {
case DELEGATECALL:
if !in.evm.chainRules.IsEIP7F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
case REVERT:
if !in.evm.chainRules.IsEIP140F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
case STATICCALL:
if !in.evm.chainRules.IsEIP214F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
case RETURNDATACOPY, RETURNDATASIZE:
if !in.evm.chainRules.IsEIP211F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
case SHL, SHR, SAR:
if !in.evm.chainRules.IsEIP145F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
case CREATE2:
if !in.evm.chainRules.IsEIP1014F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
case EXTCODEHASH:
if !in.evm.chainRules.IsEIP1052F {
return fmt.Errorf("invalid opcode 0x%x", int(op))
}
}
return nil
}

Expand Down Expand Up @@ -238,11 +208,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
if !operation.valid {
return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
}
// If the operation is valid, enforce and write restrictions
if err := in.enforceRestrictions(op, operation, stack); err != nil {
if err := operation.validateStack(stack); err != nil {
return nil, err
}
if err := operation.validateStack(stack); err != nil {
// If the operation is valid, enforce and write restrictions
if err := in.enforceRestrictions(op, operation, stack); err != nil {
return nil, err
}

Expand Down
188 changes: 98 additions & 90 deletions core/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,105 @@ type operation struct {

}

var baseInstructionSet = newInstructionSet()
var baseInstructionSet = newBaseInstructionSet()

// newInstructionSet returns all available instructions.
func newInstructionSet() [256]operation {
func instructionSetForConfig(config *params.ChainConfig, bn *big.Int) [256]operation {
instructionSet := baseInstructionSet
// Homestead
if config.IsEIP7F(bn) {
instructionSet[DELEGATECALL] = operation{
execute: opDelegateCall,
gasCost: gasDelegateCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryDelegateCall,
valid: true,
returns: true,
}
}

// Byzantium
if config.IsEIP140F(bn) {
instructionSet[REVERT] = operation{
execute: opRevert,
gasCost: gasRevert,
validateStack: makeStackFunc(2, 0),
memorySize: memoryRevert,
valid: true,
reverts: true,
returns: true,
}
}
if config.IsEIP214F(bn) {
instructionSet[STATICCALL] = operation{
execute: opStaticCall,
gasCost: gasStaticCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryStaticCall,
valid: true,
returns: true,
}
}
if config.IsEIP211F(bn) {
instructionSet[RETURNDATASIZE] = operation{
execute: opReturnDataSize,
gasCost: constGasFunc(GasQuickStep),
validateStack: makeStackFunc(0, 1),
valid: true,
}
instructionSet[RETURNDATACOPY] = operation{
execute: opReturnDataCopy,
gasCost: gasReturnDataCopy,
validateStack: makeStackFunc(3, 0),
memorySize: memoryReturnDataCopy,
valid: true,
}
}

// Constantinople
if config.IsEIP145F(bn) {
instructionSet[SHL] = operation{
execute: opSHL,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
}
instructionSet[SHR] = operation{
execute: opSHR,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
}
instructionSet[SAR] = operation{
execute: opSAR,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
}
}
if config.IsEIP1014F(bn) {
instructionSet[CREATE2] = operation{
execute: opCreate2,
gasCost: gasCreate2,
validateStack: makeStackFunc(4, 1),
memorySize: memoryCreate2,
valid: true,
writes: true,
returns: true,
}
}
if config.IsEIP1052F(bn) {
instructionSet[EXTCODEHASH] = operation{
execute: opExtCodeHash,
gasCost: gasExtCodeHash,
validateStack: makeStackFunc(1, 1),
valid: true,
}
}
return instructionSet
}

// newBaseInstructionSet returns Frontier instructions
func newBaseInstructionSet() [256]operation {
return [256]operation{
STOP: {
execute: opStop,
Expand Down Expand Up @@ -863,92 +958,5 @@ func newInstructionSet() [256]operation {
valid: true,
writes: true,
},

// Homestead
// EIP7
DELEGATECALL: {
execute: opDelegateCall,
gasCost: gasDelegateCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryDelegateCall,
valid: true,
returns: true,
},

// Byzantium
// EIP140
REVERT: {
execute: opRevert,
gasCost: gasRevert,
validateStack: makeStackFunc(2, 0),
memorySize: memoryRevert,
valid: true,
reverts: true,
returns: true,
},
// EIP214
STATICCALL: {
execute: opStaticCall,
gasCost: gasStaticCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryStaticCall,
valid: true,
returns: true,
},
// EIP211
RETURNDATASIZE: {
execute: opReturnDataSize,
gasCost: constGasFunc(GasQuickStep),
validateStack: makeStackFunc(0, 1),
valid: true,
},
// EIP211
RETURNDATACOPY: {
execute: opReturnDataCopy,
gasCost: gasReturnDataCopy,
validateStack: makeStackFunc(3, 0),
memorySize: memoryReturnDataCopy,
valid: true,
},

// Constantinople
// EIP145
SHL: {
execute: opSHL,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
},
// EIP145
SHR: {
execute: opSHR,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
},
// EIP145
SAR: {
execute: opSAR,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
},
// EIP1014
CREATE2: {
execute: opCreate2,
gasCost: gasCreate2,
validateStack: makeStackFunc(4, 1),
memorySize: memoryCreate2,
valid: true,
writes: true,
returns: true,
},
// EIP1052
EXTCODEHASH: {
execute: opExtCodeHash,
gasCost: gasExtCodeHash,
validateStack: makeStackFunc(1, 1),
valid: true,
},
}
}

0 comments on commit 257cf96

Please sign in to comment.