// Smoldot
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
use core::{iter, num::NonZeroU32};
use futures_lite::FutureExt as _;
fn main() {
// The `DefaultPlatform` that we use below uses the `log` crate to emit logs.
// We need to register some kind of logs listener, in this example `env_logger`.
// See also .
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
// Now initialize the client. This does nothing except allocate resources.
// The `Client` struct requires a generic parameter that provides platform bindings. In this
// example, we provide `DefaultPlatform`, which are the "plug and play" default platform.
// Any advance usage, such as embedding a client in WebAssembly, will likely require a custom
// implementation of these bindings.
let mut client =
smoldot_light::Client::new(smoldot_light::platform::default::DefaultPlatform::new(
env!("CARGO_PKG_NAME").into(),
env!("CARGO_PKG_VERSION").into(),
));
// Ask the client to connect to Polkadot.
let smoldot_light::AddChainSuccess {
chain_id: polkadot_chain_id,
json_rpc_responses: polkadot_json_rpc_responses,
} = client
.add_chain(smoldot_light::AddChainConfig {
// The most important field of the configuration is the chain specification. This is a
// JSON document containing all the information necessary for the client to connect to said
// chain.
specification: include_str!("../../demo-chain-specs/polkadot.json"),
// Configures some constants about the JSON-RPC endpoints.
// It is also possible to pass `Disabled`, in which case the chain will not be able to
// handle JSON-RPC requests. This can be used to save up some resources.
json_rpc: smoldot_light::AddChainConfigJsonRpc::Enabled {
// Maximum number of JSON-RPC in the queue of requests waiting to be processed.
// This parameter is necessary for situations where the JSON-RPC clients aren't
// trusted. If you control all the requests that are sent out and don't want them
// to fail, feel free to pass `u32::MAX`.
max_pending_requests: NonZeroU32::new(128).unwrap(),
// Maximum number of active subscriptions before new ones are automatically
// rejected. Any JSON-RPC request that causes the server to generate notifications
// counts as a subscription.
// While a typical reasonable value would be for example 64, existing UIs tend to
// start a lot of subscriptions, and a value such as 1024 is recommended.
// Similarly, if you don't want any limit, feel free to pass `u32::MAX`.
max_subscriptions: 1024,
},
// This field is necessary only if adding a parachain.
potential_relay_chains: iter::empty(),
// After a chain has been added, it is possible to extract a "database" (in the form of a
// simple string). This database can later be passed back the next time the same chain is
// added again.
// A database with an invalid format is simply ignored by the client.
// In this example, we don't use this feature, and as such we simply pass an empty string,
// which is intentionally an invalid database content.
database_content: "",
// The client gives the possibility to insert an opaque "user data" alongside each chain.
// This avoids having to create a separate `HashMap` in parallel of the
// client.
// In this example, this feature isn't used. The chain simply has `()`.
user_data: (),
})
.unwrap();
// The Polkadot chain is now properly initialized.
// `json_rpc_responses` can only be `None` if we had passed `json_rpc: Disabled` in the
// configuration.
let mut polkadot_json_rpc_responses = polkadot_json_rpc_responses.unwrap();
// Ask the client to connect to Polkadot's Assethub, which is one of its parachains.
let smoldot_light::AddChainSuccess {
chain_id: assethub_chain_id,
json_rpc_responses: assethub_json_rpc_responses,
} = client
.add_chain(smoldot_light::AddChainConfig {
// These options are the same as above.
specification: include_str!("../../demo-chain-specs/polkadot-asset-hub.json"),
json_rpc: smoldot_light::AddChainConfigJsonRpc::Enabled {
max_pending_requests: NonZeroU32::new(128).unwrap(),
max_subscriptions: 1024,
},
database_content: "",
user_data: (),
// The chain specification of the asset hub parachain mentions that the identifier
// of its relay chain is `polkadot`. Because the `Client` might contain multiple different
// chains whose identifier is `polkadot`, we need to provide a list of all the chains
// that the `Client` should consider when searching for the relay chain. The `add_chain`
// function returns an error if there is no match or if there are multiple matches when
// searching for an appropriate relay chain within this list.
// The reason why this option exists is to allow multiple different API users to share
// usage of the same smoldot client without interfering with each other. If there is
// only one API user (like is the case here), passing the list of all chains that have
// previously been created is completely appropriate.
potential_relay_chains: [polkadot_chain_id].into_iter(),
})
.unwrap();
// The Assethub chain is now properly initialized.
// Just like above, we are guaranteed that `json_rpc_responses` is `Some`.
let mut assethub_json_rpc_responses = assethub_json_rpc_responses.unwrap();
// The example here asks the client to send us notifications whenever the new best block of
// Polkadot or the Assethub has changed.
// Calling the `json_rpc_request` function only queues the request. It is not processed
// immediately. An `Err` is returned immediately if and only if the channel of JSON-RPC
// responses is clogged, as configured through the `max_pending_requests` option that was
// passed to `addChain`.
client
.json_rpc_request(
r#"{"id":1,"jsonrpc":"2.0","method":"chain_subscribeNewHeads","params":[]}"#,
polkadot_chain_id,
)
.unwrap();
client
.json_rpc_request(
r#"{"id":1,"jsonrpc":"2.0","method":"chain_subscribeNewHeads","params":[]}"#,
assethub_chain_id,
)
.unwrap();
// Now block the execution forever and print the responses received on the channels of
// JSON-RPC responses.
smol::block_on(async move {
loop {
let (chain_name, response) = async {
(
"Polkadot",
polkadot_json_rpc_responses.next().await.unwrap(),
)
}
.or(async {
(
"Assethub",
assethub_json_rpc_responses.next().await.unwrap(),
)
})
.await;
println!("{chain_name} JSON-RPC response: {response}");
}
});
}