core/vm: separated fork instruction sets

This commit is contained in:
Jeffrey Wilcke 2017-03-10 20:03:13 +01:00
parent 5f972398ae
commit 87bbc432ab
5 changed files with 94 additions and 57 deletions

View file

@ -429,6 +429,35 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
return gas, nil
}
func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
panic("verify this one")
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
return 0, errGasUintOverflow
}
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
if err != nil {
return 0, err
}
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called.
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
if gas, overflow = math.SafeAdd(gas, cg); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return GasFastestStep, nil
}

View file

@ -574,11 +574,6 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
}
func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// EIP116 availability check; return an invalid opcode error on fault
if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", STATIC_CALL)
}
// pop gas
gas := stack.pop().Uint64()
// pop address
@ -675,12 +670,6 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
}
func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// if not homestead return an error. DELEGATECALL is not supported
// during pre-homestead.
if !evm.ChainConfig().IsHomestead(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL)
}
gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(to)
@ -709,12 +698,6 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
}
func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// if not metropolis return an error. REVERT is not supported
// during pre-metropolis.
if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", REVERT)
}
offset, size := stack.pop(), stack.pop()
ret := memory.GetPtr(offset.Int64(), size.Int64())
@ -736,19 +719,11 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
}
func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", RETURNDATASIZE)
}
stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(memory.lastReturn))))
return nil, nil
}
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", RETURNDATACOPY)
}
var (
mOff = stack.pop()
cOff = stack.pop()

View file

@ -71,7 +71,14 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter {
// the jump table was initialised. If it was not
// we'll set the default jump table.
if !cfg.JumpTable[STOP].valid {
cfg.JumpTable = defaultJumpTable
switch {
case env.ChainConfig().IsMetropolis(env.BlockNumber):
cfg.JumpTable = metropolisInstructionSet
case env.ChainConfig().IsHomestead(env.BlockNumber):
cfg.JumpTable = homesteadInstructionSet
default:
cfg.JumpTable = baseInstructionSet
}
}
return &Interpreter{

View file

@ -55,9 +55,57 @@ type operation struct {
reverts bool
}
var defaultJumpTable = NewJumpTable()
var (
baseInstructionSet = NewBaseInstructionSet()
homesteadInstructionSet = NewHomesteadInstructionSet()
metropolisInstructionSet = NewMetropolisInstructionSet()
)
func NewJumpTable() [256]operation {
func NewMetropolisInstructionSet() [256]operation {
instructionSet := NewHomesteadInstructionSet()
instructionSet[STATIC_CALL] = operation{
execute: opStaticCall,
gasCost: gasStaticCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryStaticCall,
valid: true,
}
instructionSet[REVERT] = operation{
execute: opRevert,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 0),
valid: true,
reverts: true,
}
instructionSet[RETURNDATASIZE] = operation{
execute: opReturnDataSize,
gasCost: constGasFunc(0), // TODO
validateStack: makeStackFunc(0, 1),
valid: true,
}
instructionSet[RETURNDATACOPY] = operation{
execute: opReturnDataCopy,
gasCost: gasReturnDataCopy,
validateStack: makeStackFunc(3, 0),
memorySize: memoryReturnDataCopy,
valid: true,
}
return instructionSet
}
func NewHomesteadInstructionSet() [256]operation {
instructionSet := NewBaseInstructionSet()
instructionSet[DELEGATECALL] = operation{
execute: opDelegateCall,
gasCost: gasDelegateCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryDelegateCall,
valid: true,
}
return instructionSet
}
func NewBaseInstructionSet() [256]operation {
return [256]operation{
STOP: {
execute: opStop,
@ -395,15 +443,6 @@ func NewJumpTable() [256]operation {
validateStack: makeStackFunc(0, 1),
valid: true,
},
// TODO:
// * Determine cost
REVERT: {
execute: opRevert,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 0),
valid: true,
reverts: true,
},
JUMPDEST: {
execute: opJumpdest,
gasCost: constGasFunc(params.JumpdestGas),
@ -829,19 +868,6 @@ func NewJumpTable() [256]operation {
memorySize: memoryLog,
valid: true,
},
RETURNDATASIZE: {
execute: opReturnDataSize,
gasCost: constGasFunc(0), // TODO
validateStack: makeStackFunc(0, 1),
valid: true,
},
RETURNDATACOPY: {
execute: opReturnDataCopy,
gasCost: gasReturnDataCopy,
validateStack: makeStackFunc(3, 0),
memorySize: memoryReturnDataCopy,
valid: true,
},
CREATE: {
execute: opCreate,
gasCost: gasCreate,
@ -872,13 +898,6 @@ func NewJumpTable() [256]operation {
halts: true,
valid: true,
},
DELEGATECALL: {
execute: opDelegateCall,
gasCost: gasDelegateCall,
validateStack: makeStackFunc(6, 1),
memorySize: memoryDelegateCall,
valid: true,
},
SELFDESTRUCT: {
execute: opSuicide,
gasCost: gasSuicide,

View file

@ -62,6 +62,13 @@ func memoryDelegateCall(stack *Stack) *big.Int {
return math.BigMax(x, y)
}
func memoryStaticCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
return math.BigMax(x, y)
}
func memoryReturn(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}