async def _get_update(self, rr_builder: Callable, fro: int, to: int, delta: bool) -> (str, int):
LOGGER.debug(<EOL>'<STR_LIT>',<EOL>rr_builder.__name__,<EOL>fro,<EOL>to,<EOL>delta)<EOL>if fro > to:<EOL><INDENT>(fro, to) = (to, fro)<EOL><DEDENT>now = int(time())<EOL>if to > now:<EOL><INDENT>LOGGER.debug(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>' if delta else '<STR_LIT:state>',<EOL>to,<EOL>now)<EOL>raise BadRevStateTime('<STR_LIT>'.format(<EOL>'<STR_LIT>' if delta else '<STR_LIT:state>',<EOL>to,<EOL>now))<EOL><DEDENT>cache_frame = None<EOL>rr_update_json = None<EOL>rr_frames = self.rr_delta_frames if delta else self.rr_state_frames<EOL>frames = [frame for frame in rr_frames if frame.timestamp <= to <= frame.to]<EOL>if frames:<EOL><INDENT>cache_frame = max(frames, key=lambda f: f.timestamp)  <EOL><DEDENT>else:<EOL><INDENT>frames = [frame for frame in rr_frames if (fro <= frame.to and frame.timestamp <= to)]<EOL>if frames:<EOL><INDENT>cache_frame = max(frames, key=lambda f: f.timestamp)<EOL><DEDENT><DEDENT>if not frames:<EOL><INDENT>frames = [frame for frame in rr_frames if frame.timestamp < to]  <EOL>if frames:<EOL><INDENT>latest_cached = max(frames, key=lambda frame: frame.timestamp)<EOL>if delta:<EOL><INDENT>(rr_update_json, timestamp) = await rr_builder(<EOL>self.rev_reg_def['<STR_LIT:id>'],<EOL>to=to,<EOL>fro=latest_cached.timestamp,<EOL>fro_delta=latest_cached.rr_update)<EOL><DEDENT>else:<EOL><INDENT>(rr_update_json, timestamp) = await rr_builder(self.rev_reg_def['<STR_LIT:id>'], to)<EOL><DEDENT>if timestamp == latest_cached.timestamp:<EOL><INDENT>latest_cached.to = to  <EOL>cache_frame = latest_cached<EOL><DEDENT><DEDENT>else:<EOL><INDENT>(rr_update_json, timestamp) = await rr_builder(self.rev_reg_def['<STR_LIT:id>'], to)<EOL><DEDENT><DEDENT>if cache_frame is None:<EOL><INDENT>cache_frame = RevRegUpdateFrame(to, timestamp, json.loads(rr_update_json))  <EOL>rr_frames.append(cache_frame)<EOL>self.cull(delta)<EOL><DEDENT>else:<EOL><INDENT>cache_frame.qtime = int(time())<EOL><DEDENT>rv = (json.dumps(cache_frame.rr_update), cache_frame.timestamp)<EOL>LOGGER.debug('<STR_LIT>', rv)<EOL>return rv<EOL>
Get rev reg delta/state json, and its timestamp on the distributed ledger,
from cached rev reg delta/state frames list or distributed ledger,
updating cache as necessary.

Raise BadRevStateTime if caller asks for a delta/state in the future. Raise ClosedPool
if an update requires the ledger but the node pool is closed.

Issuer agents cannot revoke retroactively.
Hence, for any new request against asked-for interval (fro, to):
* if the cache has a frame f on f.timestamp <= to <= f.to,
  > return its rev reg delta/state; e.g., starred frame below:

  Frames: --------[xxxxx]----[xx]-----[*********]-----[x]-----------[xx]---------> time
  Fro-to:                                ^----^

* otherwise, if there is a maximum frame f with fro <= f.to and f.timestamp <= to
  > return its rev reg delta/state; e.g., starred frame below:

  Frames: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[*]-----------[xx]---------> time
  Fro-to:                  ^----------------------------------^

* otherwise, if the cache has a frame f on f.timestamp < to,
  > check the distributed ledger for a delta to/state for the rev reg since e.timestamp;
    - if there is one, bake it through 'to' into a new delta/state, add new frame to cache and
      return rev reg delta/state; e.g., starred frame below:

      Frames: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]-----------[xx]---------> time
      Fro-to:                                                 ^------^
      Ledger: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]--!--------[xx]---------> time
      Update: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]--[*****]--[xx]---------> time

    - otherwise, update the 'to' time in the frame and return the rev reg delta/state;
      e.g., starred frame below:

      Frames: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]-----------[xx]---------> time
      Fro-to:                                                 ^------^
      Ledger: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]-----------[xx]---------> time
      Update: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[**********]--[xx]---------> time

* otherwise, there is no cache frame f on f.timestamp < to:
  > create new frame and add it to cache; return rev reg delta/state; e.g., starred frame below:

  Frames: --------[xxxxx]----[xx]-----[xxxxxxxxx]-----[*]-----------[xx]-----> time
  Fro-to:   ^--^
  Ledger: -!------[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]-----------[xx]---------> time
  Update: -[***]--[xxxxx]----[xx]-----[xxxxxxxxx]-----[x]-----------[xx]---------> time

On return of any previously existing rev reg delta/state frame, always update its query time beforehand.

:param rr_builder: callback to build rev reg delta/state if need be (specify holder-prover agent's
    _build_rr_delta_json() or verifier agent's _build_rr_state_json() as needed)
:param fro: least time (epoch seconds) of interest; lower-bounds 'to' on frame housing return data
:param to: greatest time (epoch seconds) of interest; upper-bounds returned revocation delta/state timestamp
:param delta: True to operate on rev reg deltas, False for states
:return: rev reg delta/state json and ledger timestamp (epoch seconds)