@@ -91,67 +91,104 @@ func (ae *AccessEvents) Copy() *AccessEvents {
9191 return cpy
9292}
9393
94- // AddAccount returns the gas to be charged for each of the currently cold
95- // member fields of an account.
96- func (ae * AccessEvents ) AddAccount (addr common.Address , isWrite bool , availableGas uint64 ) uint64 {
97- var gas uint64 // accumulate the consumed gas
98- consumed , expected := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , isWrite , availableGas )
99- if consumed < expected {
100- return expected
101- }
102- gas += consumed
103- consumed , expected = ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , isWrite , availableGas - consumed )
104- if consumed < expected {
105- return expected + gas
106- }
107- gas += expected
108- return gas
94+ // AddAccount returns the gas cost for each currently cold member field of
95+ // an account. If the available gas is insufficient to cover the total cost,
96+ // a false flag is returned.
97+ func (ae * AccessEvents ) AddAccount (addr common.Address , isWrite bool , availableGas uint64 ) (uint64 , bool ) {
98+ var gas uint64
99+ cost , sufficient := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , isWrite , availableGas )
100+ if ! sufficient {
101+ return 0 , false
102+ }
103+ gas += cost
104+
105+ cost , sufficient = ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , isWrite , availableGas - cost )
106+ if ! sufficient {
107+ return 0 , false
108+ }
109+ gas += cost
110+ return gas , true
109111}
110112
111113// MessageCallGas returns the gas to be charged for each of the currently
112- // cold member fields of an account, that need to be touched when making a message
113- // call to that account.
114- func (ae * AccessEvents ) MessageCallGas (destination common.Address , availableGas uint64 ) uint64 {
115- _ , expected := ae .touchAddressAndChargeGas (destination , zeroTreeIndex , utils .BasicDataLeafKey , false , availableGas )
116- if expected == 0 {
117- expected = params .WarmStorageReadCostEIP2929
118- }
119- return expected
114+ // cold member fields of an account, that need to be touched when making
115+ // a message call to that account. If the available gas is insufficient to
116+ // cover the total cost, a false flag is returned.
117+ func (ae * AccessEvents ) MessageCallGas (destination common.Address , availableGas uint64 ) (uint64 , bool ) {
118+ cost , sufficient := ae .touchAddressAndChargeGas (destination , zeroTreeIndex , utils .BasicDataLeafKey , false , availableGas )
119+ if ! sufficient {
120+ return 0 , false
121+ }
122+ if cost == 0 {
123+ if availableGas < params .WarmStorageReadCostEIP2929 {
124+ return 0 , false
125+ }
126+ cost = params .WarmStorageReadCostEIP2929
127+ }
128+ return cost , true
120129}
121130
122131// ValueTransferGas returns the gas to be charged for each of the currently
123- // cold balance member fields of the caller and the callee accounts.
124- func (ae * AccessEvents ) ValueTransferGas (callerAddr , targetAddr common.Address , availableGas uint64 ) uint64 {
125- _ , expected1 := ae .touchAddressAndChargeGas (callerAddr , zeroTreeIndex , utils .BasicDataLeafKey , true , availableGas )
126- if expected1 > availableGas {
127- return expected1
132+ // cold balance member fields of the caller and the callee accounts. If the
133+ // available gas is insufficient to cover the total cost, a false flag is
134+ // returned.
135+ func (ae * AccessEvents ) ValueTransferGas (callerAddr , targetAddr common.Address , availableGas uint64 ) (uint64 , bool ) {
136+ var gas uint64
137+ cost , sufficient := ae .touchAddressAndChargeGas (callerAddr , zeroTreeIndex , utils .BasicDataLeafKey , true , availableGas )
138+ if ! sufficient {
139+ return 0 , false
128140 }
129- _ , expected2 := ae .touchAddressAndChargeGas (targetAddr , zeroTreeIndex , utils .BasicDataLeafKey , true , availableGas - expected1 )
130- if expected1 + expected2 > availableGas {
131- return params .WarmStorageReadCostEIP2929
141+ gas += cost
142+
143+ cost , sufficient = ae .touchAddressAndChargeGas (targetAddr , zeroTreeIndex , utils .BasicDataLeafKey , true , availableGas - cost )
144+ if ! sufficient {
145+ return 0 , false
132146 }
133- return expected1 + expected2
147+ gas += cost
148+
149+ return gas , true
134150}
135151
136- // ContractCreatePreCheckGas charges access costs before
137- // a contract creation is initiated. It is just reads, because the
138- // address collision is done before the transfer, and so no write
139- // are guaranteed to happen at this point.
140- func (ae * AccessEvents ) ContractCreatePreCheckGas (addr common.Address , availableGas uint64 ) uint64 {
141- consumed , expected1 := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , false , availableGas )
142- _ , expected2 := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , false , availableGas - consumed )
143- return expected1 + expected2
152+ // ContractCreatePreCheckGas charges access costs before a contract creation is
153+ // initiated. It is just reads, because the address collision is done before
154+ // the transfer, and so no write are guaranteed to happen at this point.
155+ // If the available gas is insufficient to cover the total cost, a false flag is
156+ // returned.
157+ func (ae * AccessEvents ) ContractCreatePreCheckGas (addr common.Address , availableGas uint64 ) (uint64 , bool ) {
158+ var gas uint64
159+ cost , sufficient := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , false , availableGas )
160+ if ! sufficient {
161+ return 0 , false
162+ }
163+ gas += cost
164+
165+ cost , sufficient = ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , false , availableGas - cost )
166+ if ! sufficient {
167+ return 0 , false
168+ }
169+ gas += cost
170+
171+ return gas , false
144172}
145173
146174// ContractCreateInitGas returns the access gas costs for the initialization of
147- // a contract creation.
148- func (ae * AccessEvents ) ContractCreateInitGas (addr common.Address , availableGas uint64 ) (uint64 , uint64 ) {
175+ // a contract creation. If the available gas is insufficient to cover the total
176+ // cost, a false flag is returned.
177+ func (ae * AccessEvents ) ContractCreateInitGas (addr common.Address , availableGas uint64 ) (uint64 , bool ) {
149178 var gas uint64
150- consumed , expected1 := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , true , availableGas )
151- gas += consumed
152- consumed , expected2 := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , true , availableGas - consumed )
153- gas += consumed
154- return gas , expected1 + expected2
179+ cost , sufficient := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , true , availableGas )
180+ if ! sufficient {
181+ return 0 , false
182+ }
183+ gas += cost
184+
185+ cost , sufficient = ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , true , availableGas - cost )
186+ if ! sufficient {
187+ return 0 , false
188+ }
189+ gas += cost
190+
191+ return gas , true
155192}
156193
157194// AddTxOrigin adds the member fields of the sender account to the access event list,
@@ -169,18 +206,28 @@ func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue, doesnt
169206}
170207
171208// SlotGas returns the amount of gas to be charged for a cold storage access.
172- func (ae * AccessEvents ) SlotGas (addr common.Address , slot common.Hash , isWrite bool , availableGas uint64 , chargeWarmCosts bool ) uint64 {
209+ // If the available gas is insufficient to cover the total cost, a false flag
210+ // is returned.
211+ func (ae * AccessEvents ) SlotGas (addr common.Address , slot common.Hash , isWrite bool , availableGas uint64 , chargeWarmCosts bool ) (uint64 , bool ) {
173212 treeIndex , subIndex := utils .StorageIndex (slot .Bytes ())
174- _ , expected := ae .touchAddressAndChargeGas (addr , * treeIndex , subIndex , isWrite , availableGas )
175- if expected == 0 && chargeWarmCosts {
176- expected = params .WarmStorageReadCostEIP2929
213+ cost , sufficient := ae .touchAddressAndChargeGas (addr , * treeIndex , subIndex , isWrite , availableGas )
214+ if ! sufficient {
215+ return 0 , false
216+ }
217+ if cost == 0 && chargeWarmCosts {
218+ if availableGas < params .WarmStorageReadCostEIP2929 {
219+ return 0 , false
220+ }
221+ cost = params .WarmStorageReadCostEIP2929
177222 }
178- return expected
223+ return cost , true
179224}
180225
181- // touchAddressAndChargeGas adds any missing access event to the access event list, and returns the
182- // consumed and required gas.
183- func (ae * AccessEvents ) touchAddressAndChargeGas (addr common.Address , treeIndex uint256.Int , subIndex byte , isWrite bool , availableGas uint64 ) (uint64 , uint64 ) {
226+ // touchAddressAndChargeGas adds a missing access event to the access list, if needed,
227+ // and returns the cold access cost to be charged. Additionally, it returns a flag
228+ // indicating whether there is enough available gas to cover the cost. If not,
229+ // the event will not be included.
230+ func (ae * AccessEvents ) touchAddressAndChargeGas (addr common.Address , treeIndex uint256.Int , subIndex byte , isWrite bool , availableGas uint64 ) (uint64 , bool ) {
184231 branchKey := newBranchAccessKey (addr , treeIndex )
185232 chunkKey := newChunkAccessKey (branchKey , subIndex )
186233
@@ -224,8 +271,7 @@ func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex
224271 }
225272
226273 if availableGas < gas {
227- // consumed != expected
228- return availableGas , gas
274+ return 0 , false
229275 }
230276
231277 if branchRead {
@@ -241,8 +287,8 @@ func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex
241287 ae .chunks [chunkKey ] |= AccessWitnessWriteFlag
242288 }
243289
244- // consumed == expected
245- return gas , gas
290+ // consumed == wanted
291+ return gas , true
246292}
247293
248294type branchAccessKey struct {
@@ -269,16 +315,18 @@ func newChunkAccessKey(branchKey branchAccessKey, leafKey byte) chunkAccessKey {
269315 return lk
270316}
271317
272- // CodeChunksRangeGas is a helper function to touch every chunk in a code range and charge witness gas costs
273- func (ae * AccessEvents ) CodeChunksRangeGas (contractAddr common.Address , startPC , size uint64 , codeLen uint64 , isWrite bool , availableGas uint64 ) (uint64 , uint64 ) {
274- // note that in the case where the copied code is outside the range of the
318+ // CodeChunksRangeGas is a helper function to touch every chunk in a code range
319+ // and charge witness gas costs. If the available gas is insufficient to cover
320+ // the total cost, a false flag is returned.
321+ func (ae * AccessEvents ) CodeChunksRangeGas (contractAddr common.Address , startPC , size uint64 , codeLen uint64 , isWrite bool , availableGas uint64 ) (uint64 , bool ) {
322+ // Note that in the case where the copied code is outside the range of the
275323 // contract code but touches the last leaf with contract code in it,
276- // we don't include the last leaf of code in the AccessWitness. The
324+ // we don't include the last leaf of code in the AccessWitness. The
277325 // reason that we do not need the last leaf is the account's code size
278326 // is already in the AccessWitness so a stateless verifier can see that
279327 // the code from the last leaf is not needed.
280328 if (codeLen == 0 && size == 0 ) || startPC > codeLen {
281- return 0 , 0
329+ return 0 , true
282330 }
283331
284332 endPC := startPC + size
@@ -293,48 +341,55 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
293341 for chunkNumber := startPC / 31 ; chunkNumber <= endPC / 31 ; chunkNumber ++ {
294342 treeIndex := * uint256 .NewInt ((chunkNumber + 128 ) / 256 )
295343 subIndex := byte ((chunkNumber + 128 ) % 256 )
296- consumed , expected := ae .touchAddressAndChargeGas (contractAddr , treeIndex , subIndex , isWrite , availableGas )
344+ cost , sufficient := ae .touchAddressAndChargeGas (contractAddr , treeIndex , subIndex , isWrite , availableGas )
297345 // did we OOG ?
298- if expected > consumed {
299- return statelessGasCharged + consumed , statelessGasCharged + expected
346+ if ! sufficient {
347+ return 0 , false
300348 }
301349 var overflow bool
302- statelessGasCharged , overflow = math .SafeAdd (statelessGasCharged , consumed )
350+ statelessGasCharged , overflow = math .SafeAdd (statelessGasCharged , cost )
303351 if overflow {
352+ //return 0, false
304353 panic ("overflow when adding gas" )
305354 }
306- availableGas -= consumed
355+ availableGas -= cost
307356 }
308- return statelessGasCharged , statelessGasCharged
357+ return statelessGasCharged , true
309358}
310359
311360// BasicDataGas adds the account's basic data to the accessed data, and returns the
312361// amount of gas that it costs.
313362// Note that an access in write mode implies an access in read mode, whereas an
314363// access in read mode does not imply an access in write mode.
315- func (ae * AccessEvents ) BasicDataGas (addr common.Address , isWrite bool , availableGas uint64 , chargeWarmCosts bool ) uint64 {
316- _ , expected := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , isWrite , availableGas )
317- if expected == 0 && chargeWarmCosts {
364+ func (ae * AccessEvents ) BasicDataGas (addr common.Address , isWrite bool , availableGas uint64 , chargeWarmCosts bool ) (uint64 , bool ) {
365+ cost , sufficient := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .BasicDataLeafKey , isWrite , availableGas )
366+ if ! sufficient {
367+ return 0 , false
368+ }
369+ if cost == 0 && chargeWarmCosts {
318370 if availableGas < params .WarmStorageReadCostEIP2929 {
319- return availableGas
371+ return 0 , false
320372 }
321- expected = params .WarmStorageReadCostEIP2929
373+ cost = params .WarmStorageReadCostEIP2929
322374 }
323- return expected
375+ return cost , true
324376}
325377
326378// CodeHashGas adds the account's code hash to the accessed data, and returns the
327379// amount of gas that it costs.
328380// in write mode. If false, the charged gas corresponds to an access in read mode.
329381// Note that an access in write mode implies an access in read mode, whereas an access in
330382// read mode does not imply an access in write mode.
331- func (ae * AccessEvents ) CodeHashGas (addr common.Address , isWrite bool , availableGas uint64 , chargeWarmCosts bool ) uint64 {
332- _ , expected := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , isWrite , availableGas )
333- if expected == 0 && chargeWarmCosts {
383+ func (ae * AccessEvents ) CodeHashGas (addr common.Address , isWrite bool , availableGas uint64 , chargeWarmCosts bool ) (uint64 , bool ) {
384+ cost , sufficient := ae .touchAddressAndChargeGas (addr , zeroTreeIndex , utils .CodeHashLeafKey , isWrite , availableGas )
385+ if ! sufficient {
386+ return 0 , false
387+ }
388+ if cost == 0 && chargeWarmCosts {
334389 if availableGas < params .WarmStorageReadCostEIP2929 {
335- return availableGas
390+ return 0 , false
336391 }
337- expected = params .WarmStorageReadCostEIP2929
392+ cost = params .WarmStorageReadCostEIP2929
338393 }
339- return expected
394+ return cost , true
340395}
0 commit comments