core/vm: expose jumptable constructors (#26880)

When interacting with geth as a library to e.g. produce state tests, it is desirable to obtain the consensus-correct jumptable definition for a given fork. This changes adds accessors so the instructionset can be obtained and characteristics about opcodes can be inspected.
This commit is contained in:
Martin Holst Swende 2023-03-21 07:14:47 -04:00 committed by GitHub
parent 905a723fae
commit b3f43c89b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 3 deletions

View File

@ -0,0 +1,74 @@
// Copyright 2023 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 (
"errors"
"github.com/ethereum/go-ethereum/params"
)
// LookupInstructionSet returns the instructionset for the fork configured by
// the rules.
func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
switch {
case rules.IsPrague:
return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet")
case rules.IsCancun:
return newShanghaiInstructionSet(), errors.New("cancun-fork not defined yet")
case rules.IsShanghai:
return newShanghaiInstructionSet(), nil
case rules.IsMerge:
return newMergeInstructionSet(), nil
case rules.IsLondon:
return newLondonInstructionSet(), nil
case rules.IsBerlin:
return newBerlinInstructionSet(), nil
case rules.IsIstanbul:
return newIstanbulInstructionSet(), nil
case rules.IsConstantinople:
return newConstantinopleInstructionSet(), nil
case rules.IsByzantium:
return newByzantiumInstructionSet(), nil
case rules.IsEIP158:
return newSpuriousDragonInstructionSet(), nil
case rules.IsEIP150:
return newTangerineWhistleInstructionSet(), nil
case rules.IsHomestead:
return newHomesteadInstructionSet(), nil
}
return newFrontierInstructionSet(), nil
}
// Stack returns the mininum and maximum stack requirements.
func (op *operation) Stack() (int, int) {
return op.minStack, op.maxStack
}
// HasCost returns true if the opcode has a cost. Opcodes which do _not_ have
// a cost assigned are one of two things:
// - undefined, a.k.a invalid opcodes,
// - the STOP opcode.
// This method can thus be used to check if an opcode is "Invalid (or STOP)".
func (op *operation) HasCost() bool {
// Ideally, we'd check this:
// return op.execute == opUndefined
// However, go-lang does now allow that. So we'll just check some other
// 'indicators' that this is an invalid op. Alas, STOP is impossible to
// filter out
return op.dynamicGas != nil || op.constantGas != 0
}

View File

@ -956,7 +956,7 @@ type Rules struct {
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
IsBerlin, IsLondon bool IsBerlin, IsLondon bool
IsMerge, IsShanghai, isCancun, isPrague bool IsMerge, IsShanghai, IsCancun, IsPrague bool
} }
// Rules ensures c's ChainID is not nil. // Rules ensures c's ChainID is not nil.
@ -979,7 +979,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
IsLondon: c.IsLondon(num), IsLondon: c.IsLondon(num),
IsMerge: isMerge, IsMerge: isMerge,
IsShanghai: c.IsShanghai(timestamp), IsShanghai: c.IsShanghai(timestamp),
isCancun: c.IsCancun(timestamp), IsCancun: c.IsCancun(timestamp),
isPrague: c.IsPrague(timestamp), IsPrague: c.IsPrague(timestamp),
} }
} }