mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
core/vm, tests: refactored precompiled contracts
This commit is contained in:
parent
b4fff69f72
commit
0abf68b533
5 changed files with 66 additions and 66 deletions
|
|
@ -26,64 +26,45 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// PrecompiledAccount represents a native ethereum contract
|
||||
type PrecompiledAccount struct {
|
||||
Gas func(l int) *big.Int
|
||||
fn func(in []byte) []byte
|
||||
}
|
||||
|
||||
// Call calls the native function
|
||||
func (self PrecompiledAccount) Call(in []byte) []byte {
|
||||
return self.fn(in)
|
||||
// Precompiled contract is the basic interface for native Go contracts. The implementation
|
||||
// requires a deterministic gas count based on the input size of the Run method of the
|
||||
// contract.
|
||||
type PrecompiledContract interface {
|
||||
RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
|
||||
Run(input []byte) []byte // Run runs the precompiled contract
|
||||
}
|
||||
|
||||
// Precompiled contains the default set of ethereum contracts
|
||||
var Precompiled = PrecompiledContracts()
|
||||
var PrecompiledContracts = map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||
common.BytesToAddress([]byte{2}): &sha256{},
|
||||
common.BytesToAddress([]byte{3}): &ripemd160{},
|
||||
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||
}
|
||||
|
||||
// PrecompiledContracts returns the default set of precompiled ethereum
|
||||
// contracts defined by the ethereum yellow paper.
|
||||
func PrecompiledContracts() map[string]*PrecompiledAccount {
|
||||
return map[string]*PrecompiledAccount{
|
||||
// ECRECOVER
|
||||
string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
||||
return params.EcrecoverGas
|
||||
}, ecrecoverFunc},
|
||||
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||
gas := p.RequiredGas(len(input))
|
||||
if contract.UseGas(gas) {
|
||||
ret = p.Run(input)
|
||||
|
||||
// SHA256
|
||||
string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
||||
n := big.NewInt(int64(l+31) / 32)
|
||||
n.Mul(n, params.Sha256WordGas)
|
||||
return n.Add(n, params.Sha256Gas)
|
||||
}, sha256Func},
|
||||
|
||||
// RIPEMD160
|
||||
string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
||||
n := big.NewInt(int64(l+31) / 32)
|
||||
n.Mul(n, params.Ripemd160WordGas)
|
||||
return n.Add(n, params.Ripemd160Gas)
|
||||
}, ripemd160Func},
|
||||
|
||||
string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
||||
n := big.NewInt(int64(l+31) / 32)
|
||||
n.Mul(n, params.IdentityWordGas)
|
||||
|
||||
return n.Add(n, params.IdentityGas)
|
||||
}, memCpy},
|
||||
return ret, nil
|
||||
} else {
|
||||
return nil, OutOfGasError
|
||||
}
|
||||
}
|
||||
|
||||
func sha256Func(in []byte) []byte {
|
||||
return crypto.Sha256(in)
|
||||
// ECRECOVER implemented as a native contract
|
||||
type ecrecover struct{}
|
||||
|
||||
func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
|
||||
return params.EcrecoverGas
|
||||
}
|
||||
|
||||
func ripemd160Func(in []byte) []byte {
|
||||
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
|
||||
}
|
||||
func (c *ecrecover) Run(in []byte) []byte {
|
||||
const ecRecoverInputLength = 128
|
||||
|
||||
const ecRecoverInputLength = 128
|
||||
|
||||
func ecrecoverFunc(in []byte) []byte {
|
||||
in = common.RightPadBytes(in, 128)
|
||||
in = common.RightPadBytes(in, ecRecoverInputLength)
|
||||
// "in" is (hash, v, r, s), each 32 bytes
|
||||
// but for ecrecover we want (r, s, v)
|
||||
|
||||
|
|
@ -114,6 +95,39 @@ func ecrecoverFunc(in []byte) []byte {
|
|||
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32)
|
||||
}
|
||||
|
||||
func memCpy(in []byte) []byte {
|
||||
// SHA256 implemented as a native contract
|
||||
type sha256 struct{}
|
||||
|
||||
func (c *sha256) RequiredGas(inputSize int) *big.Int {
|
||||
n := big.NewInt(int64(inputSize+31) / 32)
|
||||
n.Mul(n, params.Sha256WordGas)
|
||||
return n.Add(n, params.Sha256Gas)
|
||||
}
|
||||
func (c *sha256) Run(in []byte) []byte {
|
||||
return crypto.Sha256(in)
|
||||
}
|
||||
|
||||
// RIPMED160 implemented as a native contract
|
||||
type ripemd160 struct{}
|
||||
|
||||
func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
|
||||
n := big.NewInt(int64(inputSize+31) / 32)
|
||||
n.Mul(n, params.Ripemd160WordGas)
|
||||
return n.Add(n, params.Ripemd160Gas)
|
||||
}
|
||||
func (c *ripemd160) Run(in []byte) []byte {
|
||||
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
|
||||
}
|
||||
|
||||
// data copy implemented as a native contract
|
||||
type dataCopy struct{}
|
||||
|
||||
func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
|
||||
n := big.NewInt(int64(inputSize+31) / 32)
|
||||
n.Mul(n, params.IdentityWordGas)
|
||||
|
||||
return n.Add(n, params.IdentityGas)
|
||||
}
|
||||
func (c *dataCopy) Run(in []byte) []byte {
|
||||
return in
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ func (env *Environment) Call(caller ContractRef, addr common.Address, input []by
|
|||
snapshotPreTransfer = env.StateDB.Snapshot()
|
||||
)
|
||||
if !env.StateDB.Exist(addr) {
|
||||
if Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber) && value.BitLen() == 0 {
|
||||
if PrecompiledContracts[addr] == nil && env.ChainConfig().IsEIP158(env.BlockNumber) && value.BitLen() == 0 {
|
||||
caller.ReturnGas(gas)
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
|||
defer func() { evm.env.Depth-- }()
|
||||
|
||||
if contract.CodeAddr != nil {
|
||||
if p := Precompiled[contract.CodeAddr.Str()]; p != nil {
|
||||
return evm.RunPrecompiled(p, input, contract)
|
||||
if p := PrecompiledContracts[*contract.CodeAddr]; p != nil {
|
||||
return RunPrecompiledContract(p, input, contract)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,15 +192,3 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
|||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||
func (evm *EVM) RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Contract) (ret []byte, err error) {
|
||||
gas := p.Gas(len(input))
|
||||
if contract.UseGas(gas) {
|
||||
ret = p.Call(input)
|
||||
|
||||
return ret, nil
|
||||
} else {
|
||||
return nil, OutOfGasError
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,8 +205,6 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
|
|||
|
||||
func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) {
|
||||
environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx)
|
||||
// Set pre compiled contracts
|
||||
vm.Precompiled = vm.PrecompiledContracts()
|
||||
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
|
||||
|
||||
root, _ := statedb.Commit(false)
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs
|
|||
value = common.Big(exec["value"])
|
||||
)
|
||||
caller := statedb.GetOrNewStateObject(from)
|
||||
vm.Precompiled = make(map[string]*vm.PrecompiledAccount)
|
||||
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
||||
|
||||
environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
|
||||
ret, err := environment.Call(caller, to, data, gas, value)
|
||||
|
|
|
|||
Loading…
Reference in a new issue