## subxt Test with Smoldot + ChainHeadBackend
The below example is using:
- `Smoldot`: since I create the light client with `LightClient::relay_chain`
- `ChainHeadBackend`: since I use `ChainHeadBackendBuilder::default().build_with_background_driver(polkadot_rpc...`
### Test Goal
The goal of this test is to check if when using `Smoldot` + `ChainHeadBackend`, we get duplicates in bounties storage keys.
### Example / Test
#### Cargo.toml
```toml
[dependencies]
subxt-lightclient = "0.44.0"
subxt = { version = "0.44.0", features = ["unstable-light-client"] }
subxt-rpcs = { version = "0.44.0", features = ["unstable-light-client"] }
smoldot = "0.20" # used latest
smoldot-light = "0.18" # used latest
tokio = { version = "1", features = ["full"] }
tracing-subscriber = "0.3"
futures = "0.3.31"
codec = { package = "parity-scale-codec", version = "3" }
hex = "0.4.3"
```
#### main.rs
```rust
#![allow(missing_docs)]
use subxt::{client::OnlineClient, lightclient::LightClient, PolkadotConfig};
use std::collections::BTreeMap;
use subxt::backend::chain_head::{ChainHeadBackend, ChainHeadBackendBuilder};
#[subxt::subxt(runtime_metadata_path = "artifacts/polkadot_metadata_full.scale")]
pub mod polkadot {}
const POLKADOT_SPEC: &str = include_str!("../artifacts/demo_chain_specs/polkadot.json");
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
// Smoldot light client
let (_lightclient, polkadot_rpc) = LightClient::relay_chain(POLKADOT_SPEC)?;
// Convert to unstable backend (ChainHead)
let unstable_backend: ChainHeadBackend<PolkadotConfig> =
ChainHeadBackendBuilder::default().build_with_background_driver(polkadot_rpc.clone());
let api = OnlineClient::from_backend(std::sync::Arc::new(unstable_backend)).await?;
let address = polkadot::storage()
.bounties()
.bounties_iter();
let mut iter = api.storage().at_latest().await?.iter(address).await?;
let mut data = BTreeMap::new();
let mut total_count = 0;
while let Some(Ok(storage)) = iter.next().await {
total_count += 1;
let id = get_bounty_id_from_storage_key(storage.key_bytes.clone());
if data.contains_key(&id) {
println!("ā ļø Duplicate detected! ID: {} at item #{}", id, total_count);
println!(" Key: 0x{}", hex::encode(&storage.key_bytes));
}
data.entry(id).and_modify(|n| *n += 1).or_insert(1);
}
println!("\nš Final Results:");
println!("Total items: {}", total_count);
println!("Unique IDs: {}", data.len());
println!("Duplicates: {}", total_count - data.len());
for (id, count) in data.iter() {
if *count > 1 {
println!(" ID {} appeared {} times", id, count);
}
}
Ok(())
}
pub fn get_bounty_id_from_storage_key(key: Vec<u8>) -> u32 {
let s = &key[key.len() - 4..];
let v: [u8; 4] = s.try_into().expect("slice with incorrect length");
u32::from_le_bytes(v)
}
```
## Outputs
### Output after Multiple Runs
Usually, during consecutive runs we get the same result (shown below) hence we find no duplicates in the bounties storage keys.
```
2025-10-23T09:55:14.577227Z INFO runtime-polkadot: Finalized block runtime ready. Spec version: 1007001. Size of `:code`: 2.0 MiB.
š Final Results:
Total items: 23
Unique IDs: 23
Duplicates: 0
```
### Output in Some Runs
There are some runs during which the output hangs. It seems that it is happening whenever I see the following `Successfully compiled runtime. Spec version: 1007001` in the logs.
So in the terminal I see:
```
2025-10-23T09:50:24.151507Z INFO runtime-polkadot: Successfully compiled runtime. Spec version: 1006001. Size of `:code`: 1.9 MiB.
2025-10-23T09:50:36.002975Z INFO runtime-polkadot: Finalized block runtime ready. Spec version: 1007001. Size of `:code`: 2.0 MiB.
2025-10-23T09:50:38.453057Z INFO runtime-polkadot: Successfully compiled runtime. Spec version: 1007001. Size of `:code`: 2.0 MiB.
```
and then no further output and the program does not terminate.