1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Common trait definitions related to block context.
//!
//! The consensus layer for this crate works on different levels.
//!
//! On execute level, one uses `ExecuteContext`, and the type parameters defined
//! allows it to be used by an executor -- given a block, and an externalities,
//! it executes the state. This is suitable for plain state transition.
//!
//! On importer level, one uses `ImportContext`. This allows the block to be
//! written into a backend together with auxiliaries. This is suitable for
//! implementing common consensus algorithms.
//!
//! On builder level, one uses `BuildContext`. This allows to be used with
//! `BuilderExecutor` which is able to create new blocks. Used together with
//! `ImportContext`, one can build a proposer.

use std::error as stderror;
use std::hash;

/// A block contains a hash, and reference a parent block via parent hash.
pub trait Block: Clone {
	/// Hash type of the block.
	type Identifier: Copy + Eq + hash::Hash;

	/// Get the block hash.
	fn id(&self) -> Self::Identifier;
	/// Get the parent block hash. None if this block is genesis.
	fn parent_id(&self) -> Option<Self::Identifier>;
}

/// A value where the key is contained in.
pub trait Auxiliary<B: Block>: Clone {
	/// Key type
	type Key: Copy + Eq + hash::Hash;

	/// Return the key of this object.
	fn key(&self) -> Self::Key;
	/// Return block ids associated with this auxiliary. If the backend
	/// removes any of the blocks listed here, it is expected to remove
	/// this auxiliary entry, and trigger a recalculation for the
	/// consensus engine.
	fn associated(&self) -> Vec<B::Identifier> {
		Vec::new()
	}
}

impl<B: Block> Auxiliary<B> for () {
	type Key = ();

	fn key(&self) -> () { () }
}

/// Trait that allows conversion into externalities.
pub trait AsExternalities<E: ?Sized> {
	/// Turn this object into externalities.
	fn as_externalities(&mut self) -> &mut E;
}

/// Null externalities.
pub trait NullExternalities { }

/// Externalities for reading a key value based storage.
pub trait StorageExternalities<Error> {
	/// Read storage value.
	fn read_storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error>;
	/// Write storage value.
	fn write_storage(&mut self, key: Vec<u8>, value: Vec<u8>);
	/// Remove storage value.
	fn remove_storage(&mut self, key: &[u8]);
}

/// Import operation.
pub struct ImportOperation<B, S> {
	/// Block to be imported.
	pub block: B,
	/// Associated state of the block.
	pub state: S,
}

/// Operation for a backend.
pub struct Operation<B: Block, S, A: Auxiliary<B>> {
	/// Import operation.
	pub import_block: Vec<ImportOperation<B, S>>,
	/// Set head operation.
	pub set_head: Option<B::Identifier>,
	/// Auxiliaries insertion operation.
	pub insert_auxiliaries: Vec<A>,
	/// Auxiliaries removal operation.
	pub remove_auxiliaries: Vec<A::Key>,
}

impl<B: Block, S, A: Auxiliary<B>> Default for Operation<B, S, A> {
	fn default() -> Self {
		Self {
			import_block: Vec::new(),
			set_head: None,
			insert_auxiliaries: Vec::new(),
			remove_auxiliaries: Vec::new(),
		}
	}
}

/// Commit-able backend for a block context.
pub trait Backend {
	/// Block type
	type Block: Block;
	/// State type
	type State;
	/// Auxiliary type
	type Auxiliary: Auxiliary<Self::Block>;
	/// Error type
	type Error: stderror::Error + 'static;

	/// Commit operation.
	fn commit(
		&mut self,
		operation: Operation<Self::Block, Self::State, Self::Auxiliary>,
	) -> Result<(), Self::Error>;
}

/// Chain query interface for a backend.
pub trait ChainQuery: Backend {
	/// Get the genesis hash of the chain.
	fn genesis(&self) -> <Self::Block as Block>::Identifier;
	/// Get the head of the chain.
	fn head(&self) -> <Self::Block as Block>::Identifier;

	/// Check whether a hash is contained in the chain.
	fn contains(
		&self,
		hash: &<Self::Block as Block>::Identifier,
	) -> Result<bool, Self::Error>;

	/// Check whether a block is canonical.
	fn is_canon(
		&self,
		hash: &<Self::Block as Block>::Identifier,
	) -> Result<bool, Self::Error>;

	/// Look up a canonical block via its depth.
	fn lookup_canon_depth(
		&self,
		depth: usize,
	) -> Result<Option<<Self::Block as Block>::Identifier>, Self::Error>;

	/// Get the auxiliary value by key.
	fn auxiliary(
		&self,
		key: &<Self::Auxiliary as Auxiliary<Self::Block>>::Key,
	) -> Result<Option<Self::Auxiliary>, Self::Error>;

	/// Get the depth of a block.
	fn depth_at(
		&self,
		hash: &<Self::Block as Block>::Identifier,
	) -> Result<usize, Self::Error>;

	/// Get children of a block.
	fn children_at(
		&self,
		hash: &<Self::Block as Block>::Identifier,
	) -> Result<Vec<<Self::Block as Block>::Identifier>, Self::Error>;

	/// Get the state object of a block.
	fn state_at(
		&self,
		hash: &<Self::Block as Block>::Identifier,
	) -> Result<Self::State, Self::Error>;

	/// Get the object of a block.
	fn block_at(
		&self,
		hash: &<Self::Block as Block>::Identifier,
	) -> Result<Self::Block, Self::Error>;
}

/// Trait used for committing block, usually built on top of a backend.
pub trait ImportBlock {
	/// Block type
	type Block: Block;
	/// Error type
	type Error: stderror::Error + 'static;

	/// Commit a block into the backend, and handle consensus and auxiliary.
	fn import_block(&mut self, block: Self::Block) -> Result<(), Self::Error>;
}

/// Block executor
pub trait BlockExecutor {
	/// Error type
	type Error: stderror::Error + 'static;
	/// Block type
	type Block: Block;
	/// Externalities type
	type Externalities: ?Sized;

	/// Execute the block via a block object and given state.
	fn execute_block(
		&self,
		block: &Self::Block,
		state: &mut Self::Externalities
	) -> Result<(), Self::Error>;
}

/// Builder executor
pub trait BuilderExecutor {
	/// Error type
	type Error: stderror::Error + 'static;
	/// Block type
	type Block: Block;
	/// Build block type
	type BuildBlock;
	/// Externalities type
	type Externalities: ?Sized;
	/// Inherent
	type Inherent;
	/// Extrinsic
	type Extrinsic;

	/// Initialize a block from the parent block, and given state.
	fn initialize_block(
		&self,
		parent_block: &Self::Block,
		state: &mut Self::Externalities,
		inherent: Self::Inherent,
	) -> Result<Self::BuildBlock, Self::Error>;

	/// Apply extrinsic to a given block.
	fn apply_extrinsic(
		&self,
		block: &mut Self::BuildBlock,
		extrinsic: Self::Extrinsic,
		state: &mut Self::Externalities,
	) -> Result<(), Self::Error>;

	/// Finalize a block.
	fn finalize_block(
		&self,
		block: &mut Self::BuildBlock,
		state: &mut Self::Externalities,
	) -> Result<(), Self::Error>;
}