Identifying the ordering of state access across contract calls

Good catch, and good solution! I think the counter approach works fine, though I’m not sure how much complexity is introduced into the kernel circuit having to “navigate” through the counters. Maybe we’d need to provide additional inputs so we don’t have to actually sort within the circuit? But I’m out of my depth here.


EDIT: Broken by @alvaro below.

As another approach, would it work if each iteration of the public circuit reported the state changes caused by it and all nested calls? So in your example what the kernel circuit would see is:

  • A::foo: state_transitions = [ { slot: x, old_value: 0, new_value: 2 }, empty,... ]
  • B::bar: state_transitions = [ { slot: x, old_value: 1, new_value: 2 }, empty,... ]
  • A: :baz state_transitions = [ { slot: x, old_value: 1, new_value: 2 }, empty,... ]

This would mean that a nested public circuit would return the list of transitions to its caller (similarly to how it returns the function return values) which the caller then “merges” into its own state. Does this make sense?

So in the first example, as the public circuit for A::foo is running, it first tracks the 0->1 transition, calls into B::bar and gets back the 1->2 transition (along with any results from bar) which merges into its own set of transitions.


EDIT: Also broken by @alvaro below :slight_smile:

Alternatively, would it be too crazy to change how the app and kernel circuits are invoked, so we do one iteration of the circuits for each different value of counter? This would mean that the circuits would not verify entire function runs, but rather chunks of code without any nested calls in them.

In your example, the kernel circuit would have five iterations instead of 3:

  • A::foo (before calling bar)
  • B::bar (before calling baz)
  • A::baz
  • B::bar (after returning from baz)
  • A::foo (after returning from bar)

This feels more natural to me as it just follows the flow of the program, rather than having to reassemble the side affects after the fact. On the other hand, it also makes app circuits more annoying to deal with, since each function is now composed of multiple chunks rather than a single circuit.

21 Likes