Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove the restriction on pre-compile #177

Merged
merged 11 commits into from
Feb 18, 2025
32 changes: 21 additions & 11 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ import (
)

var (
errPrecompileDisabled = errors.New("sha256, ripemd160, blake2f precompiles temporarily disabled")
errModexpUnsupportedInput = errors.New("modexp temporarily only accepts inputs of 32 bytes (256 bits) or less")
errPrecompileDisabled = errors.New("sha256, ripemd160, blake2f precompiles temporarily disabled")
)

// PrecompiledContract is the basic interface for native Go contracts. The implementation
Expand Down Expand Up @@ -125,6 +124,20 @@ var PrecompiledContractsBernoulli = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{9}): &blake2FDisabled{},
}

// PrecompiledContractsMorph203 contains the default set of pre-compiled Ethereum
// contracts used in the Morph203 release.
var PrecompiledContractsMorph203 = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
}

// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
// contracts specified in EIP-2537. These are exported for testing purposes.
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
Expand All @@ -140,6 +153,7 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
}

var (
PrecompiledAddressesMorph203 []common.Address
PrecompiledAddressesBernoulli []common.Address
PrecompiledAddressesArchimedes []common.Address
PrecompiledAddressesBerlin []common.Address
Expand Down Expand Up @@ -167,11 +181,16 @@ func init() {
for k := range PrecompiledContractsBernoulli {
PrecompiledAddressesBernoulli = append(PrecompiledAddressesBernoulli, k)
}
for k := range PrecompiledContractsMorph203 {
PrecompiledAddressesMorph203 = append(PrecompiledAddressesMorph203, k)
}
}

// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsMorph203:
return PrecompiledAddressesMorph203
case rules.IsBernoulli:
return PrecompiledAddressesBernoulli
case rules.IsArchimedes:
Expand Down Expand Up @@ -437,11 +456,6 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
expLen = expLenBigInt.Uint64()
modLen = modLenBigInt.Uint64()
)
// Check that all inputs are `u256` (32 - bytes) or less, revert otherwise
var lenLimit = new(big.Int).SetInt64(32)
if baseLenBigInt.Cmp(lenLimit) > 0 || expLenBigInt.Cmp(lenLimit) > 0 || modLenBigInt.Cmp(lenLimit) > 0 {
return nil, errModexpUnsupportedInput
}
if len(input) > 96 {
input = input[96:]
} else {
Expand Down Expand Up @@ -578,10 +592,6 @@ var (
// runBn256Pairing implements the Bn256Pairing precompile, referenced by both
// Byzantium and Istanbul operations.
func runBn256Pairing(input []byte) ([]byte, error) {
// Allow at most 4 inputs
if len(input) > 4*192 {
return nil, errBadPairingInput
}
// Handle some corner cases cheaply
if len(input)%192 > 0 {
return nil, errBadPairingInput
Expand Down
2 changes: 2 additions & 0 deletions core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
if cfg.JumpTable[STOP] == nil {
var jt JumpTable
switch {
case evm.chainRules.IsMorph203:
jt = morph203InstructionSet
case evm.chainRules.IsDarwin:
jt = darwinInstructionSet
case evm.chainRules.IsCurie:
Expand Down
8 changes: 8 additions & 0 deletions core/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,19 @@ var (
shanghaiInstructionSet = newShanghaiInstructionSet()
curieInstructionSet = newCurieInstructionSet()
darwinInstructionSet = newDarwinInstructionSet()
morph203InstructionSet = newMorph203InstructionSet()
)

// JumpTable contains the EVM opcodes supported at a given fork.
type JumpTable [256]*operation

// newMorph203InstructionSet returns the frontier, homestead, byzantium,
// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin and morph203 instructions.
func newMorph203InstructionSet() JumpTable {
instructionSet := newDarwinInstructionSet()
return instructionSet
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update the function comment to accurately reflect its implementation.

The function comment suggests that it includes instructions from multiple forks, but the implementation simply returns the Darwin instruction set without any modifications. Either:

  1. Add new instructions specific to Morph203, or
  2. Update the comment to clarify that it currently inherits all instructions from Darwin.

Apply this diff to fix the comment:

-// newMorph203InstructionSet returns the frontier, homestead, byzantium,
-// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin and morph203 instructions.
+// newMorph203InstructionSet returns the Darwin instruction set.
+// TODO: Add Morph203-specific instructions if needed.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// newMorph203InstructionSet returns the frontier, homestead, byzantium,
// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin and morph203 instructions.
func newMorph203InstructionSet() JumpTable {
instructionSet := newDarwinInstructionSet()
return instructionSet
}
// newMorph203InstructionSet returns the Darwin instruction set.
// TODO: Add Morph203-specific instructions if needed.
func newMorph203InstructionSet() JumpTable {
instructionSet := newDarwinInstructionSet()
return instructionSet
}


// newDarwinInstructionSet returns the frontier, homestead, byzantium,
// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, and darwin instructions.
func newDarwinInstructionSet() JumpTable {
Expand Down
54 changes: 41 additions & 13 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ var (
BernoulliBlock: big.NewInt(0),
CurieBlock: big.NewInt(6330180),
DarwinTime: nil,
Morph203Time: nil,
TerminalTotalDifficulty: big.NewInt(0),
Morph: MorphConfig{
UseZktrie: true,
Expand Down Expand Up @@ -312,6 +313,7 @@ var (
BernoulliBlock: big.NewInt(0),
CurieBlock: big.NewInt(0),
DarwinTime: nil,
Morph203Time: nil,
TerminalTotalDifficulty: big.NewInt(0),
Morph: MorphConfig{
UseZktrie: true,
Expand Down Expand Up @@ -538,6 +540,7 @@ type ChainConfig struct {
BernoulliBlock *big.Int `json:"bernoulliBlock,omitempty"` // Bernoulli switch block (nil = no fork, 0 = already on bernoulli)
CurieBlock *big.Int `json:"curieBlock,omitempty"` // Curie switch block (nil = no fork, 0 = already on curie)
DarwinTime *uint64 `json:"darwinTime,omitempty"` // Darwin switch time (nil = no fork, 0 = already on darwin)
Morph203Time *uint64 `json:"morph203Time,omitempty"` // Morph203Time switch time (nil = no fork, 0 = already on morph203)

// TerminalTotalDifficulty is the amount of total difficulty reached by
// the network that triggers the consensus upgrade.
Expand Down Expand Up @@ -748,6 +751,11 @@ func (c *ChainConfig) IsDarwin(now uint64) bool {
return isForkedTime(now, c.DarwinTime)
}

// IsMorph203 returns whether num is either equal to the Morph203 fork block or greater.
func (c *ChainConfig) IsMorph203(now uint64) bool {
return isForkedTime(now, c.Morph203Time)
}

// IsTerminalPoWBlock returns whether the given block is the last block of PoW stage.
func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool {
if c.TerminalTotalDifficulty == nil {
Expand Down Expand Up @@ -778,9 +786,10 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi
// to guarantee that forks can be implemented in a different order than on official networks
func (c *ChainConfig) CheckConfigForkOrder() error {
type fork struct {
name string
block *big.Int
optional bool // if true, the fork may be nil and next fork is still allowed
name string
block *big.Int
timestamp *uint64 // forks after the merge are scheduled using timestamps
optional bool // if true, the fork may be nil and next fork is still allowed
}
var lastFork fork
for _, cur := range []fork{
Expand All @@ -801,22 +810,40 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
{name: "shanghaiBlock", block: c.ShanghaiBlock, optional: true},
{name: "bernoulliBlock", block: c.BernoulliBlock, optional: true},
{name: "curieBlock", block: c.CurieBlock, optional: true},
{name: "darwinTime", timestamp: c.DarwinTime, optional: true},
{name: "morph203Time", timestamp: c.Morph203Time, optional: true},
} {
if lastFork.name != "" {
// Next one must be higher number
if lastFork.block == nil && cur.block != nil {
return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %v",
lastFork.name, cur.name, cur.block)
}
if lastFork.block != nil && cur.block != nil {
if lastFork.block.Cmp(cur.block) > 0 {
return fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v",
switch {
// Non-optional forks must all be present in the chain config up to the last defined fork
case lastFork.block == nil && lastFork.timestamp == nil && (cur.block != nil || cur.timestamp != nil):
if cur.block != nil {
return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at block %v",
lastFork.name, cur.name, cur.block)
} else {
return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at timestamp %v",
lastFork.name, cur.name, *cur.timestamp)
}

// Fork (whether defined by block or timestamp) must follow the fork definition sequence
case (lastFork.block != nil && cur.block != nil) || (lastFork.timestamp != nil && cur.timestamp != nil):
if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 {
return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v",
lastFork.name, lastFork.block, cur.name, cur.block)
} else if lastFork.timestamp != nil && *lastFork.timestamp > *cur.timestamp {
return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v",
lastFork.name, *lastFork.timestamp, cur.name, *cur.timestamp)
}

// Timestamp based forks can follow block based ones, but not the other way around
if lastFork.timestamp != nil && cur.block != nil {
return fmt.Errorf("unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering",
lastFork.name, cur.name)
}
}
}
// If it was optional and not set, then ignore it
if !cur.optional || cur.block != nil {
if !cur.optional || (cur.block != nil || cur.timestamp != nil) {
lastFork = cur
}
}
Expand Down Expand Up @@ -960,7 +987,7 @@ type Rules struct {
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
IsBerlin, IsLondon, IsArchimedes, IsShanghai bool
IsBernoulli, IsCurie, IsDarwin bool
IsBernoulli, IsCurie, IsDarwin, IsMorph203 bool
}

// Rules ensures c's ChainID is not nil.
Expand All @@ -986,5 +1013,6 @@ func (c *ChainConfig) Rules(num *big.Int, time uint64) Rules {
IsBernoulli: c.IsBernoulli(num),
IsCurie: c.IsCurie(num),
IsDarwin: c.IsDarwin(time),
IsMorph203: c.IsMorph203(time),
}
}
6 changes: 3 additions & 3 deletions params/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import (
)

const (
VersionMajor = 5 // Major version component of the current release
VersionMinor = 5 // Minor version component of the current release
VersionPatch = 1 // Patch version component of the current release
VersionMajor = 2 // Major version component of the current release
VersionMinor = 0 // Minor version component of the current release
VersionPatch = 3 // Patch version component of the current release
VersionMeta = "mainnet" // Version metadata to append to the version string
)

Expand Down