docs: clarify FPI expiration requirements - #3795
Conversation
| Account component procedures can become part of an account's public interface and can be called | ||
| from note scripts, transaction scripts, and foreign accounts through FPI. If such a procedure reads | ||
| mutable security state, it must call `tx::update_expiration_block_delta` in the execution path that | ||
| reads that state. |
There was a problem hiding this comment.
Claude has a tendency to introduce newlines to .md files, but IMO (and keeping in line with our current .md files) we should not artificially split lines here.
May be worth adding a skill that we don't need to respect the 100-char (or whatever) limit in .mds
There was a problem hiding this comment.
true about claude, but this is not claude :)
| stale reads can change an authorization or pricing decision. The component owns the recency bound: | ||
| callers can choose an old reference block, so callers cannot be trusted to set the expiration | ||
| policy for the component. |
There was a problem hiding this comment.
The component owns the recency bound
I'd rather align the language with the terminology we already have, e.g. instead of "recency bound" we'd stick with the "expiration delta", or similar.
Also, "component owns" is not very clear - I think this is meant to say it defines or sets the expiration delta.
| //! staleness limit. Policies that only read immutable data, or for which stale data is acceptable, | ||
| //! do not need an expiration delta. |
There was a problem hiding this comment.
I'd align the language here, as we mix between:
- don't need
- may omit
| Asset callbacks execute against the issuing faucet through FPI. Any callback or callback-dispatched | ||
| policy that reads mutable security state must call `tx::update_expiration_block_delta` in the | ||
| execution path that reads that state. This includes checks against blocklists, allowlists, pause | ||
| flags, active policy roots, oracle values, risk parameters, or similar state. | ||
|
|
||
| Without an expiration delta, a prover can choose an older reference block where the callback state | ||
| allowed the transfer. The expiration delta bounds how stale that reference block may be when the | ||
| transaction is included. Standards components that need the common limit can use | ||
| `miden::standards::expiration::apply_default`; custom callbacks can call | ||
| `tx::update_expiration_block_delta` directly with a tighter limit. | ||
|
|
||
| Callbacks that only inspect immutable data, or for which stale data is acceptable, do not need to | ||
| set an expiration delta. |
There was a problem hiding this comment.
Parts of this read repetitive - I'd rather have the expiration deltas explained in on shared place (here or could also be in components.md) and maybe very briefly mention in the other doc location, but include a reference like:
"for more info see X"
There was a problem hiding this comment.
makes sense on the "for more info see X". I do think a bit of repetition is good since this is super important to not miss.
will trim
| `execute_foreign_procedure` reads the foreign account's state at the transaction reference block, | ||
| which is chosen by the executor. The foreign account commitment is not a transaction public input | ||
| and is not revalidated against the foreign account's current on-chain state at inclusion, so a | ||
| foreign read may be outdated. | ||
|
|
||
| Any FPI-callable procedure that reads mutable security state must call | ||
| `tx::update_expiration_block_delta` in the execution path that reads that state. This includes | ||
| asset callbacks and procedures that read blocklists, allowlists, pause flags, role maps, active | ||
| policy roots, oracle values, risk parameters, or other mutable data where stale reads can change an | ||
| authorization or pricing decision. | ||
|
|
||
| The call is the foreign account's responsibility because the caller controls which valid reference | ||
| block is used for proving. Procedures may omit the call only when they read immutable data or stale | ||
| data is acceptable. |
| Note scripts and transaction scripts can read state from foreign accounts by calling public | ||
| account procedures through foreign procedure invocation (FPI). FPI authenticates the foreign | ||
| account state against the transaction reference block. It does not prove that the foreign account | ||
| state is current when the transaction is included in a block. | ||
|
|
||
| The executor chooses the transaction reference block. If no expiration delta is set, a transaction | ||
| can be proved against an old canonical block where mutable foreign state still allowed the action. | ||
| For example, a prover could choose a block from before an account was added to a blocklist, before | ||
| an account was removed from an allowlist, or before an oracle value or active policy root changed. |
There was a problem hiding this comment.
Again parts feel repetitive
Co-authored-by: Marti <marti@miden.team>
| #! | ||
| #! Where: | ||
| #! - block_height_delta is the desired expiration time delta (1 to 0xFFFF). | ||
| #! - block_height_delta is the desired expiration delta (1 to 0xFFFF). |
There was a problem hiding this comment.
let's avoid using HEX values in user-facing docs
Summary
tx::update_expiration_block_deltaCloses #3480