|
| 1 | +--- |
| 2 | +simd: '0329' |
| 3 | +title: Track Last Accessed Slot |
| 4 | +authors: |
| 5 | + - Igor Durovic (anza) |
| 6 | +category: Standard |
| 7 | +type: Core |
| 8 | +status: Idea |
| 9 | +created: 2025-08-01 |
| 10 | +feature: (fill in with feature key and github tracking issues once accepted) |
| 11 | +--- |
| 12 | + |
| 13 | +## Summary |
| 14 | + |
| 15 | +- Track `last_accessed_slot` for each account as part of the account's metadata. |
| 16 | +- Each time a transaction that write-locks an account is included in a block, |
| 17 | + update that account's `last_accessed_slot` to the block's slot. |
| 18 | + |
| 19 | +## Motivation |
| 20 | + |
| 21 | +Solana currently does not persistently record when an account was last |
| 22 | +write-locked by an included transaction. Capturing the most recent |
| 23 | +write-lock slot per account enables downstream features such as state |
| 24 | +compaction of stale accounts, rent or TTL-style policies, analytics, and |
| 25 | +operational tooling. This SIMD introduces a single metadata field with simple |
| 26 | +update semantics to make that signal universally available without introducing |
| 27 | +additional tracking structures. |
| 28 | + |
| 29 | +Including this ahead of future features (e.g. a new rent system) allows for |
| 30 | +a more accurate view on historical account activity when those features are |
| 31 | +activated. |
| 32 | + |
| 33 | +## New Terminology |
| 34 | + |
| 35 | +- **Account `last_accessed_slot`**: the latest slot in which an account was |
| 36 | + write-locked by a transaction that was included in a block. |
| 37 | + |
| 38 | +## Detailed Design |
| 39 | + |
| 40 | +### Account Metadata Extension |
| 41 | + |
| 42 | +Account metadata includes an additional `last_accessed_slot` field encoded as an |
| 43 | +unsigned little-endian 8-byte integer. |
| 44 | + |
| 45 | +#### Implementation Details |
| 46 | + |
| 47 | +1. **New Account Creation**: When a new account is created (via system program |
| 48 | + allocation or other means), `last_accessed_slot` MUST be set to the current |
| 49 | + slot. |
| 50 | + |
| 51 | +2. **Update on Write-Lock**: Each time a transaction that write-locks an |
| 52 | + account is included in a block, that account's `last_accessed_slot` MUST be |
| 53 | + set to the block's slot. |
| 54 | + |
| 55 | +3. **Snapshot Integration**: `last_accessed_slot` MUST be included in account |
| 56 | + data when serializing snapshots and MUST be restored when deserializing |
| 57 | + snapshots. |
| 58 | + |
| 59 | +4. **Initialization for Existing Accounts**: For accounts that exist before |
| 60 | + activation of this feature, `last_accessed_slot` MUST be initialized to the |
| 61 | + slot of the block that activates the feature. |
| 62 | + |
| 63 | +5. **RPC and Client Exposure**: `last_accessed_slot` SHOULD be available |
| 64 | + through relevant RPC endpoints that return account information, allowing |
| 65 | + clients to access this metadata. |
| 66 | + |
| 67 | +6. **Feature Gate Activation**: This change is guarded by a feature gate. Upon |
| 68 | + activation in a block at slot S, all existing accounts MUST have |
| 69 | + `last_accessed_slot` initialized to S when loaded (e.g., from snapshot or |
| 70 | + ledger). New accounts created after activation MUST initialize the field to |
| 71 | + the current slot at creation time. |
| 72 | + |
| 73 | +7. **Forks and Rollbacks**: Since the value is set to the block's slot, normal |
| 74 | + bank forking/rollback naturally reverts/advances the value with the bank's |
| 75 | + state. Replay on the chosen fork MUST yield the same `last_accessed_slot` |
| 76 | + values. |
| 77 | + |
| 78 | +8. **Accounts lattice hash update**: the lattice hash of an account must |
| 79 | + include the `last_accessed_slot`: |
| 80 | + |
| 81 | + ``` |
| 82 | + lthash(account) := |
| 83 | + if account.lamports == 0: |
| 84 | + return 00..00 |
| 85 | + else: |
| 86 | + lthash.init() |
| 87 | + lthash.append( account.lamports ) |
| 88 | + lthash.append( account.data ) |
| 89 | + lthash.append( account.is_executable ) |
| 90 | + lthash.append( account.owner ) |
| 91 | + lthash.append( account.pubkey ) |
| 92 | + lthash.append( account.last_accessed_slot ) |
| 93 | + return lthash.fini() |
| 94 | + ``` |
| 95 | + |
| 96 | +#### Storage Considerations |
| 97 | + |
| 98 | +The additional 8 bytes per account may increase snapshot size if insufficient |
| 99 | +unused account metadata bytes are available. Currently, there are enough unused |
| 100 | +bytes (due to padding and deprecated fields) so this specific change shouldn't |
| 101 | +increase state size. |
| 102 | + |
| 103 | +## Alternatives Considered |
| 104 | + |
| 105 | +N/A |
| 106 | + |
| 107 | +## Impact |
| 108 | + |
| 109 | +### Validators |
| 110 | + |
| 111 | +- none: the client software must automatically handle old account formats |
| 112 | + to fill in the right default for `last_accessed_slot`. |
| 113 | + |
| 114 | +### Core Contributors |
| 115 | + |
| 116 | +- Provides a simple, in-protocol signal for "last write activity" per account. |
| 117 | +- Enables downstream features such as rent/TTL, pruning/compaction, and |
| 118 | + analytics without additional tracking structures. |
| 119 | + |
| 120 | +## Security Considerations |
| 121 | + |
| 122 | +N/A |
| 123 | + |
| 124 | +## Backwards Compatibility |
| 125 | + |
| 126 | +This change is designed to be backwards compatible: |
| 127 | + |
| 128 | +1. **RPC Compatibility**: Existing RPC calls will continue to work. |
| 129 | + `last_accessed_slot` can be added as an additional field in responses without |
| 130 | + breaking existing clients. |
| 131 | + |
| 132 | +2. **Account Structure**: `last_accessed_slot` is new metadata and does not |
| 133 | + modify existing account data or behavior. Unused bytes and bytes from |
| 134 | + deprecated fields will be used to store this value. |
| 135 | + |
| 136 | +3. **Snapshot Compatibility**: |
| 137 | + 1. New snapshots will include `last_accessed_slot` as part of the account |
| 138 | + metadata (e.g. in `AccountSharedData`). If the snapshot was created before |
| 139 | + feature activation, `last_accessed_slot` is initialized to the activation |
| 140 | + slot when loading. |
0 commit comments