@@ -10,6 +10,7 @@ import {
10
10
bytesToHex ,
11
11
createAddressFromBigInt ,
12
12
equalsBytes ,
13
+ hexToBigInt ,
13
14
setLengthLeft ,
14
15
setLengthRight ,
15
16
} from '@ethereumjs/util'
@@ -197,31 +198,74 @@ export function maxCallGas(
197
198
}
198
199
}
199
200
200
- /**
201
- * Subtracts the amount needed for memory usage from `runState.gasLeft`
202
- */
203
- export function subMemUsage ( runState : RunState , offset : bigint , length : bigint , common : Common ) {
201
+ export function isPowerOfTwo ( val : bigint ) : boolean {
202
+ if ( val <= 0n ) return false
203
+
204
+ const bin = val . toString ( 2 )
205
+ const topBitIndex = bin . length - 1
206
+ const cleared = val - ( 1n << BigInt ( topBitIndex ) )
207
+
208
+ return cleared === 0n
209
+ }
210
+
211
+ export function evmmaxMemoryGasCost (
212
+ runState : RunState ,
213
+ common : Common ,
214
+ newEVMMAXMemSize : bigint ,
215
+ offset : bigint ,
216
+ length : bigint ,
217
+ ) {
218
+ if ( runState . memoryWordCount === 0n && newEVMMAXMemSize === 0n ) {
219
+ return 0n
220
+ }
221
+
204
222
// YP (225): access with zero length will not extend the memory
205
223
if ( length === BIGINT_0 ) return BIGINT_0
206
224
207
225
const newMemoryWordCount = divCeil ( offset + length , BIGINT_32 )
208
226
if ( newMemoryWordCount <= runState . memoryWordCount ) return BIGINT_0
209
227
210
- const words = newMemoryWordCount
211
- const fee = common . param ( 'memoryGas' )
212
- const quadCoefficient = common . param ( 'quadCoefficientDivGas' )
213
- // words * 3 + words ^2 / 512
214
- let cost = words * fee + ( words * words ) / quadCoefficient
228
+ let newMemSize = newMemoryWordCount
215
229
216
- if ( cost > runState . highestMemCost ) {
217
- const currentHighestMemCost = runState . highestMemCost
218
- runState . highestMemCost = cost
219
- cost -= currentHighestMemCost
230
+ if ( newMemSize > hexToBigInt ( '0x1FFFFFFFE0' ) ) {
231
+ trap ( 'gas uint64 overflow' ) // TODO is there an error code for gas overflow?
220
232
}
233
+ const newMemSizePadded = newMemSize * 32n
221
234
222
- runState . memoryWordCount = newMemoryWordCount
235
+ const curEVMMAXMemSizePadded = runState . evmmaxState . getActive ( ) . getAllocatedSize ( ) * 32
236
+ const newEVMMAXMemSizePadded = Number ( newEVMMAXMemSize ) * 32
223
237
224
- return cost
238
+ if (
239
+ newMemSizePadded > BigInt ( runState . memory . _store . length ) ||
240
+ newEVMMAXMemSizePadded > curEVMMAXMemSizePadded
241
+ ) {
242
+ if ( newMemSize <= BigInt ( runState . memory . _store . length ) ) {
243
+ newMemSize = BigInt ( runState . memory . _store . length )
244
+ }
245
+ const newEffectiveMemSizeWords = newEVMMAXMemSize + newMemSize // toWordSize?
246
+ const words = newEffectiveMemSizeWords
247
+ const fee = common . param ( 'memoryGas' )
248
+ const quadCoefficient = common . param ( 'quadCoefficientDivGas' )
249
+ // words * 3 + words ^2 / 512
250
+ let cost = words * fee + ( words * words ) / quadCoefficient
251
+ if ( cost > runState . highestMemCost ) {
252
+ const currentHighestMemCost = runState . highestMemCost
253
+ runState . highestMemCost = cost
254
+ cost -= currentHighestMemCost
255
+ }
256
+ runState . memoryWordCount = newMemoryWordCount
257
+
258
+ return cost
259
+ }
260
+
261
+ return 0n
262
+ }
263
+
264
+ /**
265
+ * Subtracts the amount needed for memory usage from `runState.gasLeft`
266
+ */
267
+ export function subMemUsage ( runState : RunState , offset : bigint , length : bigint , common : Common ) {
268
+ return evmmaxMemoryGasCost ( runState , common , runState . evmmaxState . allocSize ( ) , offset , length )
225
269
}
226
270
227
271
/**
0 commit comments