@@ -59,6 +59,13 @@ func NewPrograms(
5959 }
6060}
6161
62+ // Reset resets the program cache.
63+ // this is called if the transactions happy path fails.
64+ func (programs * Programs ) Reset () {
65+ programs .nonAddressPrograms = make (map [common.Location ]* interpreter.Program )
66+ programs .dependencyStack = newDependencyStack ()
67+ }
68+
6269// GetOrLoadProgram gets the program from the cache,
6370// or loads it (by calling load) if it is not in the cache.
6471// When loading a program, this method will be re-entered
@@ -288,9 +295,18 @@ type dependencyStack struct {
288295}
289296
290297func newDependencyStack () * dependencyStack {
291- return & dependencyStack {
298+ stack := & dependencyStack {
292299 trackers : make ([]dependencyTracker , 0 ),
293300 }
301+
302+ // The root of the stack is the program (script/transaction) that is being executed.
303+ // At the end of the transaction execution, this will hold all the dependencies
304+ // of the script/transaction.
305+ //
306+ // The root of the stack should never be popped.
307+ stack .push (common .StringLocation ("^ProgramDependencyStackRoot$" ))
308+
309+ return stack
294310}
295311
296312// push a new location to track dependencies for.
@@ -311,17 +327,16 @@ func (s *dependencyStack) push(loc common.Location) {
311327func (s * dependencyStack ) add (dependencies derived.ProgramDependencies ) {
312328 l := len (s .trackers )
313329 if l == 0 {
314- // stack is empty.
315- // This is expected if loading a program that is already cached.
316- return
330+ // This cannot happen, as the root of the stack is always present.
331+ panic ("Dependency stack unexpectedly empty" )
317332 }
318333
319334 s .trackers [l - 1 ].dependencies .Merge (dependencies )
320335}
321336
322337// pop the last dependencies on the stack and return them.
323338func (s * dependencyStack ) pop () (common.Location , derived.ProgramDependencies , error ) {
324- if len (s .trackers ) == 0 {
339+ if len (s .trackers ) <= 1 {
325340 return nil ,
326341 derived .NewProgramDependencies (),
327342 fmt .Errorf ("cannot pop the programs dependency stack, because it is empty" )
@@ -331,14 +346,11 @@ func (s *dependencyStack) pop() (common.Location, derived.ProgramDependencies, e
331346 tracker := s .trackers [len (s .trackers )- 1 ]
332347 s .trackers = s .trackers [:len (s .trackers )- 1 ]
333348
334- // there are more trackers in the stack.
335- // add the dependencies of the popped tracker to the parent tracker
349+ // Add the dependencies of the popped tracker to the parent tracker
336350 // This is an optimisation to avoid having to iterate through the entire stack
337351 // everytime a dependency is pushed or added, instead we add the popped dependencies to the new top of the stack.
338352 // (because if C depends on B which depends on A, A's dependencies include C).
339- if len (s .trackers ) > 0 {
340- s .trackers [len (s .trackers )- 1 ].dependencies .Merge (tracker .dependencies )
341- }
353+ s .trackers [len (s .trackers )- 1 ].dependencies .Merge (tracker .dependencies )
342354
343355 return tracker .location , tracker .dependencies , nil
344356}
0 commit comments