aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/contracts.go
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2017-01-05 18:52:10 +0800
committerFelix Lange <fjl@users.noreply.github.com>2017-01-05 18:52:10 +0800
commitbbc4ea4ae8e8a962deae3d5693d9d4a9376eab88 (patch)
treed4743eaa073d1bc7788f5d4fc3771da37f3cb0b5 /core/vm/contracts.go
parent2126d8148806b6d8597d6a1c761080e9dc98d745 (diff)
downloaddexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.tar
dexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.tar.gz
dexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.tar.bz2
dexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.tar.lz
dexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.tar.xz
dexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.tar.zst
dexon-bbc4ea4ae8e8a962deae3d5693d9d4a9376eab88.zip
core/vm: improved EVM run loop & instruction calling (#3378)
The run loop, which previously contained custom opcode executes have been removed and has been simplified to a few checks. Each operation consists of 4 elements: execution function, gas cost function, stack validation function and memory size function. The execution function implements the operation's runtime behaviour, the gas cost function implements the operation gas costs function and greatly depends on the memory and stack, the stack validation function validates the stack and makes sure that enough items can be popped off and pushed on and the memory size function calculates the memory required for the operation and returns it. This commit also allows the EVM to go unmetered. This is helpful for offline operations such as contract calls.
Diffstat (limited to 'core/vm/contracts.go')
-rw-r--r--core/vm/contracts.go110
1 files changed, 62 insertions, 48 deletions
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 5cd0d0bb1..9645d268f 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -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
+// 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
}
-// Call calls the native function
-func (self PrecompiledAccount) Call(in []byte) []byte {
- return self.fn(in)
+// Precompiled contains the default set of ethereum contracts
+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{},
}
-// Precompiled contains the default set of ethereum contracts
-var Precompiled = PrecompiledContracts()
-
-// 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},
-
- // 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},
+// 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)
+
+ return ret, nil
+ } else {
+ return nil, ErrOutOfGas
}
}
-func sha256Func(in []byte) []byte {
- return crypto.Sha256(in)
-}
+// ECRECOVER implemented as a native contract
+type ecrecover struct{}
-func ripemd160Func(in []byte) []byte {
- return common.LeftPadBytes(crypto.Ripemd160(in), 32)
+func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
+ return params.EcrecoverGas
}
-const ecRecoverInputLength = 128
+func (c *ecrecover) Run(in []byte) []byte {
+ 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)
@@ -108,6 +89,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
}