Skip to content
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
76671f6
Add liquid alpha consensus modes
UnArbosSix Aug 11, 2026
777fe85
Align minimum liquid alpha with bond EMA
UnArbosSix Aug 11, 2026
53bace4
clippy
UnArbosSix Aug 12, 2026
f3165a6
retry e2e
UnArbosSix Aug 12, 2026
0bc75c8
Creating release 446
UnArbosFour Aug 12, 2026
ce2d6a6
Correct SubnetAlphaOut and refine conviction term
UnArbosFour Aug 12, 2026
1d31e2c
Fix generation-scoped alpha accounting and safely rebase recycled sub…
UnArbosFour Aug 11, 2026
1fbdd6c
Expose alpha counter cleanup phase in subnet precompile
UnArbosFour Aug 12, 2026
3cf8c4c
Add historical reconstruction of alpha burned
UnArbosFour Aug 12, 2026
8075e5f
Handle registration counters for subnets 116, 92, 40, 16, 58, 99, 90,…
UnArbosFour Aug 12, 2026
2dadde2
Temporarily allow alpha migrations on mainnet clones
UnArbosFour Aug 12, 2026
bd71460
Ignore local alpha accounting scanner data
UnArbosFour Aug 12, 2026
e6567cd
Revert "Temporarily allow alpha migrations on mainnet clones"
UnArbosFour Aug 13, 2026
9628b50
Guard alpha corrections by subnet generation
UnArbosFour Aug 13, 2026
b35a554
fix: keep timelock commitments when reveal fails
unarbos Aug 13, 2026
9bb5a76
fix: quarantine failed and expired timelock reveals
unarbos Aug 13, 2026
5717f90
Merge pull request #3078 from RaoFoundation/fix/alpha-accounting-446
UnArbosFour Aug 13, 2026
a2f6079
TimelockRevealFailedNotAllowed
UnArbosSix Aug 13, 2026
41fda81
add rust timelock commitments e2e
UnArbosSix Aug 13, 2026
959e703
Add consensus by mechanism storage
UnArbosFour Aug 13, 2026
35e8331
spec bump
UnArbosFour Aug 13, 2026
538e2a7
Merge branch 'release-v446' into agent/liquid-alpha-consensus-mode
UnArbosSix Aug 13, 2026
08ccfd9
fix e2e manifest
UnArbosSix Aug 13, 2026
479868e
address review
UnArbosFour Aug 13, 2026
8879c12
Merge branch 'agent/liquid-alpha-consensus-mode' of github.com:RaoFou…
UnArbosFour Aug 13, 2026
e6ed706
Update committed Python SDK metadata
UnArbosFour Aug 13, 2026
80c912c
RoundMismatch
UnArbosSix Aug 13, 2026
57cefe3
Fix tests
UnArbosFour Aug 13, 2026
462e29b
Merge pull request #3070 from RaoFoundation/agent/liquid-alpha-consen…
UnArbosFour Aug 13, 2026
9e58a64
add python e2e
UnArbosSix Aug 13, 2026
ed568d8
Fix GRANDPA set ID handling
UnArbosFive Jul 23, 2026
94dd956
Merge pull request #2971 from RaoFoundation/fix/grandpa-setid
UnArbosFive Aug 13, 2026
9eb28d9
Merge pull request #3080 from RaoFoundation/fix/timelock-reveal-keep-…
UnArbosSix Aug 13, 2026
55cc8cd
docs: complete v446 release documentation
UnArbosFive Aug 13, 2026
64285cc
docs: fix v446 release text spacing
UnArbosFive Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions .github/workflows/check-bittensor-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -448,11 +448,19 @@ jobs:
path: rust-e2e

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for i in 1 2 3; do
if printf '%s' "$GHCR_TOKEN" \
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin; then
exit 0
fi
echo "GHCR login failed (attempt $i), retrying in $((i * 15))s..."
sleep $((i * 15))
done
printf '%s' "$GHCR_TOKEN" \
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin

- name: Pull Docker Image
# GHCR intermittently returns permission_denied/timeouts under the
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ sdk/python/dist/

# Local dev logs
*.log
.alpha-accounting-scanner/

# Claude Code configuration (skills are checked in; everything else is ignored)
# .claude/skills is a symlink to .agents/skills (single source of truth);
Expand Down
2 changes: 1 addition & 1 deletion docs/errors/chain/AccountNotAllowedCommit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Raised by `set_commitment` when the runtime commit check fails: the subnet must

Declared by the `Commitments` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized).

Declared at [`pallets/commitments/src/lib.rs#L121`](/code/pallets/commitments/src/lib.rs#L121).
Declared at [`pallets/commitments/src/lib.rs#L132`](/code/pallets/commitments/src/lib.rs#L132).

## Remediation

Expand Down
18 changes: 18 additions & 0 deletions docs/errors/chain/GrandpaChangeDelayMustBeZero.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: "GrandpaChangeDelayMustBeZero"
description: "Check the argument values against the operation schema"
---

{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */}

`schedule_grandpa_change` was given a nonzero `in_blocks` delay. GRANDPA authority changes submitted through AdminUtils must activate at the end of the current block so the authority set and its set ID remain consistent. Pass `in_blocks=0`.

Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument).

Declared at [`pallets/admin-utils/src/lib.rs#L182`](/code/pallets/admin-utils/src/lib.rs#L182).

## Remediation

Check the argument values against the operation schema

The same explanation is available in the terminal: `btcli explain GrandpaChangeDelayMustBeZero`.
2 changes: 1 addition & 1 deletion docs/errors/chain/SpaceLimitExceeded.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The commitment would push the account's byte quota for the current epoch over th

Declared by the `Commitments` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded).

Declared at [`pallets/commitments/src/lib.rs#L123`](/code/pallets/commitments/src/lib.rs#L123).
Declared at [`pallets/commitments/src/lib.rs#L134`](/code/pallets/commitments/src/lib.rs#L134).

## Remediation

Expand Down
18 changes: 18 additions & 0 deletions docs/errors/chain/TimelockRevealFailedNotAllowed.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: "TimelockRevealFailedNotAllowed"
description: "Check the argument values against the operation schema"
---

{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */}

The submitted commitment contains `TimelockRevealFailed`, a terminal audit state that only the runtime may create after an automatic reveal fails. Submit a `TimelockEncrypted` field instead.

Declared by the `Commitments` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument).

Declared at [`pallets/commitments/src/lib.rs#L138`](/code/pallets/commitments/src/lib.rs#L138).

## Remediation

Check the argument values against the operation schema

The same explanation is available in the terminal: `btcli explain TimelockRevealFailedNotAllowed`.
2 changes: 1 addition & 1 deletion docs/errors/chain/TooManyFieldsInCommitmentInfo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields

Declared by the `Commitments` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded).

Declared at [`pallets/commitments/src/lib.rs#L119`](/code/pallets/commitments/src/lib.rs#L119).
Declared at [`pallets/commitments/src/lib.rs#L130`](/code/pallets/commitments/src/lib.rs#L130).

## Remediation

Expand Down
2 changes: 1 addition & 1 deletion docs/errors/chain/UnexpectedUnreserveLeftover.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ While lowering a commitment deposit, `Currency::unreserve` failed to return the

Declared by the `Commitments` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal).

Declared at [`pallets/commitments/src/lib.rs#L125`](/code/pallets/commitments/src/lib.rs#L125).
Declared at [`pallets/commitments/src/lib.rs#L136`](/code/pallets/commitments/src/lib.rs#L136).

## Remediation

Expand Down
2 changes: 2 additions & 0 deletions docs/errors/chain/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ The exact chain error name (from the extrinsic receipt) maps to a semantic [code
| [`GasLimitTooHigh`](/docs/errors/chain/GasLimitTooHigh) | [`invalid_argument`](/docs/errors/invalid-argument) | The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. |
| [`GasLimitTooLow`](/docs/errors/chain/GasLimitTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. |
| [`GasPriceTooLow`](/docs/errors/chain/GasPriceTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. |
| [`GrandpaChangeDelayMustBeZero`](/docs/errors/chain/GrandpaChangeDelayMustBeZero) | [`invalid_argument`](/docs/errors/invalid-argument) | `schedule_grandpa_change` was given a nonzero `in_blocks` delay. GRANDPA authority changes submitted through AdminUtils must activate at the end of the current block so the authority set and its set ID remain consistent. Pass `in_blocks=0`. |
| [`HotKeyAccountNotExists`](/docs/errors/chain/HotKeyAccountNotExists) | [`not_registered`](/docs/errors/not-registered) | The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first. |
| [`HotKeyAlreadyDelegate`](/docs/errors/chain/HotKeyAlreadyDelegate) | [`already_exists`](/docs/errors/already-exists) | `become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed. |
| [`HotKeyAlreadyRegisteredInSubNet`](/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet) | [`already_exists`](/docs/errors/already-exists) | A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid. |
Expand Down Expand Up @@ -319,6 +320,7 @@ The exact chain error name (from the extrinsic receipt) maps to a semantic [code
| [`TempoOutOfBounds`](/docs/errors/chain/TempoOutOfBounds) | [`invalid_argument`](/docs/errors/invalid-argument) | The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain constants and pick a value inside the bounds; only root may set a tempo outside them. |
| [`TerminatedInConstructor`](/docs/errors/chain/TerminatedInConstructor) | [`internal`](/docs/errors/internal) | The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls. |
| [`TerminatedWhileReentrant`](/docs/errors/chain/TerminatedWhileReentrant) | [`invalid_argument`](/docs/errors/invalid-argument) | `seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. |
| [`TimelockRevealFailedNotAllowed`](/docs/errors/chain/TimelockRevealFailedNotAllowed) | [`invalid_argument`](/docs/errors/invalid-argument) | The submitted commitment contains `TimelockRevealFailed`, a terminal audit state that only the runtime may create after an automatic reveal fails. Submit a `TimelockEncrypted` field instead. |
| [`TooBig`](/docs/errors/chain/TooBig) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it. |
| [`TooFew`](/docs/errors/chain/TooFew) | [`invalid_argument`](/docs/errors/invalid-argument) | The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. |
| [`TooFewSignatories`](/docs/errors/chain/TooFewSignatories) | [`invalid_argument`](/docs/errors/invalid-argument) | The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. |
Expand Down
2 changes: 2 additions & 0 deletions docs/errors/chain/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"GasLimitTooHigh",
"GasLimitTooLow",
"GasPriceTooLow",
"GrandpaChangeDelayMustBeZero",
"HotKeyAccountNotExists",
"HotKeyAlreadyDelegate",
"HotKeyAlreadyRegisteredInSubNet",
Expand Down Expand Up @@ -312,6 +313,7 @@
"TempoOutOfBounds",
"TerminatedInConstructor",
"TerminatedWhileReentrant",
"TimelockRevealFailedNotAllowed",
"TooBig",
"TooFew",
"TooFewSignatories",
Expand Down
2 changes: 1 addition & 1 deletion docs/errors/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ A failed `execute` returns an `ExtrinsicResult` whose `error` has a semantic `co
| [`expired`](/docs/errors/expired) | 5 | The window has closed; restart the flow with fresh state |
| [`limit_exceeded`](/docs/errors/limit-exceeded) | 37 | A chain-side capacity limit was hit; reduce the size or count of the request |
| [`unit_mismatch`](/docs/errors/unit-mismatch) | — | Match the Balance netuid to the operation's currency |
| [`invalid_argument`](/docs/errors/invalid-argument) | 134 | Check the argument values against the operation schema |
| [`invalid_argument`](/docs/errors/invalid-argument) | 136 | Check the argument values against the operation schema |
| [`policy_violation`](/docs/errors/policy-violation) | 2 | The action exceeds a configured safety policy |
| [`internal`](/docs/errors/internal) | 19 | A chain-side invariant failed; nothing to fix client-side — report it if it persists |
| [`unknown`](/docs/errors/unknown) | — | Inspect the message for details |
2 changes: 2 additions & 0 deletions docs/errors/invalid-argument.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ The exact chain error names (from the extrinsic receipt) that classify to `inval
| [`GasLimitTooHigh`](/docs/errors/chain/GasLimitTooHigh) | The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. |
| [`GasLimitTooLow`](/docs/errors/chain/GasLimitTooLow) | The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. |
| [`GasPriceTooLow`](/docs/errors/chain/GasPriceTooLow) | The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. |
| [`GrandpaChangeDelayMustBeZero`](/docs/errors/chain/GrandpaChangeDelayMustBeZero) | `schedule_grandpa_change` was given a nonzero `in_blocks` delay. GRANDPA authority changes submitted through AdminUtils must activate at the end of the current block so the authority set and its set ID remain consistent. Pass `in_blocks=0`. |
| [`IncorrectCommitRevealVersion`](/docs/errors/chain/IncorrectCommitRevealVersion) | The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version. |
| [`IncorrectPartialFillAmount`](/docs/errors/chain/IncorrectPartialFillAmount) | The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`. |
| [`IncorrectWeightVersionKey`](/docs/errors/chain/IncorrectWeightVersionKey) | The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli sudo get --netuid <n>`) and update the validator software or the key. |
Expand Down Expand Up @@ -141,6 +142,7 @@ The exact chain error names (from the extrinsic receipt) that classify to `inval
| [`TargetBlockNumberInPast`](/docs/errors/chain/TargetBlockNumberInPast) | The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block. |
| [`TempoOutOfBounds`](/docs/errors/chain/TempoOutOfBounds) | The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain constants and pick a value inside the bounds; only root may set a tempo outside them. |
| [`TerminatedWhileReentrant`](/docs/errors/chain/TerminatedWhileReentrant) | `seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. |
| [`TimelockRevealFailedNotAllowed`](/docs/errors/chain/TimelockRevealFailedNotAllowed) | The submitted commitment contains `TimelockRevealFailed`, a terminal audit state that only the runtime may create after an automatic reveal fails. Submit a `TimelockEncrypted` field instead. |
| [`TooFew`](/docs/errors/chain/TooFew) | The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. |
| [`TooFewSignatories`](/docs/errors/chain/TooFewSignatories) | The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. |
| [`UidVecContainInvalidOne`](/docs/errors/chain/UidVecContainInvalidOne) | The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`). |
Expand Down
14 changes: 10 additions & 4 deletions docs/guides/conviction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ its current value.
| Field | Value | Meaning |
|-------|-------|---------|
| `SubnetAlphaOut` | 8,000,000 α | Outstanding alpha on the subnet |
| Ownership threshold | 800,000 α | 10% of alpha out — aggregate conviction gate |
| `SubnetProtocolAlpha` | 1,000,000 α | Protocol-owned alpha, excluded from the gate |
| `AlphaBurned` | 1,000,000 α | Burned alpha, excluded from the gate |
| Eligible alpha | 6,000,000 α | `SubnetAlphaOut − SubnetProtocolAlpha − AlphaBurned` |
| Ownership threshold | 600,000 α | 10% of eligible alpha — aggregate conviction gate |
| Subnet age | > 1 year | Required before ownership can transfer |
| Alice (owner) | 250,000 α locked | Perpetual lock on **owner hotkey** — conviction = mass |
| Bob (validator) | 600,000 α locked | Perpetual lock toward his validator hotkey |
Expand All @@ -44,7 +47,7 @@ its current value.

Drag **elapsed time** forward: Bob's perpetual conviction climbs toward 600k α.
Carol's decaying conviction **rises then falls** as her locked mass frees.
When **total conviction** crosses 800k α and the subnet is old enough, the
When **total conviction** crosses 600k α and the subnet is old enough, the
**highest-conviction hotkey** becomes the new owner.

## Perpetual vs decaying
Expand Down Expand Up @@ -75,7 +78,10 @@ After each epoch, the chain runs [`change_subnet_owner_if_needed`](/code/pallets
these hold:

1. Subnet age ≥ **ONE_YEAR** (2,629,800 blocks from registration).
2. **Total aggregate conviction** ≥ 10% of [`SubnetAlphaOut`](/code/pallets/subtensor/src/lib.rs#L1424).
2. **Total aggregate conviction** ≥ 10% of eligible alpha:
`SubnetAlphaOut − SubnetProtocolAlpha − AlphaBurned`. Subtraction
saturates at zero, and ownership does not transfer when eligible alpha is
zero.
3. A hotkey with the highest rolled aggregate conviction resolves to a real
coldkey owner (not the default account).

Expand All @@ -84,7 +90,7 @@ The winning hotkey becomes [`SubnetOwnerHotkey`](/code/pallets/subtensor/src/lib

This is **not** the same as the per-hotkey projection in
[`subnet-convictions`](/docs/query/subnet-convictions) — that API estimates when
*one* hotkey might reach 10% of alpha out; ownership requires **aggregate**
*one* hotkey might reach 10% of eligible alpha; ownership requires **aggregate**
conviction across all lockers.

## Lock a position on a real subnet
Expand Down
4 changes: 3 additions & 1 deletion docs/guides/staking.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ Quick reference:
[`UnlockRate`](/code/pallets/subtensor/src/lib.rs#L1658) is 934,866 blocks (~130 days) — read them live before planning
around either.
- Aggregate conviction can trigger **subnet ownership** after one year when
total conviction ≥ 10% of [`SubnetAlphaOut`](/code/pallets/subtensor/src/lib.rs#L1424).
total conviction ≥ 10% of eligible alpha
(`SubnetAlphaOut − SubnetProtocolAlpha − AlphaBurned`). The subtraction
saturates at zero; a zero eligible balance cannot trigger a transfer.
- Query with [`subnet-convictions`](/docs/query/subnet-convictions),
[`hotkey-conviction`](/docs/query/hotkey-conviction),
[`coldkey-lock`](/docs/query/coldkey-lock).
Expand Down
45 changes: 45 additions & 0 deletions docs/guides/timelock.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,51 @@ btcli timelock show <hex> # when it unlocks, without decrypting
`--file`); files may hold raw bytes or hex text. `decrypt --out` writes the
plaintext bytes to a file — useful for binary payloads.

## Publish a timelocked commitment on chain

The Commitments pallet accepts the inner TLE ciphertext and reveal round as a
`TimelockEncrypted` field. Sign this call with the registered hotkey:

```python
import bittensor as bt

sealed = bt.timelock.encrypt("embargoed result", reveal_in="1h")
call = bt.calls.Commitments.set_commitment(
netuid=42,
info={
"fields": [[{
"TimelockEncrypted": {
"encrypted": sealed.encrypted,
"reveal_round": sealed.reveal_round,
}
}]]
},
)
result = await client.submit_call(call, wallet, signer="hotkey")
```

`sealed.encrypted` is the pallet-native inner ciphertext. The portable
`bytes(sealed)` / `sealed.hex()` envelope includes the reveal-round trailer;
v446 accepts either representation on chain.

Once the pulse exists, the chain attempts the reveal automatically. A
successful plaintext is written to `RevealedCommitments` and emits
`CommitmentRevealed`. A commitment that is still waiting for a current or
future pulse remains `TimelockEncrypted` and stays pending.

V446 makes terminal reveal failures explicit. Corrupt ciphertext, a round
mismatch, an invalid quicknet point, or a pulse that has already expired is
rewritten in place as `TimelockRevealFailed` and emits
`CommitmentRevealFailed` once. The failed field remains in `CommitmentOf` for
audit, but is removed from the reveal index and is not retried. Users cannot
submit `TimelockRevealFailed` directly; it is a runtime-only state.

Inspect all states with:

```bash
btcli query commitments --netuid 42 --json
```

## Use cases

- **Sealed challenge answers** — a subnet mechanism publishes the answer
Expand Down
Loading
Loading