feat: port the value-time-lock verifier policy (#33)#39
Merged
Conversation
Port the Sidetree reference ValueTimeLockVerifier (decentralized-identity/
sidetree v1.0.6) as exported, pure, well-tested functions, giving the reader the
policy that decides how many operations an anchor may carry once value-locking is
in use:
- ValueTimeLock{AmountLocked, Owner, LockTransactionTime, UnlockTransactionTime}
— a resolved on-chain lock (mirrors ValueTimeLockModel); active for block
times in [LockTransactionTime, UnlockTransactionTime).
- CalculateMaxNumberOfOperationsAllowed(lock, normalizedFee) =
floor(amountLocked / (normalizedFee * 0.001 * 60000)), floored to 100; the
free quota (100) when there is no lock. The 10000 ceiling is intentionally not
applied here — the reader's op-count gate (#28) enforces it separately.
- VerifyLockAmount(lock, opCount, normalizedFee, txWriter, anchorTime): <=100
ops always pass; over-quota requires a lock whose owner == txWriter, whose
window contains anchorTime, and whose allowance >= opCount; over-quota with no
lock is rejected. Matches the reference ordering exactly (owner/window checks
skipped when lock is nil, then the allowance check rejects).
This is the widened value-lock policy surface — it carries amountLocked,
normalizedFee, owner, and the lock window. sidetree-go owns this policy; the
Bitcoin layer (ion-node) owns resolving the inputs — writerLockId -> ValueTimeLock
(#55), the per-block normalized fee (#54), and the transaction writer — and plugs
the policy in by implementing the existing ValueLocking callback as a thin adapter
that calls VerifyLockAmount. The bool callback is kept as the integration seam so
nothing in the reader path changes today (and ION mainnet ships value-locking
disabled, so this is latent until a writer locks BTC to exceed 100 ops/anchor).
Sentinels: ErrValueLockInvalidOwner, ErrValueLockTimeOutOfRange,
ErrValueLockInsufficientForOps.
Tested: TestCalculateMaxNumberOfOperationsAllowed (no-lock, sub-quota floor,
exactly-100, 200, floor-toward-zero, higher-fee-lowers-allowance, non-positive-fee
guard) and TestVerifyLockAmount (free quota, no-lock over quota, sufficient lock,
over-allowance, wrong owner, window boundaries inclusive/exclusive).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ports the Sidetree reference
ValueTimeLockVerifier(decentralized-identity/sidetreev1.0.6) into sidetree-go as exported, pure, well-tested functions — the policy that decides how many operations an anchor may carry once value-locking is in use. This is the widened value-lock policy surface: it carriesamountLocked,normalizedFee,owner, and the lock window. Plan:docs/plans/2026-06-04-001-feat-ion-value-locking-protocol-rules-plan.md.API (
valuelock.go)ValueTimeLock{AmountLocked, Owner, LockTransactionTime, UnlockTransactionTime}— a resolved on-chain lock (mirrorsValueTimeLockModel); active for block times in[LockTransactionTime, UnlockTransactionTime).CalculateMaxNumberOfOperationsAllowed(lock, normalizedFee)=floor(amountLocked / (normalizedFee × 0.001 × 60000)), floored to 100; the free quota (100) with no lock. The 10000 ceiling is not applied here — the reader's op-count gate (P0: Reader accepts >100-op anchors that canonical ION rejects (per-anchor op-limit unenforced) — consensus divergence #28) enforces it separately, matching the reference.VerifyLockAmount(lock, opCount, normalizedFee, txWriter, anchorTime)—≤100ops always pass; over-quota requires a lock whoseowner == txWriter, whose window containsanchorTime, and whose allowance≥ opCount; over-quota with no lock is rejected. Mirrors the reference ordering exactly (owner/window checks skipped whenlock == nil, then the allowance check rejects the over-quota anchor).Architecture
sidetree-go owns this policy; the Bitcoin layer (ion-node) owns the data: resolving
writerLockId → ValueTimeLock(#55), tracking the per-block normalized fee (#54), and identifying the transaction writer. ion-node plugs the policy in by implementing the existingValueLockingcallback as a thin adapter that resolves those inputs and callsVerifyLockAmount.The bool
ValueLockingcallback is kept as the integration seam, so nothing in the reader's runtime path changes today — this PR is purely additive library API. It is latent until a writer locks BTC to exceed 100 ops/anchor; ION mainnet ships value-locking disabled. Until the resolver exists, the reader default-rejects over-quota locked anchors (#28).New sentinels:
ErrValueLockInvalidOwner,ErrValueLockTimeOutOfRange,ErrValueLockInsufficientForOps.Testing
TestCalculateMaxNumberOfOperationsAllowed— no-lock free quota, sub-quota floored to 100, exactly 100, 200, floor-toward-zero, higher-fee-lowers-allowance, non-positive-fee guard.TestVerifyLockAmount— free quota, no-lock over quota, sufficient lock, over-allowance, wrong owner, and window boundaries (start inclusive, unlock exclusive).gofmtclean;go build,go vet,go test -race -count=1 ./...green.Post-Deploy Monitoring & Validation
No additional operational monitoring required: purely additive library API with no change to the reader's runtime path (the verifier is not yet invoked by the processor — ion-node's
ValueLockingadapter will call it in #55). Inert on ION mainnet (value-locking disabled).🤖 Generated with Claude Code