full.rs 9.42 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Copyright 2017 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/>.

//! Strongly typed API for full Polkadot client.

use client::backend::{Backend, LocalBackend};
Gav Wood's avatar
Gav Wood committed
20
21
use client::block_builder::BlockBuilder as ClientBlockBuilder;
use client::{Client, LocalCallExecutor};
22
23
use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::{NativeExecutionDispatch, NativeExecutor};
Gav Wood's avatar
Gav Wood committed
24
use state_machine;
25

Gav Wood's avatar
Gav Wood committed
26
27
use runtime::Address;
use runtime_primitives::traits::AuxLookup;
Gav Wood's avatar
Gav Wood committed
28
29
use primitives::{AccountId, Block, Header, BlockId, Hash, Index, SessionKey, Timestamp, UncheckedExtrinsic};
use primitives::parachain::{CandidateReceipt, DutyRoster, Id as ParaId};
30
31
32
33
34

use {CheckedBlockId, BlockBuilder, PolkadotApi, LocalPolkadotApi, ErrorKind, Error, Result};

/// A checked block ID used for the substrate-client implementation of CheckedBlockId;
#[derive(Debug, Clone, Copy)]
Gav Wood's avatar
Gav Wood committed
35
pub struct CheckedId(pub(crate) BlockId);
36
37
38
39
40
41
42
43
44
45
46
47
48

impl CheckedBlockId for CheckedId {
	fn block_id(&self) -> &BlockId {
		&self.0
	}
}

// set up the necessary scaffolding to execute a set of calls to the runtime.
// this creates a new block on top of the given ID and initialises it.
macro_rules! with_runtime {
	($client: ident, $at: expr, $exec: expr) => {{
		let parent = $at.block_id();
		let header = Header {
Gav Wood's avatar
Gav Wood committed
49
50
51
52
			parent_hash: $client.block_hash_from_id(&parent)?
				.ok_or_else(|| ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
			number: $client.block_number_from_id(&parent)?
				.ok_or_else(|| ErrorKind::UnknownBlock(format!("{:?}", parent)))? + 1,
53
54
55
56
57
			state_root: Default::default(),
			extrinsics_root: Default::default(),
			digest: Default::default(),
		};

Gav Wood's avatar
Gav Wood committed
58
		$client.state_at(&parent).map_err(Error::from).and_then(|state| {
59
60
61
62
63
64
65
66
67
68
69
			let mut changes = Default::default();
			let mut ext = state_machine::Ext::new(&mut changes, &state);

			::substrate_executor::with_native_environment(&mut ext, || {
				::runtime::Executive::initialise_block(&header);
				($exec)()
			}).map_err(Into::into)
		})
	}}
}

Gav Wood's avatar
Gav Wood committed
70
71
impl<B: LocalBackend<Block>> BlockBuilder for ClientBlockBuilder<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block>
	where ::client::error::Error: From<<<B as Backend<Block>>::State as state_machine::backend::Backend>::Error>
72
73
{
	fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
Gav Wood's avatar
Gav Wood committed
74
		self.push(extrinsic).map_err(Into::into)
75
76
	}

Gav Wood's avatar
Gav Wood committed
77
78
79
	/// Bake the block with provided extrinsics.
	fn bake(self) -> Result<Block> {
		ClientBlockBuilder::bake(self).map_err(Into::into)
80
81
82
	}
}

Gav Wood's avatar
Gav Wood committed
83
84
impl<B: LocalBackend<Block>> PolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block>
	where ::client::error::Error: From<<<B as Backend<Block>>::State as state_machine::backend::Backend>::Error>
85
86
{
	type CheckedBlockId = CheckedId;
Gav Wood's avatar
Gav Wood committed
87
	type BlockBuilder = ClientBlockBuilder<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block>;
88
89
90

	fn check_id(&self, id: BlockId) -> Result<CheckedId> {
		// bail if the code is not the same as the natively linked.
Gav Wood's avatar
Gav Wood committed
91
		if self.code_at(&id.into())? != LocalDispatch::native_equivalent() {
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
			bail!("This node is out of date. Block authoring may not work correctly. Bailing.")
		}

		Ok(CheckedId(id))
	}

	fn session_keys(&self, at: &CheckedId) -> Result<Vec<SessionKey>> {
		with_runtime!(self, at, ::runtime::Consensus::authorities)
	}

	fn validators(&self, at: &CheckedId) -> Result<Vec<AccountId>> {
		with_runtime!(self, at, ::runtime::Session::validators)
	}

	fn random_seed(&self, at: &CheckedId) -> Result<Hash> {
		with_runtime!(self, at, ::runtime::System::random_seed)
	}

	fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> {
		with_runtime!(self, at, ::runtime::Parachains::calculate_duty_roster)
	}

	fn timestamp(&self, at: &CheckedId) -> Result<Timestamp> {
115
		with_runtime!(self, at, ::runtime::Timestamp::get)
116
117
118
119
	}

	fn evaluate_block(&self, at: &CheckedId, block: Block) -> Result<bool> {
		use substrate_executor::error::ErrorKind as ExecErrorKind;
Gav Wood's avatar
Gav Wood committed
120
121
122
123
124
125
126
127
		use codec::Slicable;
		use runtime::Block as RuntimeBlock;

		let encoded = block.encode();
		let runtime_block = match RuntimeBlock::decode(&mut &encoded[..]) {
			Some(x) => x,
			None => return Ok(false),
		};
128

Gav Wood's avatar
Gav Wood committed
129
		let res = with_runtime!(self, at, || ::runtime::Executive::execute_block(runtime_block));
130
131
132
133
134
135
136
137
138
139
		match res {
			Ok(()) => Ok(true),
			Err(err) => match err.kind() {
				&ErrorKind::Executor(ExecErrorKind::Runtime) => Ok(false),
				_ => Err(err)
			}
		}
	}

	fn index(&self, at: &CheckedId, account: AccountId) -> Result<Index> {
Gav Wood's avatar
Gav Wood committed
140
141
142
143
144
		with_runtime!(self, at, || ::runtime::System::account_nonce(account))
	}

	fn lookup(&self, at: &Self::CheckedBlockId, address: Address) -> Result<Option<AccountId>> {
		with_runtime!(self, at, || <::runtime::Staking as AuxLookup>::lookup(address).ok())
145
146
147
148
149
150
151
152
153
154
155
156
157
158
	}

	fn active_parachains(&self, at: &CheckedId) -> Result<Vec<ParaId>> {
		with_runtime!(self, at, ::runtime::Parachains::active_parachains)
	}

	fn parachain_code(&self, at: &CheckedId, parachain: ParaId) -> Result<Option<Vec<u8>>> {
		with_runtime!(self, at, || ::runtime::Parachains::parachain_code(parachain))
	}

	fn parachain_head(&self, at: &CheckedId, parachain: ParaId) -> Result<Option<Vec<u8>>> {
		with_runtime!(self, at, || ::runtime::Parachains::parachain_head(parachain))
	}

Gav Wood's avatar
Gav Wood committed
159
160
161
162
163
	fn build_block(&self, at: &CheckedId, timestamp: Timestamp, new_heads: Vec<CandidateReceipt>) -> Result<Self::BlockBuilder> {
		let mut block_builder = self.new_block_at(at.block_id())?;
		for inherent in self.inherent_extrinsics(at, timestamp, new_heads)? {
			block_builder.push(inherent)?;
		}
164

Gav Wood's avatar
Gav Wood committed
165
166
		Ok(block_builder)
	}
167

Gav Wood's avatar
Gav Wood committed
168
169
	fn inherent_extrinsics(&self, at: &Self::CheckedBlockId, timestamp: Timestamp, new_heads: Vec<CandidateReceipt>) -> Result<Vec<UncheckedExtrinsic>> {
		use codec::Slicable;
170

Gav Wood's avatar
Gav Wood committed
171
172
173
174
175
176
177
178
		with_runtime!(self, at, || {
			let extrinsics = ::runtime::inherent_extrinsics(timestamp, new_heads);
			extrinsics.into_iter()
				.map(|x| x.encode()) // get encoded representation
				.map(|x| Slicable::decode(&mut &x[..])) // get byte-vec equivalent to extrinsic
				.map(|x| x.expect("UncheckedExtrinsic has encoded representation equivalent to Vec<u8>; qed"))
				.collect()
		})
179
180
181
	}
}

Gav Wood's avatar
Gav Wood committed
182
183
impl<B: LocalBackend<Block>> LocalPolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block>
	where ::client::error::Error: From<<<B as Backend<Block>>::State as state_machine::backend::Backend>::Error>
184
185
186
187
188
189
{}

#[cfg(test)]
mod tests {
	use super::*;
	use keyring::Keyring;
Gav Wood's avatar
Gav Wood committed
190
	use client::LocalCallExecutor;
191
192
	use client::in_mem::Backend as InMemory;
	use substrate_executor::NativeExecutionDispatch;
193
	use runtime::{GenesisConfig, ConsensusConfig, SessionConfig};
194
195

	fn validators() -> Vec<AccountId> {
Gav Wood's avatar
Gav Wood committed
196
197
198
199
200
201
202
		vec![
			Keyring::One.to_raw_public().into(),
			Keyring::Two.to_raw_public().into(),
		]
	}

	fn session_keys() -> Vec<SessionKey> {
203
		vec![
204
205
			Keyring::One.to_raw_public().into(),
			Keyring::Two.to_raw_public().into(),
206
207
208
		]
	}

Gav Wood's avatar
Gav Wood committed
209
	fn client() -> Client<InMemory<Block>, LocalCallExecutor<InMemory<Block>, NativeExecutor<LocalDispatch>>, Block> {
Gav Wood's avatar
Gav Wood committed
210
211
212
213
214
215
216
217
218
		let genesis_config = GenesisConfig {
			consensus: Some(ConsensusConfig {
				code: LocalDispatch::native_equivalent().to_vec(),
				authorities: session_keys(),
			}),
			system: None,
			session: Some(SessionConfig {
				validators: validators(),
				session_length: 100,
219
				broken_percent_late: 100,
Gav Wood's avatar
Gav Wood committed
220
221
222
223
224
			}),
			council: Some(Default::default()),
			democracy: Some(Default::default()),
			parachains: Some(Default::default()),
			staking: Some(Default::default()),
225
			timestamp: Some(Default::default()),
Gav Wood's avatar
Gav Wood committed
226
		};
227

228
		::client::new_in_mem(LocalDispatch::new(), genesis_config).unwrap()
229
230
231
232
233
	}

	#[test]
	fn gets_session_and_validator_keys() {
		let client = client();
Gav Wood's avatar
Gav Wood committed
234
235
		let id = client.check_id(BlockId::number(0)).unwrap();
		assert_eq!(client.session_keys(&id).unwrap(), session_keys());
236
237
238
239
		assert_eq!(client.validators(&id).unwrap(), validators());
	}

	#[test]
Gav Wood's avatar
Gav Wood committed
240
	fn build_block_implicit_succeeds() {
241
242
		let client = client();

Gav Wood's avatar
Gav Wood committed
243
		let id = client.check_id(BlockId::number(0)).unwrap();
244
		let block_builder = client.build_block(&id, 1_000_000, Vec::new()).unwrap();
Gav Wood's avatar
Gav Wood committed
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
		let block = block_builder.bake().unwrap();

		assert_eq!(block.header.number, 1);
		assert!(block.header.extrinsics_root != Default::default());
	}

	#[test]
	fn build_block_with_inherent_succeeds() {
		let client = client();

		let id = client.check_id(BlockId::number(0)).unwrap();
		let inherent = client.inherent_extrinsics(&id, 1_000_000, Vec::new()).unwrap();

		let mut block_builder = client.new_block_at(id.block_id()).unwrap();
		for extrinsic in inherent {
			block_builder.push(extrinsic).unwrap();
		}

		let block = block_builder.bake().unwrap();
264
265
266
267
268
269
270

		assert_eq!(block.header.number, 1);
		assert!(block.header.extrinsics_root != Default::default());
	}

	#[test]
	fn fails_to_check_id_for_unknown_block() {
Gav Wood's avatar
Gav Wood committed
271
		assert!(client().check_id(BlockId::number(100)).is_err());
272
273
274
275
276
277
	}

	#[test]
	fn gets_random_seed_with_genesis() {
		let client = client();

Gav Wood's avatar
Gav Wood committed
278
		let id = client.check_id(BlockId::number(0)).unwrap();
279
280
281
		assert!(client.random_seed(&id).is_ok());
	}
}