1717package core
1818
1919import (
20+ "errors"
2021 "fmt"
2122 "math/big"
2223
2324 "github.com/eth-classic/go-ethereum/common"
25+ "github.com/eth-classic/go-ethereum/core/state"
2426 "github.com/eth-classic/go-ethereum/core/vm"
2527 "github.com/eth-classic/go-ethereum/crypto"
28+ "github.com/eth-classic/go-ethereum/params"
2629)
2730
2831var (
32+ emptyCodeHash = crypto .Keccak256Hash (nil )
33+
2934 callCreateDepthMax = 1024 // limit call/create stack
3035 errCallCreateDepth = fmt .Errorf ("Max call depth exceeded (%d)" , callCreateDepthMax )
3136
3237 maxCodeSize = 24576
3338 errMaxCodeSizeExceeded = fmt .Errorf ("Max Code Size exceeded (%d)" , maxCodeSize )
39+
40+ errContractAddressCollision = errors .New ("contract address collision" )
3441)
3542
36- // Call executes within the given contract
43+ // Call executes the contract associated with the addr with the given input as
44+ // parameters. It also handles any necessary value transfer required and takes
45+ // the necessary steps to create accounts and reverses the state in case of an
46+ // execution error or failed value transfer.
3747func Call (env vm.Environment , caller vm.ContractRef , addr common.Address , input []byte , gas , gasPrice , value * big.Int ) (ret []byte , err error ) {
38- ret , _ , err = exec (env , caller , & addr , & addr , env .Db ().GetCodeHash (addr ), input , env .Db ().GetCode (addr ), gas , gasPrice , value , false )
48+ evm := env .Vm ()
49+ // Depth check execution. Fail if we're trying to execute above the limit.
50+ if env .Depth () > callCreateDepthMax {
51+ caller .ReturnGas (gas , gasPrice )
52+
53+ return nil , errCallCreateDepth
54+ }
55+
56+ if ! env .CanTransfer (caller .Address (), value ) {
57+ caller .ReturnGas (gas , gasPrice )
58+
59+ return nil , ValueTransferErr ("insufficient funds to transfer value. Req %v, has %v" , value , env .Db ().GetBalance (caller .Address ()))
60+ }
61+
62+ var (
63+ from = env .Db ().GetAccount (caller .Address ())
64+ to vm.Account
65+ snapshot = env .SnapshotDatabase ()
66+ isAtlantis = env .RuleSet ().IsAtlantis (env .BlockNumber ())
67+ )
68+ if ! env .Db ().Exist (addr ) {
69+ precompiles := vm .PrecompiledPreAtlantis
70+ if isAtlantis {
71+ precompiles = vm .PrecompiledAtlantis
72+ }
73+ if precompiles [addr .Str ()] == nil && isAtlantis && value .BitLen () == 0 {
74+ caller .ReturnGas (gas , gasPrice )
75+ return nil , nil
76+ }
77+ to = env .Db ().CreateAccount (addr )
78+ } else {
79+ to = env .Db ().GetAccount (addr )
80+ }
81+ env .Transfer (from , to , value )
82+ // Initialise a new contract and set the code that is to be used by the EVM.
83+ // The contract is a scoped environment for this execution context only.
84+ contract := vm .NewContract (caller , to , value , gas , gasPrice )
85+ contract .SetCallCode (& addr , env .Db ().GetCodeHash (addr ), env .Db ().GetCode (addr ))
86+ defer contract .Finalise ()
87+
88+ // Even if the account has no code, we need to continue because it might be a precompile
89+ ret , err = evm .Run (contract , input , false )
90+
91+ // When an error was returned by the EVM or when setting the creation code
92+ // above we revert to the snapshot and consume any gas remaining. Additionally
93+ // when we're in homestead this also counts for code storage gas errors.
94+ if err != nil {
95+ env .RevertToSnapshot (snapshot )
96+ if err != vm .ErrRevert {
97+ contract .UseGas (contract .Gas )
98+ }
99+ }
39100 return ret , err
40101}
41102
42103// CallCode executes the given address' code as the given contract address
43104func CallCode (env vm.Environment , caller vm.ContractRef , addr common.Address , input []byte , gas , gasPrice , value * big.Int ) (ret []byte , err error ) {
44- callerAddr := caller .Address ()
45- ret , _ , err = exec (env , caller , & callerAddr , & addr , env .Db ().GetCodeHash (addr ), input , env .Db ().GetCode (addr ), gas , gasPrice , value , false )
105+ evm := env .Vm ()
106+ // Depth check execution. Fail if we're trying to execute above the limit.
107+ if env .Depth () > callCreateDepthMax {
108+ caller .ReturnGas (gas , gasPrice )
109+
110+ return nil , errCallCreateDepth
111+ }
112+
113+ if ! env .CanTransfer (caller .Address (), value ) {
114+ caller .ReturnGas (gas , gasPrice )
115+
116+ return nil , ValueTransferErr ("insufficient funds to transfer value. Req %v, has %v" , value , env .Db ().GetBalance (caller .Address ()))
117+ }
118+
119+ var (
120+ to = env .Db ().GetAccount (caller .Address ())
121+ snapshot = env .SnapshotDatabase ()
122+ )
123+ // Initialise a new contract and set the code that is to be used by the EVM.
124+ // The contract is a scoped environment for this execution context only.
125+ contract := vm .NewContract (caller , to , value , gas , gasPrice )
126+ contract .SetCallCode (& addr , env .Db ().GetCodeHash (addr ), env .Db ().GetCode (addr ))
127+ defer contract .Finalise ()
128+
129+ // Even if the account has no code, we need to continue because it might be a precompile
130+ ret , err = evm .Run (contract , input , false )
131+
132+ if err != nil {
133+ env .RevertToSnapshot (snapshot )
134+ if err != vm .ErrRevert {
135+ contract .UseGas (contract .Gas )
136+ }
137+ }
46138 return ret , err
47139}
48140
49141// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
50142func DelegateCall (env vm.Environment , caller vm.ContractRef , addr common.Address , input []byte , gas , gasPrice * big.Int ) (ret []byte , err error ) {
51- callerAddr := caller .Address ()
52- originAddr := env .Origin ()
53- callerValue := caller .Value ()
54- ret , _ , err = execDelegateCall (env , caller , & originAddr , & callerAddr , & addr , env .Db ().GetCodeHash (addr ), input , env .Db ().GetCode (addr ), gas , gasPrice , callerValue )
143+ evm := env .Vm ()
144+ // Depth check execution. Fail if we're trying to execute above the limit.
145+ if env .Depth () > callCreateDepthMax {
146+ caller .ReturnGas (gas , gasPrice )
147+
148+ return nil , errCallCreateDepth
149+ }
150+
151+ var (
152+ to vm.Account
153+ snapshot = env .SnapshotDatabase ()
154+ )
155+ if ! env .Db ().Exist (caller .Address ()) {
156+ to = env .Db ().CreateAccount (caller .Address ())
157+ } else {
158+ to = env .Db ().GetAccount (caller .Address ())
159+ }
160+
161+ // Initialise a new contract and set the code that is to be used by the EVM.
162+ // The contract is a scoped environment for this execution context only.
163+ contract := vm .NewContract (caller , to , caller .Value (), gas , gasPrice ).AsDelegate ()
164+ contract .SetCallCode (& addr , env .Db ().GetCodeHash (addr ), env .Db ().GetCode (addr ))
165+ defer contract .Finalise ()
166+
167+ // Even if the account has no code, we need to continue because it might be a precompile
168+ ret , err = evm .Run (contract , input , false )
169+
170+ // When an error was returned by the EVM or when setting the creation code
171+ // above we revert to the snapshot and consume any gas remaining. Additionally
172+ // when we're in homestead this also counts for code storage gas errors.
173+ if err != nil {
174+ env .RevertToSnapshot (snapshot )
175+ if err != vm .ErrRevert {
176+ contract .UseGas (contract .Gas )
177+ }
178+ }
55179 return ret , err
56180}
57181
58182// StaticCall executes within the given contract and throws exception if state is attempted to be changed
59183func StaticCall (env vm.Environment , caller vm.ContractRef , addr common.Address , input []byte , gas , gasPrice * big.Int ) (ret []byte , err error ) {
60- ret , _ , err = exec (env , caller , & addr , & addr , env .Db ().GetCodeHash (addr ), input , env .Db ().GetCode (addr ), gas , gasPrice , new (big.Int ), true )
184+ evm := env .Vm ()
185+ // Depth check execution. Fail if we're trying to execute above the limit.
186+ if env .Depth () > callCreateDepthMax {
187+ caller .ReturnGas (gas , gasPrice )
188+
189+ return nil , errCallCreateDepth
190+ }
191+
192+ var (
193+ to vm.Account
194+ snapshot = env .SnapshotDatabase ()
195+ )
196+ if ! env .Db ().Exist (addr ) {
197+ to = env .Db ().CreateAccount (addr )
198+ } else {
199+ to = env .Db ().GetAccount (addr )
200+ }
201+
202+ // Initialise a new contract and set the code that is to be used by the EVM.
203+ // The contract is a scoped environment for this execution context only.
204+ contract := vm .NewContract (caller , to , new (big.Int ), gas , gasPrice )
205+ contract .SetCallCode (& addr , env .Db ().GetCodeHash (addr ), env .Db ().GetCode (addr ))
206+ defer contract .Finalise ()
207+
208+ // We do an AddBalance of zero here, just in order to trigger a touch.
209+ // This is done to keep consensus with other clients since empty objects
210+ // get touched to be deleted even in a StaticCall context
211+ env .Db ().AddBalance (addr , big .NewInt (0 ))
212+
213+ // Even if the account has no code, we need to continue because it might be a precompile
214+ ret , err = evm .Run (contract , input , true )
215+
216+ // When an error was returned by the EVM or when setting the creation code
217+ // above we revert to the snapshot and consume any gas remaining. Additionally
218+ // when we're in homestead this also counts for code storage gas errors.
219+ if err != nil {
220+ env .RevertToSnapshot (snapshot )
221+ if err != vm .ErrRevert {
222+ contract .UseGas (contract .Gas )
223+ }
224+ }
61225 return ret , err
62226}
63227
64228// Create creates a new contract with the given code
65229func Create (env vm.Environment , caller vm.ContractRef , code []byte , gas , gasPrice , value * big.Int ) (ret []byte , address common.Address , err error ) {
66- ret , address , err = exec (env , caller , nil , nil , crypto .Keccak256Hash (code ), nil , code , gas , gasPrice , value , false )
230+ ret , address , err = create (env , caller , crypto .Keccak256Hash (code ), code , gas , gasPrice , value )
67231 // Here we get an error if we run into maximum stack depth,
68232 // See: https://github.com/ethereum/yellowpaper/pull/131
69233 // and YP definitions for CREATE
@@ -75,10 +239,9 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric
75239 return ret , address , err
76240}
77241
78- func exec (env vm.Environment , caller vm.ContractRef , address , codeAddr * common. Address , codeHash common.Hash , input , code []byte , gas , gasPrice , value * big.Int , readOnly bool ) (ret []byte , addr common.Address , err error ) {
242+ func create (env vm.Environment , caller vm.ContractRef , codeHash common.Hash , code []byte , gas , gasPrice , value * big.Int ) (ret []byte , address common.Address , err error ) {
79243 evm := env .Vm ()
80- // Depth check execution. Fail if we're trying to execute above the
81- // limit.
244+ // Depth check execution. Fail if we're trying to execute above the limit.
82245 if env .Depth () > callCreateDepthMax {
83246 caller .ReturnGas (gas , gasPrice )
84247
@@ -91,39 +254,25 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
91254 return nil , common.Address {}, ValueTransferErr ("insufficient funds to transfer value. Req %v, has %v" , value , env .Db ().GetBalance (caller .Address ()))
92255 }
93256
94- var createAccount bool
95- if address == nil {
96- // Create a new account on the state
97- nonce := env .Db ().GetNonce (caller .Address ())
98- env .Db ().SetNonce (caller .Address (), nonce + 1 )
99- addr = crypto .CreateAddress (caller .Address (), nonce )
100- address = & addr
101- createAccount = true
257+ // Create a new account on the state
258+ nonce := env .Db ().GetNonce (caller .Address ())
259+ env .Db ().SetNonce (caller .Address (), nonce + 1 )
260+ address = crypto .CreateAddress (caller .Address (), nonce )
261+
262+ // Ensure there's no existing contract already at the designated address
263+ contractHash := env .Db ().GetCodeHash (address )
264+ if env .Db ().GetNonce (address ) != state .StartingNonce || (contractHash != (common.Hash {}) && contractHash != emptyCodeHash ) {
265+ return nil , common.Address {}, errContractAddressCollision
102266 }
103267
104- snapshotPreTransfer := env .SnapshotDatabase ()
105268 var (
106- from = env .Db ().GetAccount (caller .Address ())
107- to vm.Account
269+ snapshot = env .SnapshotDatabase ()
270+ from = env .Db ().GetAccount (caller .Address ())
271+ to = env .Db ().CreateAccount (address )
108272 )
109273
110- if createAccount {
111- to = env .Db ().CreateAccount (* address )
112-
113- if env .RuleSet ().IsAtlantis (env .BlockNumber ()) {
114- env .Db ().SetNonce (* address , 1 )
115- }
116- } else {
117- if ! env .Db ().Exist (* address ) {
118- //no account may change state from non-existent to existent-but-empty. Refund sender.
119- if vm .PrecompiledAtlantis [(* address ).Str ()] == nil && env .RuleSet ().IsAtlantis (env .BlockNumber ()) && value .BitLen () == 0 {
120- caller .ReturnGas (gas , gasPrice )
121- return nil , common.Address {}, nil
122- }
123- to = env .Db ().CreateAccount (* address )
124- } else {
125- to = env .Db ().GetAccount (* address )
126- }
274+ if env .RuleSet ().IsAtlantis (env .BlockNumber ()) {
275+ env .Db ().SetNonce (address , state .StartingNonce + 1 )
127276 }
128277
129278 env .Transfer (from , to , value )
@@ -132,22 +281,22 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
132281 // EVM. The contract is a scoped environment for this execution context
133282 // only.
134283 contract := vm .NewContract (caller , to , value , gas , gasPrice )
135- contract .SetCallCode (codeAddr , codeHash , code )
284+ contract .SetCallCode (nil , codeHash , code )
136285 defer contract .Finalise ()
137286
138- ret , err = evm .Run (contract , input , readOnly )
287+ ret , err = evm .Run (contract , nil , false )
139288
140289 maxCodeSizeExceeded := len (ret ) > maxCodeSize && env .RuleSet ().IsAtlantis (env .BlockNumber ())
141290 // if the contract creation ran successfully and no errors were returned
142291 // calculate the gas required to store the code. If the code could not
143292 // be stored due to not enough gas set an error and let it be handled
144293 // by the error checking condition below.
145- if err == nil && createAccount && ! maxCodeSizeExceeded {
294+ if err == nil && ! maxCodeSizeExceeded {
146295 dataGas := big .NewInt (int64 (len (ret )))
147296 // create data gas
148- dataGas .Mul (dataGas , big . NewInt ( 200 ) )
297+ dataGas .Mul (dataGas , params . CreateDataGas )
149298 if contract .UseGas (dataGas ) {
150- env .Db ().SetCode (* address , ret )
299+ env .Db ().SetCode (address , ret )
151300 } else {
152301 err = vm .CodeStoreOutOfGasError
153302 }
@@ -156,8 +305,8 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
156305 // When an error was returned by the EVM or when setting the creation code
157306 // above we revert to the snapshot and consume any gas remaining. Additionally
158307 // when we're in homestead this also counts for code storage gas errors.
159- if createAccount && maxCodeSizeExceeded || (err != nil && (env .RuleSet ().IsHomestead (env .BlockNumber ()) || err != vm .CodeStoreOutOfGasError )) {
160- env .RevertToSnapshot (snapshotPreTransfer )
308+ if maxCodeSizeExceeded || (err != nil && (env .RuleSet ().IsHomestead (env .BlockNumber ()) || err != vm .CodeStoreOutOfGasError )) {
309+ env .RevertToSnapshot (snapshot )
161310 if err != vm .ErrRevert {
162311 contract .UseGas (contract .Gas )
163312 }
@@ -168,42 +317,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
168317 err = errMaxCodeSizeExceeded
169318 }
170319
171- return ret , addr , err
172- }
173-
174- func execDelegateCall (env vm.Environment , caller vm.ContractRef , originAddr , toAddr , codeAddr * common.Address , codeHash common.Hash , input , code []byte , gas , gasPrice , value * big.Int ) (ret []byte , addr common.Address , err error ) {
175- evm := env .Vm ()
176- // Depth check execution. Fail if we're trying to execute above the
177- // limit.
178- if env .Depth () > callCreateDepthMax {
179- caller .ReturnGas (gas , gasPrice )
180- return nil , common.Address {}, errCallCreateDepth
181- }
182-
183- snapshot := env .SnapshotDatabase ()
184-
185- var to vm.Account
186- if ! env .Db ().Exist (* toAddr ) {
187- to = env .Db ().CreateAccount (* toAddr )
188- } else {
189- to = env .Db ().GetAccount (* toAddr )
190- }
191-
192- // Iinitialise a new contract and make initialise the delegate values
193- contract := vm .NewContract (caller , to , value , gas , gasPrice ).AsDelegate ()
194- contract .SetCallCode (codeAddr , codeHash , code )
195- defer contract .Finalise ()
196-
197- ret , err = evm .Run (contract , input , false )
198-
199- if err != nil {
200- env .RevertToSnapshot (snapshot )
201- if err != vm .ErrRevert {
202- contract .UseGas (contract .Gas )
203- }
204- }
205-
206- return ret , addr , err
320+ return ret , address , err
207321}
208322
209323// generic transfer method
0 commit comments