fix restart issue of staking miner (#4073)

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
This commit is contained in:
Kian Paimani
2021-10-14 13:12:01 +01:00
committed by GitHub
parent 56e9f5fedc
commit 51b694e05c
4 changed files with 170 additions and 138 deletions
+93 -86
View File
@@ -21,7 +21,7 @@ use crate::{
};
use codec::Encode;
use jsonrpsee_ws_client::{
types::{traits::SubscriptionClient, v2::params::JsonRpcParams, Subscription},
types::{traits::SubscriptionClient, Subscription},
WsClient,
};
use sc_transaction_pool_api::TransactionStatus;
@@ -71,106 +71,113 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! {
signer: Signer,
) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> {
use $crate::[<$runtime _runtime_exports>]::*;
let (sub, unsub) = if config.listen == "head" {
("chain_subscribeNewHeads", "chain_unsubscribeNewHeads")
} else {
("chain_subscribeFinalizedHeads", "chain_unsubscribeFinalizedHeads")
};
log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", sub, unsub);
let mut subscription: Subscription<Header> = client
.subscribe(&sub, JsonRpcParams::NoParams, &unsub)
.await
.unwrap();
loop {
log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", sub, unsub);
let mut subscription: Subscription<Header> = client
.subscribe(&sub, params! {}, &unsub)
.await
.unwrap();
while let Some(now) = subscription.next().await? {
let hash = now.hash();
log::debug!(target: LOG_TARGET, "new event at #{:?} ({:?})", now.number, hash);
while let Some(now) = subscription.next().await? {
let hash = now.hash();
log::trace!(target: LOG_TARGET, "new event at #{:?} ({:?})", now.number, hash);
// if the runtime version has changed, terminate
crate::check_versions::<Runtime>(client, false).await?;
// if the runtime version has changed, terminate.
crate::check_versions::<Runtime>(client).await?;
// we prefer doing this check before fetching anything into a remote-ext.
if ensure_signed_phase::<Runtime, Block>(client, hash).await.is_err() {
log::debug!(target: LOG_TARGET, "phase closed, not interested in this block at all.");
continue;
};
// we prefer doing this check before fetching anything into a remote-ext.
if ensure_signed_phase::<Runtime, Block>(client, hash).await.is_err() {
log::debug!(target: LOG_TARGET, "phase closed, not interested in this block at all.");
continue;
};
// NOTE: we don't check the score of any of the submitted solutions. If we submit a weak
// one, as long as we are valid, we will end up getting our deposit back, so not a big
// deal for now. Note that to avoid an unfeasible solution, we should make sure that we
// only start the process on a finalized snapshot. If the signed phase is long enough,
// this will not be a solution.
// grab an externalities without staking, just the election snapshot.
let mut ext = crate::create_election_ext::<Runtime, Block>(
shared.uri.clone(),
Some(hash),
vec![],
).await?;
// grab an externalities without staking, just the election snapshot.
let mut ext = crate::create_election_ext::<Runtime, Block>(shared.uri.clone(), Some(hash), vec![]).await?;
if ensure_no_previous_solution::<Runtime, Block>(&mut ext, &signer.account).await.is_err() {
log::debug!(target: LOG_TARGET, "We already have a solution in this phase, skipping.");
continue;
}
if ensure_no_previous_solution::<Runtime, Block>(&mut ext, &signer.account).await.is_err() {
log::debug!(target: LOG_TARGET, "We already have a solution in this phase, skipping.");
continue;
// mine a solution, and run feasibility check on it as well.
let (raw_solution, witness) = crate::mine_with::<Runtime>(&config.solver, &mut ext, true)?;
log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score);
let nonce = crate::get_account_info::<Runtime>(client, &signer.account, Some(hash))
.await?
.map(|i| i.nonce)
.expect(crate::signer::SIGNER_ACCOUNT_WILL_EXIST);
let tip = 0 as Balance;
let period = <Runtime as frame_system::Config>::BlockHashCount::get() / 2;
let current_block = now.number.saturating_sub(1);
let era = sp_runtime::generic::Era::mortal(period.into(), current_block.into());
log::trace!(
target: LOG_TARGET, "transaction mortality: {:?} -> {:?}",
era.birth(current_block.into()),
era.death(current_block.into()),
);
let extrinsic = ext.execute_with(|| create_uxt(raw_solution, witness, signer.clone(), nonce, tip, era));
let bytes = sp_core::Bytes(extrinsic.encode());
let mut tx_subscription: Subscription<
TransactionStatus<<Block as BlockT>::Hash, <Block as BlockT>::Hash>
> = match client
.subscribe(&"author_submitAndWatchExtrinsic", params! { bytes }, "author_unwatchExtrinsic")
.await
{
Ok(sub) => sub,
Err(why) => {
// This usually happens when we've been busy with mining for a few blocks, and
// now we're receiving the subscriptions of blocks in which we were busy. In
// these blocks, we still don't have a solution, so we re-compute a new solution
// and submit it with an outdated `Nonce`, which yields most often `Stale`
// error. NOTE: to improve this overall, and to be able to introduce an array of
// other fancy features, we should make this multi-threaded and do the
// computation outside of this callback.
log::warn!(target: LOG_TARGET, "failing to submit a transaction {:?}. continuing...", why);
continue
}
};
while let Some(status_update) = tx_subscription.next().await? {
log::trace!(target: LOG_TARGET, "status update {:?}", status_update);
match status_update {
TransactionStatus::Ready | TransactionStatus::Broadcast(_) | TransactionStatus::Future => continue,
TransactionStatus::InBlock(hash) => {
log::info!(target: LOG_TARGET, "included at {:?}", hash);
let key = frame_support::storage::storage_prefix(b"System", b"Events");
let events = get_storage::<Vec<frame_system::EventRecord<Event, <Block as BlockT>::Hash>>,
>(client, params!{ key, hash }).await?.unwrap_or_default();
log::info!(target: LOG_TARGET, "events at inclusion {:?}", events);
}
TransactionStatus::Retracted(hash) => {
log::info!(target: LOG_TARGET, "Retracted at {:?}", hash);
}
TransactionStatus::Finalized(hash) => {
log::info!(target: LOG_TARGET, "Finalized at {:?}", hash);
break
}
_ => {
log::warn!(target: LOG_TARGET, "Stopping listen due to other status {:?}", status_update);
break
}
}
};
}
let (raw_solution, witness) = crate::mine_with::<Runtime>(&config.solver, &mut ext)?;
log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score);
let nonce = crate::get_account_info::<Runtime>(client, &signer.account, Some(hash))
.await?
.map(|i| i.nonce)
.expect(crate::signer::SIGNER_ACCOUNT_WILL_EXIST);
let tip = 0 as Balance;
let period = <Runtime as frame_system::Config>::BlockHashCount::get() / 2;
let current_block = now.number.saturating_sub(1);
let era = sp_runtime::generic::Era::mortal(period.into(), current_block.into());
log::trace!(target: LOG_TARGET, "transaction mortality: {:?} -> {:?}", era.birth(current_block.into()), era.death(current_block.into()));
let extrinsic = ext.execute_with(|| create_uxt(raw_solution, witness, signer.clone(), nonce, tip, era));
let bytes = sp_core::Bytes(extrinsic.encode());
let mut tx_subscription: Subscription<
TransactionStatus<<Block as BlockT>::Hash, <Block as BlockT>::Hash>
> = match client
.subscribe(&"author_submitAndWatchExtrinsic", params! { bytes }, "author_unwatchExtrinsic")
.await
{
Ok(sub) => sub,
Err(why) => {
// This usually happens when we've been busy with mining for a few blocks, and now we're receiving the
// subscriptions of blocks in which we were busy. In these blocks, we still don't have a solution, so we
// re-compute a new solution and submit it with an outdated `Nonce`, which yields most often `Stale`
// error. NOTE: to improve this overall, and to be able to introduce an array of other fancy features,
// we should make this multi-threaded and do the computation outside of this callback.
log::warn!(target: LOG_TARGET, "failing to submit a transaction {:?}. continuing...", why);
continue
}
};
let _success = while let Some(status_update) = tx_subscription.next().await? {
log::trace!(target: LOG_TARGET, "status update {:?}", status_update);
match status_update {
TransactionStatus::Ready | TransactionStatus::Broadcast(_) | TransactionStatus::Future => continue,
TransactionStatus::InBlock(hash) => {
log::info!(target: LOG_TARGET, "included at {:?}", hash);
let key = frame_support::storage::storage_prefix(b"System", b"Events");
let events = get_storage::<Vec<frame_system::EventRecord<Event, <Block as BlockT>::Hash>>,
>(client, params!{ key, hash }).await?.unwrap_or_default();
log::info!(target: LOG_TARGET, "events at inclusion {:?}", events);
}
TransactionStatus::Retracted(hash) => {
log::info!(target: LOG_TARGET, "Retracted at {:?}", hash);
}
TransactionStatus::Finalized(hash) => {
log::info!(target: LOG_TARGET, "Finalized at {:?}", hash);
break
}
_ => {
log::warn!(target: LOG_TARGET, "Stopping listen due to other status {:?}", status_update);
break
}
}
};
log::warn!(target: LOG_TARGET, "subscription to {} terminated. Retrying..", sub)
}
Ok(())
}
}}}