mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +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"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrecompiledAccount represents a native ethereum contract
|
// Precompiled contract is the basic interface for native Go contracts. The implementation
|
||||||
type PrecompiledAccount struct {
|
// requires a deterministic gas count based on the input size of the Run method of the
|
||||||
Gas func(l int) *big.Int
|
// contract.
|
||||||
fn func(in []byte) []byte
|
type PrecompiledContract interface {
|
||||||
}
|
RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
|
||||||
|
Run(input []byte) []byte // Run runs the precompiled contract
|
||||||
// Call calls the native function
|
|
||||||
func (self PrecompiledAccount) Call(in []byte) []byte {
|
|
||||||
return self.fn(in)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precompiled contains the default set of ethereum contracts
|
// 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
|
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||||
// contracts defined by the ethereum yellow paper.
|
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||||
func PrecompiledContracts() map[string]*PrecompiledAccount {
|
gas := p.RequiredGas(len(input))
|
||||||
return map[string]*PrecompiledAccount{
|
if contract.UseGas(gas) {
|
||||||
// ECRECOVER
|
ret = p.Run(input)
|
||||||
string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
|
||||||
|
return ret, nil
|
||||||
|
} else {
|
||||||
|
return nil, OutOfGasError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECRECOVER implemented as a native contract
|
||||||
|
type ecrecover struct{}
|
||||||
|
|
||||||
|
func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
|
||||||
return params.EcrecoverGas
|
return params.EcrecoverGas
|
||||||
}, ecrecoverFunc},
|
|
||||||
|
|
||||||
// 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},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func sha256Func(in []byte) []byte {
|
|
||||||
return crypto.Sha256(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
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, ecRecoverInputLength)
|
||||||
in = common.RightPadBytes(in, 128)
|
|
||||||
// "in" is (hash, v, r, s), each 32 bytes
|
// "in" is (hash, v, r, s), each 32 bytes
|
||||||
// but for ecrecover we want (r, s, v)
|
// 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)
|
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
|
return in
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func (env *Environment) Call(caller ContractRef, addr common.Address, input []by
|
||||||
snapshotPreTransfer = env.StateDB.Snapshot()
|
snapshotPreTransfer = env.StateDB.Snapshot()
|
||||||
)
|
)
|
||||||
if !env.StateDB.Exist(addr) {
|
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)
|
caller.ReturnGas(gas)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,8 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
defer func() { evm.env.Depth-- }()
|
defer func() { evm.env.Depth-- }()
|
||||||
|
|
||||||
if contract.CodeAddr != nil {
|
if contract.CodeAddr != nil {
|
||||||
if p := Precompiled[contract.CodeAddr.Str()]; p != nil {
|
if p := PrecompiledContracts[*contract.CodeAddr]; p != nil {
|
||||||
return evm.RunPrecompiled(p, input, contract)
|
return RunPrecompiledContract(p, input, contract)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,15 +192,3 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
return nil, nil
|
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) {
|
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)
|
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"]))
|
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
|
||||||
|
|
||||||
root, _ := statedb.Commit(false)
|
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"])
|
value = common.Big(exec["value"])
|
||||||
)
|
)
|
||||||
caller := statedb.GetOrNewStateObject(from)
|
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)
|
environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
|
||||||
ret, err := environment.Call(caller, to, data, gas, value)
|
ret, err := environment.Call(caller, to, data, gas, value)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue