You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Identity update bills no validation reads — local execution_context is dropped
Summary
IdentityUpdateTransition::validate_state_v0 creates a localstate_transition_execution_context, threads it into five validators, and drops it on every return path. All the ValidationOperation::PrecalculatedOperation entries those validators push are lost — the user is not billed for the grovedb reads that ran. This is the same B7 pattern from #3670 (which fixed the batch transformer's dropped local), applied to identity_update.
This issue tracks the follow-up to PR #3697 (audit entries N6/N7), and closes the broader N8/N9/N10 leaks for identity_update at the same time. CodeRabbit flagged this on #3697.
The outer trait correctly receives execution_context: &mut StateTransitionExecutionContext from the processor (processor/traits/state.rs:32-40, processor/v0/mod.rs:324). The IdentityUpdate dispatcher then drops it on the floor.
N6/N7 (billing wired up by #3697 but stuck in this local)
HIGH
validate_identity_public_key_ids_exist_in_state
N9
HIGH
validate_master_key_uniqueness
— (no grovedb reads, but takes the ctx)
—
Fix shape
Mirror the B7 fix from #3670 — version-gate the change for chain replay safety, no behavior change pre-PROTOCOL_VERSION_12.
Add _v1-suffixed sibling to validate_state_v0 that takes execution_context: &mut StateTransitionExecutionContext and uses it instead of constructing a local one.
Update the IdentityUpdate inner dispatcher in identity_update/mod.rs to:
Drop the _ prefix on execution_context.
Add a 1 => arm that calls validate_state_v1(platform, tx, execution_context, platform_version).
Keep the 0 => arm calling validate_state_v0(platform, tx, platform_version) (which keeps its local-and-dropped behavior verbatim — byte-identical for PROTOCOL_VERSION_11 replay).
v0 remains untouched. v1 is byte-identical to v0 except for the context plumbing.
Consensus implications
Activating v1 changes the fee a user pays for an identity_update that hits any of the five validators above. That is consensus-affecting (a chain that runs v1 will compute a different fee than one that runs v0 for the same transition). It must therefore be gated behind a protocol-version bump — folding into PROTOCOL_VERSION_12 (the next not-yet-shipped version) is appropriate.
Tests to add
A test that exercises validate_state end-to-end on V12 and asserts the outer execution_context receives PrecalculatedOperation entries with non-zero processing fees from at least one of the five validators.
A v0 baseline test asserting the legacy "drop the local" behavior is preserved (no entries reach the outer context).
Identity update bills no validation reads — local
execution_contextis droppedSummary
IdentityUpdateTransition::validate_state_v0creates a localstate_transition_execution_context, threads it into five validators, and drops it on every return path. All theValidationOperation::PrecalculatedOperationentries those validators push are lost — the user is not billed for the grovedb reads that ran. This is the same B7 pattern from #3670 (which fixed the batch transformer's dropped local), applied to identity_update.This issue tracks the follow-up to PR #3697 (audit entries N6/N7), and closes the broader N8/N9/N10 leaks for identity_update at the same time. CodeRabbit flagged this on #3697.
Where the leak is
packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs:92-118:
The outer trait correctly receives
execution_context: &mut StateTransitionExecutionContextfrom the processor (processor/traits/state.rs:32-40,processor/v0/mod.rs:324). The IdentityUpdate dispatcher then drops it on the floor.packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/state/v0/mod.rs:40-164:
The five validators currently leaking reads into the dropped local:
validate_unique_identity_public_key_hashes_not_in_statevalidate_identity_public_key_ids_dont_exist_in_statevalidate_identity_public_keys_contract_boundsvalidate_identity_public_key_ids_exist_in_statevalidate_master_key_uniquenessFix shape
Mirror the B7 fix from #3670 — version-gate the change for chain replay safety, no behavior change pre-PROTOCOL_VERSION_12.
_v1-suffixed sibling tovalidate_state_v0that takesexecution_context: &mut StateTransitionExecutionContextand uses it instead of constructing a local one.identity_update_state_transition.state: 0 → 1insideDRIVE_ABCI_VALIDATION_VERSIONS_V8(the V12 table, already touched by fix(drive-abci): correct DECRYPTION bounds branch + bill grovedb reads in bounds validation #3697's bounds fix).identity_update/mod.rsto:_prefix onexecution_context.1 =>arm that callsvalidate_state_v1(platform, tx, execution_context, platform_version).0 =>arm callingvalidate_state_v0(platform, tx, platform_version)(which keeps its local-and-dropped behavior verbatim — byte-identical for PROTOCOL_VERSION_11 replay).Consensus implications
Activating v1 changes the fee a user pays for an
identity_updatethat hits any of the five validators above. That is consensus-affecting (a chain that runs v1 will compute a different fee than one that runs v0 for the same transition). It must therefore be gated behind a protocol-version bump — folding into PROTOCOL_VERSION_12 (the next not-yet-shipped version) is appropriate.Tests to add
validate_stateend-to-end on V12 and asserts the outerexecution_contextreceivesPrecalculatedOperationentries with non-zero processing fees from at least one of the five validators.References
docs/paid-error-fee-audit.md(from fix(drive-abci): bill batch transformer drive reads (B7) #3670) — Tier 3 audit; N6, N7, N8, N9, N10 entries.