Skip to content

Commit

Permalink
evm: enable new instruction and precompile in ETH_SH
Browse files Browse the repository at this point in the history
  • Loading branch information
libotony committed Mar 19, 2024
1 parent ed5d05d commit d9b0b85
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 38 deletions.
8 changes: 7 additions & 1 deletion runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ func New(
}

// alloc precompiled contracts
if forkConfig.ETH_IST == ctx.Number {
if forkConfig.ETH_SH == ctx.Number {
for addr := range vm.PrecompiledContractsShanghai {
if err := state.SetCode(thor.Address(addr), EmptyRuntimeBytecode); err != nil {
panic(err)
}
}
} else if forkConfig.ETH_IST == ctx.Number {
for addr := range vm.PrecompiledContractsIstanbul {
if err := state.SetCode(thor.Address(addr), EmptyRuntimeBytecode); err != nil {
panic(err)
Expand Down
90 changes: 53 additions & 37 deletions vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,20 @@ type (
OnSuicideContractFunc func(evm *EVM, contractAddr common.Address, tokenReceiver common.Address)
)

// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsIstanbul(evm.BlockNumber) {
precompiles = PrecompiledContractsIstanbul
} else if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if p := precompiles[*contract.CodeAddr]; p != nil {
return RunPrecompiledContract(p, input, contract)
}
}
return evm.interpreter.Run(contract, input)
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsShanghai:
precompiles = PrecompiledContractsShanghai
case evm.chainRules.IsIstanbul:
precompiles = PrecompiledContractsIstanbul
case evm.chainRules.IsByzantium:
precompiles = PrecompiledContractsByzantium
default:
precompiles = PrecompiledContractsHomestead
}
p, ok := precompiles[addr]
return p, ok
}

// Context provides the EVM with auxiliary information. Once provided
Expand Down Expand Up @@ -185,7 +185,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
return evm.call(caller, addr, input, gas, value)
}

func (evm *EVM) call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) ([]byte, uint64, error) {
func (evm *EVM) call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, gas, nil
}
Expand All @@ -195,22 +195,17 @@ func (evm *EVM) call(caller ContractRef, addr common.Address, input []byte, gas
return nil, gas, ErrDepth
}
// Fail if we're trying to transfer more than the available balance
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, gas, ErrInsufficientBalance
}

var (
to = AccountRef(addr)
snapshot = evm.StateDB.Snapshot()
to = AccountRef(addr)
snapshot = evm.StateDB.Snapshot()
p, isPrecompile = evm.precompile(addr)
)
if !evm.StateDB.Exist(addr) {
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsIstanbul(evm.BlockNumber) {
precompiles = PrecompiledContractsIstanbul
} else if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
return nil, gas, nil
}
evm.StateDB.CreateAccount(addr)
Expand All @@ -222,7 +217,11 @@ func (evm *EVM) call(caller ContractRef, addr common.Address, input []byte, gas
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

ret, err := run(evm, contract, input)
if isPrecompile {
ret, err = RunPrecompiledContract(p, input, contract)
} else {
ret, err = evm.interpreter.Run(contract, input)
}

// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
Expand Down Expand Up @@ -266,16 +265,22 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
}

var (
snapshot = evm.StateDB.Snapshot()
to = AccountRef(caller.Address())
snapshot = evm.StateDB.Snapshot()
to = AccountRef(caller.Address())
p, isPrecompile = evm.precompile(addr)
)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

ret, err = run(evm, contract, input)
if isPrecompile {
ret, err = RunPrecompiledContract(p, input, contract)
} else {
ret, err = evm.interpreter.Run(contract, input)
}

if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
Expand Down Expand Up @@ -308,15 +313,20 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
}

var (
snapshot = evm.StateDB.Snapshot()
to = AccountRef(caller.Address())
snapshot = evm.StateDB.Snapshot()
to = AccountRef(caller.Address())
p, isPrecompile = evm.precompile(addr)
)

// Initialise a new contract and make initialise the delegate values
contract := NewContract(caller, to, nil, gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

ret, err = run(evm, contract, input)
if isPrecompile {
ret, err = RunPrecompiledContract(p, input, contract)
} else {
ret, err = evm.interpreter.Run(contract, input)
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
Expand Down Expand Up @@ -355,19 +365,25 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}

var (
to = AccountRef(addr)
snapshot = evm.StateDB.Snapshot()
to = AccountRef(addr)
snapshot = evm.StateDB.Snapshot()
p, isPrecompile = evm.precompile(addr)
)
// Initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := NewContract(caller, to, new(big.Int), gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

if isPrecompile {
ret, err = RunPrecompiledContract(p, input, contract)
} else {
ret, err = evm.interpreter.Run(contract, input)
}

// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
ret, err = run(evm, contract, input)
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
Expand Down Expand Up @@ -447,7 +463,7 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
// Create a new account on the state
snapshot := evm.StateDB.Snapshot()
evm.StateDB.CreateAccount(contractAddr)
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
if evm.chainRules.IsEIP158 {
evm.StateDB.SetNonce(contractAddr, 1)
}

Expand All @@ -468,7 +484,7 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
return nil, contractAddr, gas, nil
}

ret, err := run(evm, contract, nil)
ret, err := evm.interpreter.Run(contract, nil)

// Check whether the max code size has been exceeded, assign err if the case.
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
Expand Down
2 changes: 2 additions & 0 deletions vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
// we'll set the default jump table.
if cfg.JumpTable == nil {
switch {
case evm.ChainConfig().IsShanghai(evm.BlockNumber):
cfg.JumpTable = shanghaiInstructionSet
case evm.ChainConfig().IsIstanbul(evm.BlockNumber):
cfg.JumpTable = istanbulInstructionSet
case evm.ChainConfig().IsConstantinople(evm.BlockNumber):
Expand Down

0 comments on commit d9b0b85

Please sign in to comment.