@@ -94,6 +94,24 @@ func (programs *Programs) getOrLoadAddressProgram(
9494 load func () (* interpreter.Program , error ),
9595) (* interpreter.Program , error ) {
9696
97+ if programs .dependencyStack .top ().ContainsLocation (location ) {
98+ // this dependency has already been seen in the current stack/scope
99+ // this means that it is safe to just fetch it and not reapply
100+ // state/metering changes
101+ program , ok := programs .txnState .GetProgram (location )
102+ if ! ok {
103+ // program should be in the cache, if it is not,
104+ // this means there is an implementation error
105+ return nil , errors .NewDerivedDataCacheImplementationFailure (
106+ fmt .Errorf ("expected program missing" +
107+ " in cache for location: %s" , location ))
108+ }
109+ programs .dependencyStack .add (program .Dependencies )
110+ programs .cacheHit ()
111+
112+ return program .Program , nil
113+ }
114+
97115 loader := newProgramLoader (load , programs .dependencyStack , location )
98116 program , err := programs .txnState .GetOrComputeProgram (
99117 programs .txnState ,
@@ -201,12 +219,17 @@ func (loader *programLoader) Compute(
201219 // This should never happen, as the program loader is only called once per
202220 // program. The same loader is never reused. This is only here to make
203221 // this more apparent.
204- panic ("program loader called twice" )
222+ return nil ,
223+ errors .NewDerivedDataCacheImplementationFailure (
224+ fmt .Errorf ("program loader called twice" ))
205225 }
226+
206227 if loader .location != location {
207228 // This should never happen, as the program loader constructed specifically
208229 // to load one location once. This is only a sanity check.
209- panic ("program loader called with unexpected location" )
230+ return nil ,
231+ errors .NewDerivedDataCacheImplementationFailure (
232+ fmt .Errorf ("program loader called with unexpected location" ))
210233 }
211234
212235 loader .called = true
@@ -339,7 +362,9 @@ func (s *dependencyStack) pop() (common.Location, derived.ProgramDependencies, e
339362 if len (s .trackers ) <= 1 {
340363 return nil ,
341364 derived .NewProgramDependencies (),
342- fmt .Errorf ("cannot pop the programs dependency stack, because it is empty" )
365+ errors .NewDerivedDataCacheImplementationFailure (
366+ fmt .Errorf ("cannot pop the programs" +
367+ " dependency stack, because it is empty" ))
343368 }
344369
345370 // pop the last tracker
@@ -354,3 +379,14 @@ func (s *dependencyStack) pop() (common.Location, derived.ProgramDependencies, e
354379
355380 return tracker .location , tracker .dependencies , nil
356381}
382+
383+ // top returns the last dependencies on the stack without pop-ing them.
384+ func (s * dependencyStack ) top () derived.ProgramDependencies {
385+ l := len (s .trackers )
386+ if l == 0 {
387+ // This cannot happen, as the root of the stack is always present.
388+ panic ("Dependency stack unexpectedly empty" )
389+ }
390+
391+ return s .trackers [len (s .trackers )- 1 ].dependencies
392+ }
0 commit comments