dry_run.rs 5.61 KB
Newer Older
Kian Paimani's avatar
Kian Paimani committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.

//! The dry-run command.

use crate::{
	params, prelude::*, rpc_helpers::*, signer::Signer, DryRunConfig, Error, SharedConfig, WsClient,
};
use codec::Encode;
23
use frame_support::traits::Currency;
Kian Paimani's avatar
Kian Paimani committed
24
25

/// Forcefully create the snapshot. This can be used to compute the election at anytime.
26
fn force_create_snapshot<T: EPM::Config>(ext: &mut Ext) -> Result<(), Error<T>> {
Kian Paimani's avatar
Kian Paimani committed
27
28
29
30
31
32
33
34
35
36
37
38
	ext.execute_with(|| {
		if <EPM::Snapshot<T>>::exists() {
			log::info!(target: LOG_TARGET, "snapshot already exists.");
			Ok(())
		} else {
			log::info!(target: LOG_TARGET, "creating a fake snapshot now.");
			<EPM::Pallet<T>>::create_snapshot().map(|_| ()).map_err(Into::into)
		}
	})
}

/// Helper method to print the encoded size of the snapshot.
39
40
41
42
43
44
45
46
async fn print_info<T: EPM::Config>(
	client: &WsClient,
	ext: &mut Ext,
	raw_solution: &EPM::RawSolution<EPM::SolutionOf<T>>,
	extrinsic: sp_core::Bytes,
) where
	<T as EPM::Config>::Currency: Currency<T::AccountId, Balance = Balance>,
{
Kian Paimani's avatar
Kian Paimani committed
47
48
49
	ext.execute_with(|| {
		log::info!(
			target: LOG_TARGET,
50
51
52
53
54
55
			"Snapshot Metadata: {:?}",
			<EPM::Pallet<T>>::snapshot_metadata()
		);
		log::info!(
			target: LOG_TARGET,
			"Snapshot Encoded Length: {:?}",
Kian Paimani's avatar
Kian Paimani committed
56
57
58
59
60
			<EPM::Pallet<T>>::snapshot()
				.expect("snapshot must exist before calling `measure_snapshot_size`")
				.encode()
				.len()
		);
61
62
63

		let snapshot_size =
			<EPM::Pallet<T>>::snapshot_metadata().expect("snapshot must exist by now; qed.");
64
		let deposit = EPM::Pallet::<T>::deposit_for(raw_solution, snapshot_size);
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
		log::info!(
			target: LOG_TARGET,
			"solution score {:?} / deposit {:?} / length {:?}",
			&raw_solution.score.iter().map(|x| Token::from(*x)).collect::<Vec<_>>(),
			Token::from(deposit),
			raw_solution.encode().len(),
		);
	});

	let info = rpc::<pallet_transaction_payment::RuntimeDispatchInfo<Balance>>(
		client,
		"payment_queryInfo",
		params! { extrinsic },
	)
	.await;
	log::info!(
		target: LOG_TARGET,
		"payment_queryInfo: (fee = {}) {:?}",
83
84
85
		info.as_ref()
			.map(|d| Token::from(d.partial_fee))
			.unwrap_or_else(|_| Token::from(0)),
86
87
		info,
	);
Kian Paimani's avatar
Kian Paimani committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
}

/// Find the stake threshold in order to have at most `count` voters.
#[allow(unused)]
fn find_threshold<T: EPM::Config>(ext: &mut Ext, count: usize) {
	ext.execute_with(|| {
		let mut voters = <EPM::Pallet<T>>::snapshot()
			.expect("snapshot must exist before calling `measure_snapshot_size`")
			.voters;
		voters.sort_by_key(|(_voter, weight, _targets)| std::cmp::Reverse(*weight));
		match voters.get(count) {
			Some(threshold_voter) => println!("smallest allowed voter is {:?}", threshold_voter),
			None => {
				println!("requested truncation to {} voters but had only {}", count, voters.len());
				println!("smallest current voter: {:?}", voters.last());
Shawn Tabrizi's avatar
Shawn Tabrizi committed
103
			},
Kian Paimani's avatar
Kian Paimani committed
104
105
106
107
108
109
110
111
112
113
114
		}
	})
}

macro_rules! dry_run_cmd_for { ($runtime:ident) => { paste::paste! {
	/// Execute the dry-run command.
	pub(crate) async fn [<dry_run_cmd_ $runtime>](
		client: &WsClient,
		shared: SharedConfig,
		config: DryRunConfig,
		signer: Signer,
115
	) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> {
Kian Paimani's avatar
Kian Paimani committed
116
		use $crate::[<$runtime _runtime_exports>]::*;
117
118
119
		let mut ext = crate::create_election_ext::<Runtime, Block>(
			shared.uri.clone(),
			config.at,
120
			vec!["Staking".to_string(), "System".to_string()],
121
		).await?;
Kian Paimani's avatar
Kian Paimani committed
122
123
		force_create_snapshot::<Runtime>(&mut ext)?;

124
		let (raw_solution, witness) = crate::mine_with::<Runtime>(&config.solver, &mut ext, false)?;
125

Kian Paimani's avatar
Kian Paimani committed
126
127
128
129
		let nonce = crate::get_account_info::<Runtime>(client, &signer.account, config.at)
			.await?
			.map(|i| i.nonce)
			.expect("signer account is checked to exist upon startup; it can only die if it \
130
131
132
			transfers funds out of it, or get slashed. If it does not exist at this point, \
			it is likely due to a bug, or the signer got slashed. Terminating."
		);
Kian Paimani's avatar
Kian Paimani committed
133
134
		let tip = 0 as Balance;
		let era = sp_runtime::generic::Era::Immortal;
135
		let extrinsic = ext.execute_with(|| create_uxt(raw_solution.clone(), witness, signer.clone(), nonce, tip, era));
Kian Paimani's avatar
Kian Paimani committed
136
137

		let bytes = sp_core::Bytes(extrinsic.encode().to_vec());
138
139
140
141
142
143
144
145
146
147
148
149
150
151
		print_info::<Runtime>(client, &mut ext, &raw_solution, bytes.clone()).await;

		let feasibility_result = ext.execute_with(|| {
			EPM::Pallet::<Runtime>::feasibility_check(raw_solution.clone(), EPM::ElectionCompute::Signed)
		});
		log::info!(target: LOG_TARGET, "feasibility result is {:?}", feasibility_result.map(|_| ()));

		let dispatch_result = ext.execute_with(|| {
			// manually tweak the phase.
			EPM::CurrentPhase::<Runtime>::put(EPM::Phase::Signed);
			EPM::Pallet::<Runtime>::submit(frame_system::RawOrigin::Signed(signer.account).into(), Box::new(raw_solution), witness)
		});
		log::info!(target: LOG_TARGET, "dispatch result is {:?}", dispatch_result);

152
153
154
		let outcome = rpc_decode::<sp_runtime::ApplyExtrinsicResult>(client, "system_dryRun", params!{ bytes })
			.await
			.map_err::<Error<Runtime>, _>(Into::into)?;
Kian Paimani's avatar
Kian Paimani committed
155
156
157
158
159
160
161
162
		log::info!(target: LOG_TARGET, "dry-run outcome is {:?}", outcome);
		Ok(())
	}
}}}

dry_run_cmd_for!(polkadot);
dry_run_cmd_for!(kusama);
dry_run_cmd_for!(westend);