mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
core/vm: separated fork instruction sets
This commit is contained in:
parent
5f972398ae
commit
87bbc432ab
5 changed files with 94 additions and 57 deletions
|
|
@ -429,6 +429,35 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
|
||||||
return gas, nil
|
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) {
|
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
return GasFastestStep, nil
|
return GasFastestStep, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
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
|
// pop gas
|
||||||
gas := stack.pop().Uint64()
|
gas := stack.pop().Uint64()
|
||||||
// pop address
|
// 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) {
|
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()
|
gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
|
|
||||||
toAddr := common.BigToAddress(to)
|
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) {
|
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()
|
offset, size := stack.pop(), stack.pop()
|
||||||
ret := memory.GetPtr(offset.Int64(), size.Int64())
|
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) {
|
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))))
|
stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(memory.lastReturn))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
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 (
|
var (
|
||||||
mOff = stack.pop()
|
mOff = stack.pop()
|
||||||
cOff = stack.pop()
|
cOff = stack.pop()
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,14 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter {
|
||||||
// the jump table was initialised. If it was not
|
// the jump table was initialised. If it was not
|
||||||
// we'll set the default jump table.
|
// we'll set the default jump table.
|
||||||
if !cfg.JumpTable[STOP].valid {
|
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{
|
return &Interpreter{
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,57 @@ type operation struct {
|
||||||
reverts bool
|
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{
|
return [256]operation{
|
||||||
STOP: {
|
STOP: {
|
||||||
execute: opStop,
|
execute: opStop,
|
||||||
|
|
@ -395,15 +443,6 @@ func NewJumpTable() [256]operation {
|
||||||
validateStack: makeStackFunc(0, 1),
|
validateStack: makeStackFunc(0, 1),
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
// TODO:
|
|
||||||
// * Determine cost
|
|
||||||
REVERT: {
|
|
||||||
execute: opRevert,
|
|
||||||
gasCost: constGasFunc(GasFastestStep),
|
|
||||||
validateStack: makeStackFunc(2, 0),
|
|
||||||
valid: true,
|
|
||||||
reverts: true,
|
|
||||||
},
|
|
||||||
JUMPDEST: {
|
JUMPDEST: {
|
||||||
execute: opJumpdest,
|
execute: opJumpdest,
|
||||||
gasCost: constGasFunc(params.JumpdestGas),
|
gasCost: constGasFunc(params.JumpdestGas),
|
||||||
|
|
@ -829,19 +868,6 @@ func NewJumpTable() [256]operation {
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
valid: true,
|
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: {
|
CREATE: {
|
||||||
execute: opCreate,
|
execute: opCreate,
|
||||||
gasCost: gasCreate,
|
gasCost: gasCreate,
|
||||||
|
|
@ -872,13 +898,6 @@ func NewJumpTable() [256]operation {
|
||||||
halts: true,
|
halts: true,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
DELEGATECALL: {
|
|
||||||
execute: opDelegateCall,
|
|
||||||
gasCost: gasDelegateCall,
|
|
||||||
validateStack: makeStackFunc(6, 1),
|
|
||||||
memorySize: memoryDelegateCall,
|
|
||||||
valid: true,
|
|
||||||
},
|
|
||||||
SELFDESTRUCT: {
|
SELFDESTRUCT: {
|
||||||
execute: opSuicide,
|
execute: opSuicide,
|
||||||
gasCost: gasSuicide,
|
gasCost: gasSuicide,
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,13 @@ func memoryDelegateCall(stack *Stack) *big.Int {
|
||||||
return math.BigMax(x, y)
|
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 {
|
func memoryReturn(stack *Stack) *big.Int {
|
||||||
return calcMemSize(stack.Back(0), stack.Back(1))
|
return calcMemSize(stack.Back(0), stack.Back(1))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue