@@ -227,6 +227,9 @@ class MaxSizedContractInitcode(FixedIterationsBytecode):
227227 fork's limits.
228228 """
229229
230+ _cached_address : Address
231+ """Cached address to avoid expensive recomputation."""
232+
230233 def __new__ (cls , * , pre : Alloc , fork : Fork ) -> Self :
231234 """
232235 Create a new MaxSizedContractInitcode instance.
@@ -292,19 +295,21 @@ def __new__(cls, *, pre: Alloc, fork: Fork) -> Self:
292295 cleanup = cleanup ,
293296 iteration_count = iteration_count ,
294297 )
298+ # Cache the address to avoid expensive recomputation
299+ instance ._cached_address = compute_deterministic_create2_address (
300+ salt = 0 ,
301+ initcode = Initcode (deploy_code = instance ),
302+ fork = fork ,
303+ )
295304 deployed_address = pre .deterministic_deploy_contract (
296305 deploy_code = instance
297306 )
298- assert deployed_address == instance .address ( fork = fork )
307+ assert deployed_address == instance ._cached_address
299308 return instance
300309
301- def address (self , * , fork : Fork ) -> Address :
310+ def address (self ) -> Address :
302311 """Get the deterministic address of the initcode."""
303- return compute_deterministic_create2_address (
304- salt = 0 ,
305- initcode = Initcode (deploy_code = self ),
306- fork = fork ,
307- )
312+ return self ._cached_address
308313
309314
310315class MaxSizedContractFactory (IteratingBytecode ):
@@ -322,6 +327,9 @@ class MaxSizedContractFactory(IteratingBytecode):
322327 initcode : MaxSizedContractInitcode
323328 """The initcode used to deploy maximum-sized contracts via CREATE2."""
324329
330+ _cached_address : Address
331+ """Cached address to avoid expensive recomputation."""
332+
325333 def __new__ (cls , * , pre : Alloc , fork : Fork ) -> Self :
326334 """
327335 Create a new MaxSizedContractFactory instance.
@@ -337,7 +345,7 @@ def __new__(cls, *, pre: Alloc, fork: Fork) -> Self:
337345
338346 """
339347 initcode = MaxSizedContractInitcode (pre = pre , fork = fork )
340- initcode_address = initcode .address (fork = fork )
348+ initcode_address = initcode .address ()
341349 setup = (
342350 Op .EXTCODECOPY (
343351 address = initcode_address ,
@@ -381,10 +389,16 @@ def __new__(cls, *, pre: Alloc, fork: Fork) -> Self:
381389 cleanup = cleanup ,
382390 )
383391 instance .initcode = initcode
392+ # Cache the address to avoid expensive recomputation
393+ instance ._cached_address = compute_deterministic_create2_address (
394+ salt = 0 ,
395+ initcode = Initcode (deploy_code = instance ),
396+ fork = fork ,
397+ )
384398 deployed_address = pre .deterministic_deploy_contract (
385399 deploy_code = instance
386400 )
387- assert deployed_address == instance .address ( fork = fork )
401+ assert deployed_address == instance ._cached_address
388402 return instance
389403
390404 def transactions_by_total_contract_count (
@@ -400,33 +414,64 @@ def transactions_by_total_contract_count(
400414 given number of contracts, each capped tx properly capped by the
401415 gas limit cap of the fork.
402416 """
403- to = self .address (fork = fork )
417+ to = self .address ()
418+
419+ # Use a sensible hardcoded maximum for the calldata, to avoid
420+ # binary searching.
421+ max_number = (2 ** (contract_count .bit_length () + 1 )) - 1
422+ calldata_max = Hash (max_number ) + Hash (max_number )
404423
405424 def calldata (iteration_count : int , start_iteration : int ) -> bytes :
406425 index_end = iteration_count + start_iteration - 1
407426 return Hash (start_iteration ) + Hash (index_end )
408427
409- yield from self .transactions_by_total_iteration_count (
428+ start_iteration : int = contract_start_index
429+
430+ tx_gas_limit : int | None = None
431+ tx_gas_cost : int | None = None
432+ last_iteration_count : int = 0
433+
434+ for iteration_count in self .tx_iterations_by_total_iteration_count (
410435 fork = fork ,
411436 total_iterations = contract_count ,
412- start_iteration = contract_start_index ,
413- sender = sender ,
414- to = to ,
415- calldata = calldata ,
416- )
437+ start_iteration = start_iteration ,
438+ calldata = calldata_max ,
439+ ):
440+ if (
441+ tx_gas_limit is None
442+ or tx_gas_cost is None
443+ or iteration_count != last_iteration_count
444+ ):
445+ tx_gas_limit = self .tx_gas_limit_by_iteration_count (
446+ fork = fork ,
447+ iteration_count = iteration_count ,
448+ start_iteration = start_iteration ,
449+ calldata = calldata_max ,
450+ )
451+ tx_gas_cost = self .tx_gas_cost_by_iteration_count (
452+ fork = fork ,
453+ iteration_count = iteration_count ,
454+ start_iteration = start_iteration ,
455+ calldata = calldata_max ,
456+ )
457+ yield TransactionWithCost (
458+ to = to ,
459+ gas_limit = tx_gas_limit ,
460+ sender = sender ,
461+ gas_cost = tx_gas_cost ,
462+ data = calldata (iteration_count , start_iteration ),
463+ )
464+ start_iteration += iteration_count
465+ last_iteration_count = iteration_count
417466
418- def address (self , * , fork : Fork ) -> Address :
419- """Get the deterministic address of the initcode."""
420- return compute_deterministic_create2_address (
421- salt = 0 ,
422- initcode = Initcode (deploy_code = self ),
423- fork = fork ,
424- )
467+ def address (self ) -> Address :
468+ """Get the deterministic address of the factory contract."""
469+ return self ._cached_address
425470
426- def created_contract_address (self , * , fork : Fork , salt : int ) -> Address :
471+ def created_contract_address (self , * , salt : int ) -> Address :
427472 """Get the deterministic address of the created contract."""
428473 return compute_create2_address (
429- address = self .address (fork = fork ),
474+ address = self .address (),
430475 salt = salt ,
431476 initcode = self .initcode ,
432477 )
0 commit comments