Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
- **BREAKING**: Rewrite the websocket client around a typed `Subscription` handle. `solana.rpc.websocket_api.connect()` and `SolanaWsClientProtocol` are replaced by `SolanaWsClient`, which owns its connection instead of subclassing it. Each `*_subscribe()` helper now awaits the server confirmation and returns a `Subscription`; the nine `*_unsubscribe(int)` helpers are replaced by a single `unsubscribe(subscription)`, so request IDs and server-assigned subscription IDs can no longer be confused. `recv()` and async iteration yield notifications only.
- **BREAKING**: A `*_subscribe()`/`unsubscribe()` call whose request already reached the wire tears down the whole connection if its wait ends early — either the `request_timeout` (10s default) expiring or the awaiting task being cancelled. Every other in-flight request fails with the same exception, every `Subscription` is dropped, and the client cannot be reused. The server may have created a subscription whose ID never arrived, and an orphaned subscription cannot be cancelled without it, so the connection is dropped instead. Cancelling `recv()` is still safe, and `close()` is shielded against cancellation. See [Subscribing to Events](https://michaelhly.github.io/solana-py/cookbook/development-guides/subscribing-to-events/) for details.

### Fixed

- `cluster_api_url("mainnet")` raised `AttributeError: 'ClusterUrls' object has no attribute 'mainnet'`. The cluster was renamed in 0.40.2, but the lookup still used the cluster name as the field name, and the `ClusterUrls` field is `mainnet_beta`.

## [0.40.3] - 2026-08-26

### Changed
Expand Down
3 changes: 3 additions & 0 deletions src/solana/utils/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ def cluster_api_url(cluster: Cluster | None = None, tls: bool = True) -> str:
urls = ENDPOINT.https if tls else ENDPOINT.http
if cluster is None:
return urls.devnet
if cluster == "mainnet":
# The cluster was renamed to "mainnet"; the ClusterUrls field kept its old name.
return urls.mainnet_beta
return getattr(urls, cluster)
9 changes: 9 additions & 0 deletions tests/unit/test_cluster_api_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ def test_input_output():
assert cluster_api_url("devnet") == "https://api.devnet.solana.com"
assert cluster_api_url("devnet", True) == "https://api.devnet.solana.com"
assert cluster_api_url("devnet", False) == "http://api.devnet.solana.com"
assert cluster_api_url("testnet") == "https://api.testnet.solana.com"
assert cluster_api_url("testnet", False) == "http://api.testnet.solana.com"


def test_mainnet():
"""Test that the mainnet cluster resolves to its URL."""
assert cluster_api_url("mainnet") == "https://api.mainnet.solana.com/"
assert cluster_api_url("mainnet", True) == "https://api.mainnet.solana.com/"
assert cluster_api_url("mainnet", False) == "http://api.mainnet.solana.com/"
Loading