diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b2388de..d05cec27d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,33 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ +## [v1.3.0] - 2023-12-15 + +The main changes of this release are as follows: +- Change the binary name to `polkadot-staking-miner` to publish on crates.io. +- Temporarly disable runtime upgrades more information below. +- Bump rust MSRV to 1.74 +- Change `submit_signed_solution` extrinsic to be mortal +- A runtime upgrade bug was discovered and is fixed in this release. + +### Runtime upgrade bug fixed. + +Recently, we noticed that it can be possible that the runtime upgrades won't +upgrade the metadata because the actual runtime upgrade is applied to the block +after 'state_subscribeRuntimeVersion' emits an event. + +For that reason, the polkadot-staking-miner now subscribes to `system().last_runtime_upgrade()` instead to fix that. + +### [Changed] +- refactor: make solution extrinsic mortal ([#728](https://github.com/paritytech/staking-miner-v2/pull/728)) +- chore(deps): bump subxt, subxt-signer, scale-value ([#726](https://github.com/paritytech/staking-miner-v2/pull/726)) +- chore(deps): bump clap from 4.4.10 to 4.4.11 ([#721](https://github.com/paritytech/staking-miner-v2/pull/721)) +- chore(deps): bump tokio from 1.34.0 to 1.35.0 ([#724](https://github.com/paritytech/staking-miner-v2/pull/724)) +- chore(deps): bump once_cell from 1.18.0 to 1.19.0 ([#722](https://github.com/paritytech/staking-miner-v2/pull/722)) +- refactor: use `subxt-signer` to reduce the number of deps ([#720](https://github.com/paritytech/staking-miner-v2/pull/720)) +- chore(deps): bump clap from 4.4.8 to 4.4.10 ([#719](https://github.com/paritytech/staking-miner-v2/pull/719)) +- rename project to polkadot-staking-miner ([#717](https://github.com/paritytech/staking-miner-v2/pull/717)) + ## [v1.2.0] - 2023-11-23 The major changes of this release: diff --git a/Cargo.lock b/Cargo.lock index 9a9b8620a..074cf88f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3180,7 +3180,7 @@ checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "polkadot-staking-miner" -version = "1.2.0" +version = "1.3.0" dependencies = [ "anyhow", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 9d0bdf348..fe1032013 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-staking-miner" -version = "1.2.0" +version = "1.3.0" authors = ["Parity Technologies "] edition = "2021" rust-version = "1.74.0" @@ -51,4 +51,4 @@ regex = "1" [features] default = [] -slow-tests = [] +slow-tests = [] \ No newline at end of file diff --git a/src/client.rs b/src/client.rs index e8733f20c..98464e0fe 100644 --- a/src/client.rs +++ b/src/client.rs @@ -9,6 +9,8 @@ pub struct Client { rpc: RpcClient, /// Access to chain APIs such as storage, events etc. chain_api: ChainClient, + /// Raw RPC client. + raw_rpc: RawRpcClient, } impl Client { @@ -36,8 +38,7 @@ impl Client { }; let chain_api = ChainClient::from_rpc_client(rpc.clone()).await?; - - Ok(Self { rpc: RpcClient::new(rpc), chain_api }) + Ok(Self { rpc: RpcClient::new(rpc.clone()), raw_rpc: rpc, chain_api }) } /// Get a reference to the RPC interface exposed by subxt. @@ -49,4 +50,9 @@ impl Client { pub fn chain_api(&self) -> &ChainClient { &self.chain_api } + + /// Get a reference to the raw rpc client API. + pub fn raw_rpc(&self) -> &RawRpcClient { + &self.raw_rpc + } } diff --git a/src/main.rs b/src/main.rs index 8a5e8492d..934a8ded3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,10 +39,12 @@ mod prometheus; mod static_types; use clap::Parser; +use codec::Decode; use error::Error; use futures::future::{BoxFuture, FutureExt}; use prelude::*; use std::str::FromStr; +use subxt::backend::rpc::RpcSubscription; use tokio::sync::oneshot; use tracing_subscriber::EnvFilter; @@ -127,7 +129,7 @@ async fn main() -> Result<(), Error> { // Start a new tokio task to perform the runtime updates in the background. // if this fails then the miner will be stopped and has to be re-started. let (tx_upgrade, rx_upgrade) = oneshot::channel::(); - tokio::spawn(runtime_upgrade_task(client.chain_api().clone(), tx_upgrade)); + tokio::spawn(runtime_upgrade_task(client.clone(), tx_upgrade, runtime_version.spec_version)); let res = any_runtime!(chain, { let fut = match command { @@ -156,7 +158,7 @@ async fn main() -> Result<(), Error> { run_command(fut, rx_upgrade).await }); - log::info!(target: LOG_TARGET, "round of execution finished. outcome = {:?}", res); + log::debug!(target: LOG_TARGET, "round of execution finished. outcome = {:?}", res); res } @@ -206,49 +208,85 @@ async fn run_command( } /// Runs until the RPC connection fails or updating the metadata failed. -async fn runtime_upgrade_task(api: ChainClient, tx: oneshot::Sender) { - let updater = api.updater(); +async fn runtime_upgrade_task(client: Client, tx: oneshot::Sender, mut spec_version: u32) { + use sp_core::storage::StorageChangeSet; + + async fn new_update_stream( + client: &Client, + ) -> Result>, subxt::Error> { + use sp_core::Bytes; + use subxt::rpc_params; + + let storage_key = Bytes(runtime::storage().system().last_runtime_upgrade().to_root_bytes()); + + client + .raw_rpc() + .subscribe( + "state_subscribeStorage", + rpc_params![vec![storage_key]], + "state_unsubscribeStorage", + ) + .await + } - let mut update_stream = match updater.runtime_updates().await { - Ok(u) => u, + let mut update_stream = match new_update_stream(&client).await { + Ok(s) => s, Err(e) => { - let _ = tx.send(e.into()); - return + _ = tx.send(e.into()); + return; }, }; - loop { - // if the runtime upgrade subscription fails then try establish a new one and if it fails quit. - let update = match update_stream.next().await { - Some(Ok(update)) => update, - _ => { - log::warn!(target: LOG_TARGET, "Runtime upgrade subscription failed"); - update_stream = match updater.runtime_updates().await { - Ok(u) => u, - Err(e) => { - let _ = tx.send(e.into()); - return - }, + let close_err = loop { + let change_set = match update_stream.next().await { + Some(Ok(changes)) => changes, + Some(Err(err)) => break err.into(), + None => { + update_stream = match new_update_stream(&client).await { + Ok(sub) => sub, + Err(err) => break err.into(), }; - continue + continue; }, }; - let version = update.runtime_version().spec_version; - match updater.apply_update(update) { - Ok(()) => { - if let Err(e) = epm::update_metadata_constants(&api) { - let _ = tx.send(e); - return - } - prometheus::on_runtime_upgrade(); - log::info!(target: LOG_TARGET, "upgrade to v{} successful", version); - }, - Err(e) => { - log::debug!(target: LOG_TARGET, "upgrade to v{} failed: {:?}", version, e); - }, + let at = change_set.block; + assert!(change_set.changes.len() < 2, "Only one storage change per runtime upgrade"); + let Some(bytes) = change_set.changes.get(0).and_then(|v| v.1.clone()) else { continue }; + let next: runtime::runtime_types::frame_system::LastRuntimeUpgradeInfo = + match Decode::decode(&mut bytes.0.as_ref()) { + Ok(n) => n, + Err(e) => break e.into(), + }; + + if next.spec_version > spec_version { + let metadata = match client.rpc().state_get_metadata(Some(at)).await { + Ok(m) => m, + Err(err) => break err.into(), + }; + + let runtime_version = match client.rpc().state_get_runtime_version(Some(at)).await { + Ok(r) => r, + Err(err) => break err.into(), + }; + + client.chain_api().set_metadata(metadata); + client.chain_api().set_runtime_version(subxt::backend::RuntimeVersion { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + }); + + spec_version = next.spec_version; + prometheus::on_runtime_upgrade(); + + log::info!(target: LOG_TARGET, "Runtime upgraded to v{spec_version}"); + if let Err(e) = epm::update_metadata_constants(client.chain_api()) { + break e; + } } - } + }; + + let _ = tx.send(close_err.into()); } #[cfg(test)] diff --git a/src/opt.rs b/src/opt.rs index 45430ee6b..3bac15e4a 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -119,7 +119,7 @@ impl From for RuntimeVersion { } } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] pub struct RuntimeVersion { pub spec_name: String, pub impl_name: String,