mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
core/vm, tests: refactored native contracts
Refactored native contract such that native contract can be easily extended using a struct that implements the vm.NativeContract interface.
This commit is contained in:
parent
9182d80946
commit
b5d6206bdc
4 changed files with 59 additions and 57 deletions
|
|
@ -26,25 +26,27 @@ 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{},
|
||||||
|
}
|
||||||
|
|
||||||
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||||
func RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Contract) (ret []byte, err error) {
|
func RunPrecompiled(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||||
gas := p.Gas(len(input))
|
gas := p.RequiredGas(len(input))
|
||||||
if contract.UseGas(gas.Uint64()) {
|
if contract.UseGas(gas.Uint64()) {
|
||||||
ret = p.Call(input)
|
ret = p.Run(input)
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -52,50 +54,17 @@ func RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Contract) (re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrecompiledContracts returns the default set of precompiled ethereum
|
// ECRECOVER implemented as a native contract
|
||||||
// contracts defined by the ethereum yellow paper.
|
type ecrecover struct{}
|
||||||
func PrecompiledContracts() map[string]*PrecompiledAccount {
|
|
||||||
return map[string]*PrecompiledAccount{
|
func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
|
||||||
// ECRECOVER
|
|
||||||
string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l 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 {
|
func (c *ecrecover) Run(in []byte) []byte {
|
||||||
return crypto.Sha256(in)
|
const ecRecoverInputLength = 128
|
||||||
}
|
|
||||||
|
|
||||||
func ripemd160Func(in []byte) []byte {
|
in = common.RightPadBytes(in, ecRecoverInputLength)
|
||||||
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ecRecoverInputLength = 128
|
|
||||||
|
|
||||||
func ecrecoverFunc(in []byte) []byte {
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
@ -126,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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) ([]byte, error) {
|
||||||
defer evm.env.SetDepth(evm.env.Depth() - 1)
|
defer evm.env.SetDepth(evm.env.Depth() - 1)
|
||||||
|
|
||||||
if contract.CodeAddr != nil {
|
if contract.CodeAddr != nil {
|
||||||
if p := Precompiled[contract.CodeAddr.Str()]; p != nil {
|
if p, exist := PrecompiledContracts[*contract.CodeAddr]; exist {
|
||||||
return RunPrecompiled(p, input, contract)
|
return RunPrecompiled(p, input, contract)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ func RunState(ruleSet RuleSet, statedb *state.StateDB, env, tx map[string]string
|
||||||
to = &t
|
to = &t
|
||||||
}
|
}
|
||||||
// Set pre compiled contracts
|
// Set pre compiled contracts
|
||||||
vm.Precompiled = vm.PrecompiledContracts()
|
//vm.Precompiled = vm.PrecompiledContracts()
|
||||||
snapshot := statedb.Copy()
|
snapshot := statedb.Copy()
|
||||||
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
|
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs,
|
||||||
value = common.Big(exec["value"])
|
value = common.Big(exec["value"])
|
||||||
)
|
)
|
||||||
// Reset the pre-compiled contracts for VM tests.
|
// Reset the pre-compiled contracts for VM tests.
|
||||||
vm.Precompiled = make(map[string]*vm.PrecompiledAccount)
|
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
||||||
|
|
||||||
caller := state.GetOrNewStateObject(from)
|
caller := state.GetOrNewStateObject(from)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue