@@ -44,7 +44,6 @@ func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address
44
44
originAddr := env .Origin ()
45
45
callerValue := caller .Value ()
46
46
ret , _ , err = execDelegateCall (env , caller , & originAddr , & callerAddr , & addr , input , env .Db ().GetCode (addr ), gas , gasPrice , callerValue )
47
- caller .SetAddress (callerAddr )
48
47
return ret , err
49
48
}
50
49
@@ -78,15 +77,15 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
78
77
79
78
var createAccount bool
80
79
if address == nil {
81
- // Generate a new address
80
+ // Create a new account on the state
82
81
nonce := env .Db ().GetNonce (caller .Address ())
83
82
env .Db ().SetNonce (caller .Address (), nonce + 1 )
84
83
addr = crypto .CreateAddress (caller .Address (), nonce )
85
84
address = & addr
86
85
createAccount = true
87
86
}
88
- snapshotPreTransfer := env .MakeSnapshot ()
89
87
88
+ snapshotPreTransfer := env .MakeSnapshot ()
90
89
var (
91
90
from = env .Db ().GetAccount (caller .Address ())
92
91
to vm.Account
@@ -101,24 +100,38 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
101
100
}
102
101
}
103
102
env .Transfer (from , to , value )
104
- snapshotPostTransfer := env .MakeSnapshot ()
105
103
104
+ // initialise a new contract and set the code that is to be used by the
105
+ // EVM. The contract is a scoped environment for this execution context
106
+ // only.
106
107
contract := vm .NewContract (caller , to , value , gas , gasPrice )
107
108
contract .SetCallCode (codeAddr , code )
109
+ defer contract .Finalise ()
108
110
109
111
ret , err = evm .Run (contract , input )
110
-
111
- if err != nil {
112
- if err == vm .CodeStoreOutOfGasError {
113
- // TODO: this is rather hacky, restore all state changes
114
- // except sender's account nonce increment
115
- toNonce := env .Db ().GetNonce (to .Address ())
116
- env .SetSnapshot (snapshotPostTransfer )
117
- env .Db ().SetNonce (to .Address (), toNonce )
112
+ // if the contract creation ran successfully and no errors were returned
113
+ // calculate the gas required to store the code. If the code could not
114
+ // be stored due to not enough gas set an error and let it be handled
115
+ // by the error checking condition below.
116
+ if err == nil && createAccount {
117
+ dataGas := big .NewInt (int64 (len (ret )))
118
+ dataGas .Mul (dataGas , params .CreateDataGas )
119
+ if contract .UseGas (dataGas ) {
120
+ env .Db ().SetCode (* address , ret )
118
121
} else {
119
- env . SetSnapshot ( snapshotPreTransfer ) //env.Db().Set(snapshot)
122
+ err = vm . CodeStoreOutOfGasError
120
123
}
121
124
}
125
+
126
+ // When an error was returned by the EVM or when setting the creation code
127
+ // above we revert to the snapshot and consume any gas remaining. Additionally
128
+ // when we're in homestead this also counts for code storage gas errors.
129
+ if err != nil && (params .IsHomestead (env .BlockNumber ()) || err != vm .CodeStoreOutOfGasError ) {
130
+ contract .UseGas (contract .Gas )
131
+
132
+ env .SetSnapshot (snapshotPreTransfer )
133
+ }
134
+
122
135
return ret , addr , err
123
136
}
124
137
@@ -131,32 +144,27 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA
131
144
return nil , common.Address {}, vm .DepthError
132
145
}
133
146
134
- if ! env .CanTransfer (* originAddr , value ) {
135
- caller .ReturnGas (gas , gasPrice )
136
- return nil , common.Address {}, ValueTransferErr ("insufficient funds to transfer value. Req %v, has %v" , value , env .Db ().GetBalance (caller .Address ()))
137
- }
138
-
139
147
snapshot := env .MakeSnapshot ()
140
148
141
- var (
142
- //from = env.Db().GetAccount(*originAddr)
143
- to vm.Account
144
- )
149
+ var to vm.Account
145
150
if ! env .Db ().Exist (* toAddr ) {
146
151
to = env .Db ().CreateAccount (* toAddr )
147
152
} else {
148
153
to = env .Db ().GetAccount (* toAddr )
149
154
}
150
155
151
- contract := vm .NewContract (caller , to , value , gas , gasPrice )
156
+ // Iinitialise a new contract and make initialise the delegate values
157
+ contract := vm .NewContract (caller , to , value , gas , gasPrice ).AsDelegate ()
152
158
contract .SetCallCode (codeAddr , code )
153
- contract .DelegateCall = true
159
+ defer contract .Finalise ()
154
160
155
161
ret , err = evm .Run (contract , input )
156
-
157
162
if err != nil {
158
- env .SetSnapshot (snapshot ) //env.Db().Set(snapshot)
163
+ contract .UseGas (contract .Gas )
164
+
165
+ env .SetSnapshot (snapshot )
159
166
}
167
+
160
168
return ret , addr , err
161
169
}
162
170
0 commit comments