-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* First approach to detecting runtime upgrades * Support for canceling the wait for runtime upgrade * Cleanup * Move code from the example into the library * Provide sync and async example * Provide a sync example as well * Use alloc instead of std * Error handling and documentation * Cleanup * Update src/api/rpc_api/runtime_update.rs Co-authored-by: Bigna Härdi <bigna.h@hotmail.com> * Update node-api/src/events/event_details.rs Co-authored-by: Bigna Härdi <bigna.h@hotmail.com> * Update src/api/rpc_api/runtime_update.rs Co-authored-by: Bigna Härdi <bigna.h@hotmail.com> * Update src/api/rpc_api/runtime_update.rs Co-authored-by: Bigna Härdi <bigna.h@hotmail.com> * Do acual runtime update in example * Add examples to tests * Fix test * Cleanup and documentation * Cleanup * Apply suggestions from code review Co-authored-by: Bigna Härdi <bigna.h@hotmail.com> * Expand async example to also trigger a runtime update * Only compile send_code_update_extrinsic in async compilation mode * Incorporate review feedback * Remove comment --------- Co-authored-by: Bigna Härdi <bigna.h@hotmail.com>
- Loading branch information
Showing
11 changed files
with
311 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
Copyright 2023 Supercomputing Systems AG | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
//! Example that shows how to detect a runtime update and afterwards update the metadata. | ||
use sp_keyring::AccountKeyring; | ||
use sp_weights::Weight; | ||
use substrate_api_client::{ | ||
ac_compose_macros::{compose_call, compose_extrinsic}, | ||
ac_primitives::{AssetRuntimeConfig, Config, ExtrinsicSigner as GenericExtrinsicSigner}, | ||
api_client::UpdateRuntime, | ||
rpc::JsonrpseeClient, | ||
rpc_api::RuntimeUpdateDetector, | ||
Api, SubmitAndWatch, SubscribeEvents, XtStatus, | ||
}; | ||
use tokio::select; | ||
use tokio_util::sync::CancellationToken; | ||
|
||
type ExtrinsicSigner = GenericExtrinsicSigner<AssetRuntimeConfig>; | ||
type Hash = <AssetRuntimeConfig as Config>::Hash; | ||
|
||
#[cfg(feature = "sync-examples")] | ||
#[tokio::main] | ||
async fn main() { | ||
println!("This example is for async use-cases. Please see runtime_update_sync.rs for the sync implementation.") | ||
} | ||
|
||
#[cfg(not(feature = "sync-examples"))] | ||
pub async fn send_code_update_extrinsic( | ||
api: &substrate_api_client::Api<AssetRuntimeConfig, JsonrpseeClient>, | ||
) { | ||
let new_wasm: &[u8] = include_bytes!("kitchensink_runtime.compact.compressed.wasm"); | ||
|
||
// this call can only be called by sudo | ||
let call = compose_call!(api.metadata(), "System", "set_code", new_wasm.to_vec()); | ||
let weight: Weight = 0.into(); | ||
let xt = compose_extrinsic!(&api, "Sudo", "sudo_unchecked_weight", call, weight); | ||
|
||
println!("Sending extrinsic to trigger runtime update"); | ||
let block_hash = api | ||
.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) | ||
.await | ||
.unwrap() | ||
.block_hash | ||
.unwrap(); | ||
println!("[+] Extrinsic got included. Block Hash: {:?}", block_hash); | ||
} | ||
|
||
#[cfg(not(feature = "sync-examples"))] | ||
#[tokio::main] | ||
async fn main() { | ||
env_logger::init(); | ||
|
||
// Initialize the api. | ||
let client = JsonrpseeClient::with_default_url().unwrap(); | ||
let mut api = Api::<AssetRuntimeConfig, _>::new(client).await.unwrap(); | ||
let sudoer = AccountKeyring::Alice.pair(); | ||
api.set_signer(ExtrinsicSigner::new(sudoer)); | ||
|
||
let subscription = api.subscribe_events().await.unwrap(); | ||
let mut update_detector: RuntimeUpdateDetector<Hash, JsonrpseeClient> = | ||
RuntimeUpdateDetector::new(subscription); | ||
println!("Current spec_version: {}", api.spec_version()); | ||
|
||
// Create future that informs about runtime update events | ||
let detector_future = update_detector.detect_runtime_update(); | ||
|
||
let token = CancellationToken::new(); | ||
let cloned_token = token.clone(); | ||
|
||
// To prevent blocking forever we create another future that cancels the | ||
// wait after some time | ||
tokio::spawn(async move { | ||
tokio::time::sleep(std::time::Duration::from_secs(5)).await; | ||
cloned_token.cancel(); | ||
println!("Cancelling wait for runtime update"); | ||
}); | ||
|
||
send_code_update_extrinsic(&api).await; | ||
|
||
// Wait for one of the futures to resolve and check which one resolved | ||
let runtime_update_detected = select! { | ||
_ = token.cancelled() => { | ||
false | ||
}, | ||
_ = detector_future => { | ||
api.update_runtime().await.unwrap(); | ||
true | ||
}, | ||
}; | ||
println!("Detected runtime update: {runtime_update_detected}"); | ||
println!("New spec_version: {}", api.spec_version()); | ||
assert!(api.spec_version() == 1268); | ||
assert!(runtime_update_detected); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
Copyright 2023 Supercomputing Systems AG | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
//! Example that shows how to detect a runtime update and afterwards update the metadata. | ||
use core::{ | ||
sync::atomic::{AtomicBool, Ordering}, | ||
time::Duration, | ||
}; | ||
use sp_keyring::AccountKeyring; | ||
use sp_weights::Weight; | ||
use std::{sync::Arc, thread}; | ||
use substrate_api_client::{ | ||
ac_compose_macros::{compose_call, compose_extrinsic}, | ||
ac_primitives::{AssetRuntimeConfig, Config, ExtrinsicSigner as GenericExtrinsicSigner}, | ||
api_client::UpdateRuntime, | ||
rpc::JsonrpseeClient, | ||
rpc_api::RuntimeUpdateDetector, | ||
Api, SubmitAndWatch, SubscribeEvents, XtStatus, | ||
}; | ||
|
||
type ExtrinsicSigner = GenericExtrinsicSigner<AssetRuntimeConfig>; | ||
type Hash = <AssetRuntimeConfig as Config>::Hash; | ||
|
||
#[cfg(not(feature = "sync-examples"))] | ||
#[tokio::main] | ||
async fn main() { | ||
println!("This example is for sync use-cases. Please see runtime_update_async.rs for the async implementation.") | ||
} | ||
|
||
pub fn send_code_update_extrinsic( | ||
api: &substrate_api_client::Api<AssetRuntimeConfig, JsonrpseeClient>, | ||
) { | ||
let new_wasm: &[u8] = include_bytes!("kitchensink_runtime.compact.compressed.wasm"); | ||
|
||
// Create a sudo `set_code` call. | ||
let call = compose_call!(api.metadata(), "System", "set_code", new_wasm.to_vec()); | ||
let weight: Weight = 0.into(); | ||
let xt = compose_extrinsic!(&api, "Sudo", "sudo_unchecked_weight", call, weight); | ||
|
||
println!("Sending extrinsic to trigger runtime update"); | ||
let block_hash = api | ||
.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) | ||
.unwrap() | ||
.block_hash | ||
.unwrap(); | ||
println!("[+] Extrinsic got included. Block Hash: {:?}", block_hash); | ||
} | ||
|
||
#[cfg(feature = "sync-examples")] | ||
#[tokio::main] | ||
async fn main() { | ||
env_logger::init(); | ||
|
||
// Initialize the api. | ||
let client = JsonrpseeClient::with_default_url().unwrap(); | ||
let mut api = Api::<AssetRuntimeConfig, _>::new(client).unwrap(); | ||
let sudoer = AccountKeyring::Alice.pair(); | ||
api.set_signer(ExtrinsicSigner::new(sudoer)); | ||
|
||
let subscription = api.subscribe_events().unwrap(); | ||
let cancellation = Arc::new(AtomicBool::new(false)); | ||
let mut update_detector: RuntimeUpdateDetector<Hash, JsonrpseeClient> = | ||
RuntimeUpdateDetector::new_with_cancellation(subscription, cancellation.clone()); | ||
|
||
println!("Current spec_version: {}", api.spec_version()); | ||
|
||
let handler = thread::spawn(move || { | ||
// Wait for potential runtime update events | ||
let runtime_update_detected = update_detector.detect_runtime_update().unwrap(); | ||
println!("Detected runtime update: {runtime_update_detected}"); | ||
assert!(runtime_update_detected); | ||
}); | ||
|
||
// Execute an actual runtime update | ||
{ | ||
send_code_update_extrinsic(&api); | ||
} | ||
|
||
// Sleep for some time in order to wait for a runtime update | ||
// If no update happens we cancel the wait | ||
{ | ||
thread::sleep(Duration::from_secs(1)); | ||
cancellation.store(true, Ordering::SeqCst); | ||
} | ||
|
||
handler.join().unwrap(); | ||
api.update_runtime().unwrap(); | ||
println!("New spec_version: {}", api.spec_version()); | ||
assert!(api.spec_version() == 1268); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.