Skip to content

Commit 54c1df2

Browse files
Remove double counting of imports
1 parent 69fa06c commit 54c1df2

File tree

6 files changed

+368
-40
lines changed

6 files changed

+368
-40
lines changed

fvm/derived/derived_block_data.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type DerivedTransaction interface {
1818
*Program,
1919
error,
2020
)
21+
GetProgram(location common.AddressLocation) (*Program, bool)
2122

2223
GetMeterParamOverrides(
2324
txnState state.NestedTransaction,
@@ -185,6 +186,19 @@ func (transaction *DerivedTransactionData) GetOrComputeProgram(
185186
programComputer)
186187
}
187188

189+
// GetProgram returns the program for the given address location.
190+
// This does NOT apply reads/metering to any nested transaction.
191+
// Use with caution!
192+
func (transaction *DerivedTransactionData) GetProgram(
193+
location common.AddressLocation,
194+
) (
195+
*Program,
196+
bool,
197+
) {
198+
program, _, ok := transaction.programs.get(location)
199+
return program, ok
200+
}
201+
188202
func (transaction *DerivedTransactionData) AddInvalidator(
189203
invalidator TransactionInvalidator,
190204
) {

fvm/environment/programs.go

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)