Skip to content

docs: mimd-0024 low-level design docs - #192

Closed
snawaz wants to merge 20 commits into
dlp-v2from
snawaz/mimd-0025-design
Closed

docs: mimd-0024 low-level design docs#192
snawaz wants to merge 20 commits into
dlp-v2from
snawaz/mimd-0025-design

Conversation

@snawaz

@snawaz snawaz commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Stack created with GitHub Stacks CLIGive Feedback 💬

Summary by CodeRabbit

  • Documentation
    • Added comprehensive implementation guidance for DLP v2.
    • Documented permissioning, account structures, lifecycle states, validation rules, failure handling, and dispute workflows.
    • Clarified verifier selection, challenge windows, evidence requirements, dispute resolution, and payout timelocks.
    • Added reference definitions for protocol states, configuration, commitments, challenges, and related operations.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds a DLP v2 implementation document. The document defines the permission model, domain-separated hashes, PDA accounts, public enums, and public structs. It specifies commitment, state-buffer, challenge, dispute, payout, and finalization state. It also defines bootstrap and runtime instructions and their input schemas. The document adds validation rules, failure handling, lifecycle examples, actor responsibilities, FAQ items, and unresolved design points.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch snawaz/mimd-0025-design

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mimd-0025-impl.md`:
- Around line 625-626: Update the FinalizeCommitment happy-path rule wording by
replacing “requires closed window” with “requires the window to be closed,”
while preserving the other listed requirements unchanged.
- Around line 164-169: Validate verifier configuration before activation: ensure
the eligible verifier population, excluding the operator, is at least
selected_verifier_count, and require approval_threshold to be greater than zero
and no greater than selected_verifier_count. Add these checks to the activation
validation flow and reject invalid commitments before they enter Active.
- Around line 503-504: Update ProtocolConfig or the protocol’s immutable
configuration to define the configured withdrawal delay, then make WithdrawStake
enforce that delay using each bond’s withdraw_requested_slot before allowing
either operator or verifier stake withdrawal. Ensure RequestStakeWithdrawal
records the request slot consistently for both bond types and preserve existing
lock and slashing checks.
- Around line 232-235: Define explicit maximum sizes for
VerifierRegistry.entries, PendingCommitment.selected_verifiers, approval_bitmap,
and StateBuffer.data before implementing account storage. Document and enforce
allocation and reallocation rules, reject oversize inputs deterministically, and
ensure registry growth cannot exceed the account limits; use a bounded or
Merkleized/paged representation where the Vec cannot safely be bounded.
- Line 507: Update the CancelUnactivatedCommitment design and related
PendingCommitment/ProtocolConfig definitions to include a configured VRF
callback timeout and a per-commitment deadline snapshot. Ensure
CancelUnactivatedReason::VrfTimeout validates the current slot against that
stored deadline rather than relying on posted_slot alone, and document the
required configuration/account data wherever the commitment lifecycle is
specified.
- Around line 168-169: Update PendingCommitment to persist an explicit extension
counter rather than using challenge_window_id. In ExtendChallengeWindow,
atomically increment the counter and reject the request once
max_window_extensions is reached, while preserving the configured limit’s
behavior and updating any related serialization or initialization paths.
- Around line 185-198: Make commitment-local operator locking consistent across
all terminal paths: either add the operator bond account and exact locked amount
to PendingCommitment and CancelUnactivatedCommitment so every release updates
OperatorBond.locked_lamports, including multiple commitments and disputes, or
remove the commitment-local locking introduced by PostCommitment entirely.
Ensure each terminal path releases exactly its own unspent lock without
affecting other commitments.
- Line 517: Align the FinalizeCommitment specification with the process_finalize
handler’s account contract: document validator signer, delegated/committed/state
accounts, delegation metadata, and validator fees vault, and define how the
legacy commit state/account maps to PendingCommitment. Alternatively, update
process_finalize to enforce only the accounts listed by FinalizeCommitment,
keeping validation and finalization behavior consistent across the table and
handler.
- Around line 525-532: Update the PostCommitmentData shape so er_slot is either
actually carried into the commitment state used by
PendingCommitment/state_commitment_hash, or removed if it is not part of the
committed data. Use the existing FullStateBuffer::state_slot input as the source
of truth if the slot must be preserved, and keep PostCommitment,
PendingCommitment, and state_commitment_hash aligned so no field exists only in
PostCommitmentData.
- Around line 147-171: Update PendingCommitment and its creation path to
snapshot every protocol configuration value later read by lifecycle
instructions, including resolver, protocol_fee_vault, match_penalty_bps, and
max_window_extensions, alongside the existing approval_threshold and registry
revision. Ensure ResolveDispute, payout/penalty handling, and extension handling
use the commitment’s stored values so UpdateProtocolConfig cannot alter
already-committed transactions; alternatively, explicitly document each
intentionally dynamic field.
- Around line 619-624: Update the `ChallengerReveal` and `ResolveDispute` spec
text to separate the truly terminal outcomes (invalid hash and matching state)
from the timeout-driven mismatch path; use `AwaitingDisputeResolution` to
describe the post-`MarkOperatorTimeout` state where a valid reveal can proceed.
Make it explicit that, after `MarkOperatorTimeout`, a valid reveal enables the
configured `resolver` from `ProtocolConfig` to call `ResolveDispute` before
finalization, while preserving the existing invalid/matching terminal branches
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: be495dcd-af5b-4baf-9a48-a9c9695a52d5

📥 Commits

Reviewing files that changed from the base of the PR and between dcd46dc and 4445e0d.

📒 Files selected for processing (1)
  • mimd-0025-impl.md

Comment thread mimd-0025-impl.md
Comment on lines +147 to +171
pub resolver: Pubkey,
/// Vault receiving protocol fees, penalties, or slashed funds.
pub protocol_fee_vault: Pubkey,
/// Minimum stake required for an operator to register and stay active.
pub min_operator_bond: u64,
/// Minimum stake required for a verifier to register and stay active.
pub min_verifier_bond: u64,
/// Minimum stake locked by RaiseChallenge to prevent cheap spam.
pub min_challenger_stake: u64,
/// Slots available for approval/challenge after VRF activation.
pub challenge_window_slots: u64,
/// Slots the operator gets to open state after a challenge.
pub operator_response_timeout_slots: u64,
/// Slots the challenger gets to reveal after operator response or timeout.
pub challenger_reveal_timeout_slots: u64,
/// Delay before a winning challenger can claim payout.
pub payout_timelock_slots: u64,
/// Number of verifiers randomly picked from VerifierRegistry.
pub selected_verifier_count: u16,
/// Approvals required for happy-path finalization.
pub approval_threshold: u16,
/// Maximum under-approval extensions before the commitment expires.
pub max_window_extensions: u16,
/// Penalty for a valid reveal that matches the operator state.
pub match_penalty_bps: u16,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the relevant design doc and referenced account/lifecycle sections.
if [ -f mimd-0025-impl.md ]; then
  echo "== file exists =="
  wc -l mimd-0025-impl.md
  echo "== references to PendingCommitment / config fields =="
  rg -n "PendingCommitment|approval_threshold|max_window_extensions|match_penalty_bps|protocol_fee_vault|resolver|vrf_program|vrf_request_id|registry_revision|configuration snapshot|copied values|Update" mimd-0025-impl.md
  echo
  echo "== sections around account definition and lifecycle references =="
  sed -n '130,185p' mimd-0025-impl.md
  echo "----"
  sed -n '270,355p' mimd-0025-impl.md
  echo "----"
  sed -n '475,505p' mimd-0025-impl.md
  echo "----"
  sed -n '675,705p' mimd-0025-impl.md
else
  echo "mimd-0025-impl.md not found"
  git ls-files | rg 'mimd-0025-impl\.md|impl\.md|protocol|pending|registry|vrf|challenge'
fi

Repository: magicblock-labs/delegation-program

Length of output: 19967


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== sections around Challenge / state buffer fields =="
sed -n '345,440p' mimd-0025-impl.md

echo
echo "== deterministic probe of pending config fields in PendingCommitment =="
python3 - <<'PY'
from pathlib import Path
p = Path("mimd-0025-impl.md")
text = p.read_text().splitlines()
def block(name, title=None):
    in_block = False
    for i, line in enumerate(text, 1):
        if title:
            if title in line and ("```" in "".join(text[max(0,i-3):i]) or "///" in "".join(text[max(0,i-3):i])):
                in_block = True
                j=i
                continue
        if in_block:
            if line.lstrip().startswith("pub struct ") or (j and line.lstrip().startswith("///")):
                yield line, i

# approximate PendingCommitment struct lines by sentinel range
start = next(i for i,l in enumerate(text,1) if "pub struct PendingCommitment {" in l)
end = start + next(i for i,l in enumerate(text[start:],2) if l == "}")
pending = set(l.strip().strip(",") for _,l in zip(range(start,end), text[start:end]) if l.strip() and l.lstrip().startswith("pub "))
fields = ["resolver", "protocol_fee_vault", "match_penalty_bps", "max_window_extensions", "approval_threshold"]
print("PendingCommitment contains:")
for f in fields:
    print(f"  {f}: {f in pending}")

# approximate Challenge struct lines by sentinel range
starts = [i for i,l in enumerate(text,1) if "pub struct Challenge {" in l]
end = next(i for i,l in enumerate(text[starts[0]-1:],1) if l.startswith("pub struct ")) + starts[0] - 1 if starts else None
challenge = set(l.strip().strip(",") for j,l in zip(range(starts[0],end), text[starts[0]-1:end-1]) if l.strip() and l.lstrip().startswith("pub "))
print("Challenge contains:")
for f in fields:
    print(f"  {f}: {f in challenge}")
PY

Repository: magicblock-labs/delegation-program

Length of output: 4248


Snapshot configuration fields that affect committed lifecycles.

UpdateProtocolConfig says existing pending commitments keep copied values, and PendingCommitment stores only approval_threshold plus the registry revision. PendingCommitment still references resolver, protocol_fee_vault, match_penalty_bps, and max_window_extensions through ResolveDispute, payouts/penalties, and extension handling, so a later config update can change dispute authorization, penalties, or extension limits for an already-committed transaction. Store all configuration values that lifecycle instructions read, or explicitly document that these values remain dynamic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 147 - 171, Update PendingCommitment and its
creation path to snapshot every protocol configuration value later read by
lifecycle instructions, including resolver, protocol_fee_vault,
match_penalty_bps, and max_window_extensions, alongside the existing
approval_threshold and registry revision. Ensure ResolveDispute, payout/penalty
handling, and extension handling use the commitment’s stored values so
UpdateProtocolConfig cannot alter already-committed transactions; alternatively,
explicitly document each intentionally dynamic field.

Comment thread mimd-0025-impl.md
Comment on lines +164 to +169
/// Number of verifiers randomly picked from VerifierRegistry.
pub selected_verifier_count: u16,
/// Approvals required for happy-path finalization.
pub approval_threshold: u16,
/// Maximum under-approval extensions before the commitment expires.
pub max_window_extensions: u16,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject impossible verifier thresholds before activation.

The operator is excluded from selection, but the specification does not require enough eligible verifiers for selected_verifier_count. It also does not require approval_threshold to be positive and no greater than the selected set. Validate these conditions before activation. Otherwise a commitment can enter Active with no possible approval path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 164 - 169, Validate verifier configuration
before activation: ensure the eligible verifier population, excluding the
operator, is at least selected_verifier_count, and require approval_threshold to
be greater than zero and no greater than selected_verifier_count. Add these
checks to the activation validation flow and reject invalid commitments before
they enter Active.

Comment thread mimd-0025-impl.md
Comment on lines +168 to +169
/// Maximum under-approval extensions before the commitment expires.
pub max_window_extensions: u16,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Persist the extension count.

ExtendChallengeWindow must enforce max_window_extensions, but PendingCommitment has no extension counter. challenge_window_id is described as an identifier, not as a bounded count. Add an explicit counter, increment it atomically, and reject extensions after the configured maximum.

Also applies to: 690-692

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 168 - 169, Update PendingCommitment to
persist an explicit extension counter rather than using challenge_window_id. In
ExtendChallengeWindow, atomically increment the counter and reject the request
once max_window_extensions is reached, while preserving the configured limit’s
behavior and updating any related serialization or initialization paths.

Comment thread mimd-0025-impl.md
Comment on lines +185 to +198
pub struct OperatorBond {
/// Operator identity this bond belongs to.
pub operator_identity: Pubkey,
/// Slashable stake currently credited to this operator.
pub stake_lamports: u64,
/// Stake temporarily unavailable for withdrawal.
pub locked_lamports: u64,
/// Whether this operator can post new commitments.
pub status: ActorStatus,
/// Slot when exit was requested; None means no pending withdrawal.
pub withdraw_requested_slot: Option<u64>,
}
// Review: `locked_lamports` needs exact lock/unlock rules when one operator has
// multiple pending commitments or disputes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file location and relevant snippets =="
git ls-files | grep -F 'mimd-0025-impl.md' || true
wc -l mimd-0025-impl.md
sed -n '160,220p' mimd-0025-impl.md
sed -n '480,525p' mimd-0025-impl.md
sed -n '590,625p' mimd-0025-impl.md

echo "== search for lock/unlock terms =="
rg -n "locked_lamports|lock|unlock|PostCommitment|CancelUnactivatedCommitment|PendingCommitment|OperatorBond" mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 21373


Make commitment-local operator locks explicit in all terminal paths.

OperatorBond.locked_lamports is aggregate, but PostCommitment can lock commitment-local stake while PendingCommitment stores no lock amount and CancelUnactivatedCommitment cannot update OperatorBond. Add the bond account and exact lock amount to every path that can release an unspent operator lock, or remove commitment-local operator locking entirely.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 185 - 198, Make commitment-local operator
locking consistent across all terminal paths: either add the operator bond
account and exact locked amount to PendingCommitment and
CancelUnactivatedCommitment so every release updates
OperatorBond.locked_lamports, including multiple commitments and disputes, or
remove the commitment-local locking introduced by PostCommitment entirely.
Ensure each terminal path releases exactly its own unspent lock without
affecting other commitments.

Comment thread mimd-0025-impl.md
Comment on lines +232 to +235
pub entries: Vec<VerifierRegistryEntry>,
}
// Review: account size must be bounded before implementation. If the verifier
// set can grow large, replace this Vec with a Merkleized or paged registry.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Set hard bounds for every variable-length account field.

VerifierRegistry.entries, PendingCommitment.selected_verifiers, approval_bitmap, and StateBuffer.data are Vec fields stored in accounts. Define maximum sizes, allocation/reallocation rules, and oversize failure behavior before implementation. Without these bounds, an attacker-controlled or registry-controlled size can make account creation or resizing fail.

Also applies to: 329-331, 365-386

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 232 - 235, Define explicit maximum sizes for
VerifierRegistry.entries, PendingCommitment.selected_verifiers, approval_bitmap,
and StateBuffer.data before implementing account storage. Document and enforce
allocation and reallocation rules, reject oversize inputs deterministically, and
ensure registry growth cannot exceed the account limits; use a bounded or
Merkleized/paged representation where the Vec cannot safely be bounded.

Comment thread mimd-0025-impl.md
| `WithdrawStake`<ul><li>ix-data: <code>actor_kind</code></li><li>accounts: <strong>actor signer, OperatorBond or VerifierBond, ProtocolConfig</strong></li></ul> | Operator or verifier | Withdraws unlocked stake after the exit delay. Slashed or locked stake stays in the protocol. |
| `PostCommitment`<ul><li>ix-data: <code>commitment</code></li><li>accounts: <strong>operator signer, OperatorBond, PendingCommitment, delegated account, DelegationRecord, ProtocolConfig, VerifierRegistry, DLP identity PDA, VRF queue/program</strong></li></ul> | Operator | Creates an `AwaitingRandomness` commitment, stores the current `registry_revision`, locks any commitment-local stake if needed, and requests VRF. |
| `ConsumeCommitmentRandomness`<ul><li>ix-data: <code>randomness</code></li><li>accounts: <strong>VRF identity signer, PendingCommitment, ProtocolConfig, VerifierRegistry</strong></li></ul> | VRF callback | Verifies the VRF caller and registry revision, selects verifiers from the registry excluding the commitment operator, and starts the challenge window. |
| `CancelUnactivatedCommitment`<ul><li>ix-data: <code>reason</code></li><li>accounts: <strong>cranker/operator signer, PendingCommitment, ProtocolConfig, VerifierRegistry</strong></li></ul> | Operator or cranker | Cancels a commitment that is still waiting for randomness but can no longer activate, such as after registry change or VRF timeout. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Store a verifiable VRF timeout.

CancelUnactivatedReason::VrfTimeout requires a timeout check, but neither ProtocolConfig nor PendingCommitment supplies a VRF callback timeout or deadline. posted_slot alone cannot establish when cancellation becomes valid. Add a configured timeout and snapshot its resulting deadline in the pending record.

Also applies to: 605-608

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 507, Update the CancelUnactivatedCommitment design
and related PendingCommitment/ProtocolConfig definitions to include a configured
VRF callback timeout and a per-commitment deadline snapshot. Ensure
CancelUnactivatedReason::VrfTimeout validates the current slot against that
stored deadline rather than relying on posted_slot alone, and document the
required configuration/account data wherever the commitment lifecycle is
specified.

Comment thread mimd-0025-impl.md
| `ChallengerReveal`<ul><li>ix-data: <code>state, salt</code></li><li>accounts: <strong>challenger signer, PendingCommitment, Challenge, optional StateBuffer, fee vault</strong></li></ul> | Challenger | Verifies the challenge preimage and opened state. It slashes invalid reveals, penalizes matching reveals, or moves mismatches to resolver decision. |
| `MarkChallengerRevealTimeout`<ul><li>ix-data: <code>empty</code></li><li>accounts: <strong>cranker, PendingCommitment, Challenge, fee vault</strong></li></ul> | Cranker | Slashes challenger stake when the reveal deadline passes without a valid reveal. |
| `ResolveDispute`<ul><li>ix-data: <code>decision</code></li><li>accounts: <strong>resolver signer, Challenge, PendingCommitment, OperatorBond, fee vault, optional PayoutTimelock</strong></li></ul> | Resolver multisig | Applies the multisig decision for a valid mismatch: operator correct or challenger correct. |
| `FinalizeCommitment`<ul><li>ix-data: <code>state_source</code></li><li>accounts: <strong>finalizer, PendingCommitment, delegated account, DelegationRecord/metadata, StateBuffer, optional Challenge, ProtocolConfig</strong></li></ul> | Finalizer or cranker | Applies the final state after the happy path or after dispute resolution. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)(mimd-0025-impl\.md|finalize\.rs|commit_state_from_buffer\.rs|processor)' | sed -n '1,200p'

echo
echo "== relevant outline for candidate source files =="
for f in src/processor/fast/finalize.rs src/processor/fast/commit_state_from_buffer.rs; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    ast-grep outline "$f" --view compact 2>/dev/null || true
    sed -n '1,230p' "$f"
  else
    echo "missing $f"
  fi
done

echo
echo "== relevant lines in mimd-0025-impl.md around 480-540 =="
sed -n '480,540p' mimd-0025-impl.md

echo
echo "== searches for FinalizeCommitment / finalizer / Commitment handling =="
rg -n "FinalizeCommitment|finalizer|CommitStateFromBuffer|commit_state_from_buffer|Commitment|DelegationRecord|metadata|fee vault|vault|StateBuffer|ProtocolConfig|Challenge|PendingCommitment" mimd-0025-impl.md src/processor/fast/mimd-0025-impl.md src 2>/dev/null | sed -n '1,240p'

Repository: magicblock-labs/delegation-program

Length of output: 45418


Align FinalizeCommitment with the processor account contract.

The current process_finalize handler requires validator signer, delegated/committed/state accounts, delegation metadata, and the validator fees vault. The FinalizeCommitment table entry omits these accounts and does not define how the legacy commit state/account contract maps to the new pending-commitment model. Add the required account validation and behavior or update the handler to match the documented boundary before implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` at line 517, Align the FinalizeCommitment specification
with the process_finalize handler’s account contract: document validator signer,
delegated/committed/state accounts, delegation metadata, and validator fees
vault, and define how the legacy commit state/account maps to PendingCommitment.
Alternatively, update process_finalize to enforce only the accounts listed by
FinalizeCommitment, keeping validation and finalization behavior consistent
across the table and handler.

Comment thread mimd-0025-impl.md
Comment on lines +525 to +532
pub struct PostCommitmentData {
pub commit_id: u64,
pub lamports: u64,
pub owner: Pubkey,
pub data_hash: [u8; 32],
pub da_pointer_hash: [u8; 32],
pub er_slot: Option<u64>,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files matching mimd-0025:"
fd -i 'mimd-0025' . || true

echo
echo "Relevant snippets around PostCommitmentData and state_commitment_hash:"
rg -n "PostCommitmentData|PendingCommitment|state_commitment_hash|er_slot" mimd-0025-impl.md -C 4 || true

echo
echo "Diff stat:"
git diff --stat || true

echo
echo "Line context in mimd-0025-impl.md:"
wc -l mimd-0025-impl.md || true
sed -n '480,560p' mimd-0025-impl.md
sed -n '560,640p' mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 25069


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '288,340p' mimd-0025-impl.md
sed -n '65,90p' mimd-0025-impl.md

python3 - <<'PY'
from pathlib import Path
text = Path("mimd-0025-impl.md").read_text()

# Simulate PostCommitmentData hash inputs for the documented state_commitment_hash formula.
inputs_a = ["magicblock.state_commitment.v1", "op", "acc", "1", "delegation", "da", ["data_hash"]]
inputs_b = ["magicblock.state_commitment.v1", "op", "acc", "1", "delegation", "da", ["data_hash", "extra"]]
print("documented contains er_slot:", "er_slot" in text[text.find("### Key Instruction Data"):text.find("### Important Instruction Rules")])
print("PendingCommitment stores er_slot:", "pub er_slot" in text[text.find("pub struct PendingCommitment"):text.find("pub struct Challenge")])
print("state_commitment_hash contains er_slot:", "er_slot" in text[text.find("state_commitment_hash = H("):text.find("challenge_hash = H(")] if "state_commitment_hash = H(" in text and "challenge_hash = H(" in text else False)
print("same hash prefix produces same first hash:", hash(tuple(inputs_a)) == hash(tuple(inputs_b[:-1]) + (inputs_b[-1][0],)))
PY

Repository: magicblock-labs/delegation-program

Length of output: 3348


Remove or bind er_slot.

PostCommitment stores the commitment in PendingCommitment, but neither PendingCommitment nor state_commitment_hash includes er_slot. FullStateBuffer accepts state_slot, which can serve as the ER slot at buffer creation. Move or hash the slot into the commitment state, or remove er_slot from PostCommitmentData.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 525 - 532, Update the PostCommitmentData
shape so er_slot is either actually carried into the commitment state used by
PendingCommitment/state_commitment_hash, or removed if it is not part of the
committed data. Use the existing FullStateBuffer::state_slot input as the source
of truth if the slot must be preserved, and keep PostCommitment,
PendingCommitment, and state_commitment_hash aligned so no field exists only in
PostCommitmentData.

Comment thread mimd-0025-impl.md
Comment on lines +619 to +624
- `ChallengerReveal` has four terminal branches:
invalid hash, matching state, mismatch after operator response, valid reveal
after operator timeout.
- `ResolveDispute` requires the configured `resolver` signer from
`ProtocolConfig`. In DLP v2 this signer is expected to be a multisig-controlled
account.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- file list ---\n'
git ls-files | rg '(^|/)mimd-0025-impl\.md$|mimd-0025|protocol' || true

printf '\n--- relevant section 600-680 ---\n'
nl -ba mimd-0025-impl.md | sed -n '600,670p'

printf '\n--- search ChallengerReveal/ResolveDispute/timeout terms ---\n'
rg -n "ChallengerReveal|ResolveDispute|operator [Tt]imeout|timeout|valid reveal|valid mismatch|resolver" mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 263


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- file list ---'
git ls-files | rg '(^|/)mimd-0025-impl\.md$|mimd-0025|protocol' || true

printf '%s\n' ''
printf '%s\n' '--- relevant section 600-680 ---'
nl -ba mimd-0025-impl.md | sed -n '600,670p'

printf '%s\n' ''
printf '%s\n' '--- search ChallengerReveal/ResolveDispute/timeout terms ---'
rg -n "ChallengerReveal|ResolveDispute|operator [Tt]imeout|timeout|valid reveal|valid mismatch|resolver" mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 510


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- relevant section 600-680 ---'
awk 'NR>=600 && NR<=680 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md

echo ''
echo '--- search ChallengerReveal/ResolveDispute/timeout terms ---'
rg -n "ChallengerReveal|ResolveDispute|operator [Tt]imeout|timeout|valid reveal|valid mismatch|resolver" mimd-0025-impl.md || true

echo ''
echo '--- nearby status/branch references 560-630 ---'
awk 'NR>=560 && NR<=630 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md

echo ''
echo '--- all status definitions/usages ---'
rg -n "\b(status|Status)\b|ChallengerReveal|ResolveDispute|Mismatch|operator timeout|operator timeout\." mimd-0025-impl.md || true

Repository: magicblock-labs/delegation-program

Length of output: 16267


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- lines 230-445 ---'
awk 'NR>=230 && NR<=445 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md

echo ''
echo '--- lines 670-700 ---'
awk 'NR>=670 && NR<=700 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 11856


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- status definitions 445-520 ---'
awk 'NR>=445 && NR<=520 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md

echo ''
echo '--- line 255-261 plus 619-624 ---'
awk 'NR>=248 && NR<=262 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md
awk 'NR>=619 && NR<=624 { printf "%4d  %s\n", NR, $0 }' mimd-0025-impl.md

echo ''
echo '--- all PendingCommitmentStatus mentions ---'
rg -n "PendingCommitmentStatus|AwaitingDisputeResolution|AwaitingChallengerRevealAfterOperatorTimeout|ChallengerReveal" mimd-0025-impl.md

Repository: magicblock-labs/delegation-program

Length of output: 12115


Clarify the resolver-access transition for operator timeouts.

AwaitingDisputeResolution is already defined, but the spec still says ChallengerReveal branches are terminal and describes ResolveDispute only for a valid mismatch after operator response. Split the invalid/matching terminal outcomes from the timeout mismatch case, and say that a valid reveal after MarkOperatorTimeout lets the configured resolver call ResolveDispute before finalization.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 619 - 624, Update the `ChallengerReveal` and
`ResolveDispute` spec text to separate the truly terminal outcomes (invalid hash
and matching state) from the timeout-driven mismatch path; use
`AwaitingDisputeResolution` to describe the post-`MarkOperatorTimeout` state
where a valid reveal can proceed. Make it explicit that, after
`MarkOperatorTimeout`, a valid reveal enables the configured `resolver` from
`ProtocolConfig` to call `ResolveDispute` before finalization, while preserving
the existing invalid/matching terminal branches unchanged.

Comment thread mimd-0025-impl.md
Comment on lines +625 to +626
- `FinalizeCommitment` on the happy path requires closed window, approval
threshold, no unresolved challenge, and full-state hash match.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use direct wording for the finalization rule.

Replace “requires closed window” with “requires the window to be closed.”

🧰 Tools
🪛 LanguageTool

[style] ~625-~625: The double modal “requires closed” is nonstandard (only accepted in certain dialects). Consider “to be closed”.
Context: ...eCommitment` on the happy path requires closed window, approval threshold, no unreso...

(NEEDS_FIXED)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mimd-0025-impl.md` around lines 625 - 626, Update the FinalizeCommitment
happy-path rule wording by replacing “requires closed window” with “requires the
window to be closed,” while preserving the other listed requirements unchanged.

Source: Linters/SAST tools

@snawaz snawaz changed the title docs: mimd-0025 low-level design docs docs: mimd-0024 low-level design docs Aug 7, 2026
@snawaz

snawaz commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

discard as the branch is renamed and gt stack didn't handle it properly.

@snawaz snawaz closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant