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
Copy file name to clipboardExpand all lines: CHANGELOG.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
11
11
- CI
12
12
- The Agave toolchain install retries, and a failed one now fails the job. Eight workflow steps across five workflows ran `sh -c "$(curl -sSfL .../install)"` once with no retry, so a transient reset from `release.anza.xyz` killed a job before it ran anything. That form also swallowed a failed fetch: the command substitution comes back empty, `sh -c ""` exits 0, and the step passed having installed nothing. The eight are now one composite action at `.github/actions/solana-toolchain` that fetches and runs as separate steps, checks `solana --version` actually runs, clears partial state between attempts, bounds every wait so a stalled handshake or hung transfer reaches the backoff instead of sitting until the job times out, and backs off. Each caller keeps the version it used before; `solana.yml` and `offchain.local-validator.yml` are on v3.0.12 and the other three on v3.0.4, which is drift worth settling separately.
13
13
- Serviceability
14
+
- New user accounts record the selected access-pass address, and deletion rejects another pass while preserving legacy address validation.
14
15
-`write_stake_mirror` in the instruction crate and `WriteStakeMirrorCommand` in the Rust SDK, so the relayer has a caller-side surface for the instruction A6 added. The command departs from its neighbours in one way: every other one uses `append_payer_permission_account`, which attaches the caller's `Permission` account only when it already exists, because a legacy `GlobalState` key might authorize instead. No legacy key satisfies `STAKE_ORACLE`, so a missing `Permission` account is always fatal here, and the command says so locally rather than sending a transaction that can only come back `NotAllowed`. It checks what `authorize` checks, not just ownership: an account that does not decode, a suspended `Permission`, and one lacking the flag are each refused with the reason named, which matters because suspending a `Permission` is what revoking the relayer's key looks like.
15
16
- New `WriteStakeMirror` instruction (variant 119) and a `STAKE_ORACLE` permission, which is what a relayer will call to copy a builder's Solana stake onto the DZ ledger. Nothing could write a `StakeMirror` before this. The instruction refuses a write whose `source_slot` is not newer than the stored one: polling makes a repeated write harmless but says nothing about ordering, and a retry carrying an older read could otherwise walk the mirror backwards, so the program enforces it rather than trusting the caller. It also refuses to reassign a mirror to a different builder, since the builder is not a PDA seed, and it carries `feed_key` forward rather than taking it from the caller, because `CreateFeed` writes that to spend the stake and zeroing it would let one bond back two feeds. No legacy GlobalState key maps to `STAKE_ORACLE`, so a holder needs a real `Permission` account even while `require-permission-accounts` is clear. Gated on `allow-staked-feeds` with the rest of RFC-28. `STAKE_ORACLE` is grantable through `doublezero permission set --add stake-oracle`, named by `permission audit` and `bitmask_to_names`, listed in `AUTHORIZE_GATED_FLAGS` and in the Go SDK's flag constants. It is the first flag no legacy `GlobalState` key can satisfy, which the audit's own test now asserts through a `PERMISSION_ONLY_FLAGS` list rather than treating as a gap in the enumeration.
16
17
-`Feed` carries the RFC-28 stake terms: `builder`, `stake_ref`, `spec_id`, `sla_hash`, `committed_rate_bits_per_sec` and a lifecycle `status`. Setting them needs the new `allow-staked-feeds` feature flag, which no cluster has, so `CreateFeed` refuses a builder until the stake mirror and the attestor exist; without the flag the instruction behaves as before. The fields are appended rather than versioned, so a feed written before this decodes with them defaulted and `try_acc_write` resizes the account on the next update. `status` is the exception to defaulting: a short account reads `Active`, because reading it as `Pending` would pull every live catalog feed out of service. The rate is bits per second, not basis points, which is what `bps` means elsewhere in DoubleZero.
@@ -19,6 +20,8 @@ All notable changes to this project will be documented in this file.
19
20
- A feed admits a subscriber only while its status is `Active`. `SubscribeFeed` and `CreateSubscribeUser` both check it where the seat is spent, so a feed that is pending conformance, halted, or retired stops taking subscribers the moment its status changes, and retiring one needs no sweep over the access passes already holding a seat for it. The check is deliberately not in the shared coverage path, which `UnsubscribeFeed` also runs: gating there would leave a user holding a seat on a retired feed with no way to release it. New error `FeedNotActive` (123). Live subscribers are unaffected until they disconnect; evicting them is separate work.
20
21
- Test coverage for the RFC-28 publish-rights path, which needs no new instruction. A feed's multicast groups are created with `owner` set to the builder, and `AddMulticastGroupPubAllowlist` authorizes on `mgroup.owner == payer`, so the builder grants its own publish rights without the catalog admin that created the feed. The test walks it with two distinct signers.
21
22
- SDK
23
+
- User deletion and disconnect select the recorded pass, while legacy conflicts list both candidates and require `--access-pass`.
24
+
- Go, Python, and TypeScript readers expose the recorded address and decode legacy accounts with the default public key.
22
25
- The Rust SDK sends program logs and errors through the log facade instead of straight to stderr. A failed transaction's program logs now arrive as one `error!` record carrying the signature, so a service embedding the SDK can capture, filter and ship them. Four `eprintln!` sites bypassed logging entirely, while the same function logged the successful path at debug level: an operator saw every transaction that worked and got raw stderr for one that failed. RFC-20 already asks modules to use the standard log macros. One behavior change for the CLI: `--log-level off` silences program logs, which previously printed whatever the level (#4299).
23
26
-`sdk/shreds/go` carries the feed subscription program's `FeedDistribution` account: how much USDC one feed collected for one calendar month. The program is a second program alongside shred subscription and had nothing in this SDK, so each consumer decoded the account at fixed byte offsets itself, lake included. The account is a bytemuck Pod read here field by field, which agrees with the Pod bytes only because the field order leaves no interior padding; `TestStructSizes` pins the 120-byte total and a new test pins every field against a real mainnet account. `Client` is built around one program ID and so gains no fetch method, and `DeserializeFeedDistribution` is exported for a caller that makes its own `getProgramAccounts` call. `make sdk-test` never ran `./sdk/shreds/go/...`, so this package's layout pins have never run in CI; it runs them now. (#4216)
24
27
- The TypeScript and Python `Feed` deserializers read the RFC-28 tail and synthesize `Active` for an account that carries no status byte, matching the Rust program. New `feed_legacy` fixture covers that path alongside the updated `feed` fixture.
0 commit comments