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
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of Tetsy Vapory.

// Tetsy Vapory 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.

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

//! Types pertaining to sending messages and finding routes through the chain. Used mostly by the
//! ChainNotify trait.

use bytes::Bytes;
use vapory_types::H256;
use crate::{
	import_route::ImportRoute,
};
use std::time::Duration;
use std::collections::HashMap;

/// Messages to broadcast via chain
pub enum ChainMessageType {
	/// Consensus message
	Consensus(Vec<u8>),
	/// Message with private transaction
	PrivateTransaction(H256, Vec<u8>),
	/// Message with signed private transaction
	SignedPrivateTransaction(H256, Vec<u8>),
	/// Private state request for the particular private contract
	PrivateStateRequest(H256),
}

/// Route type to indicate whether it is enacted or retracted.
#[derive(Clone)]
pub enum ChainRouteType {
	/// Enacted block
	Enacted,
	/// Retracted block
	Retracted
}

/// A complete chain enacted retracted route.
#[derive(Default, Clone)]
pub struct ChainRoute {
	route: Vec<(H256, ChainRouteType)>,
	enacted: Vec<H256>,
	retracted: Vec<H256>,
}

impl<'a> From<&'a [ImportRoute]> for ChainRoute {
	fn from(import_results: &'a [ImportRoute]) -> ChainRoute {
		ChainRoute::new(import_results.iter().flat_map(|route| {
			route.retracted.iter().map(|h| (*h, ChainRouteType::Retracted))
				.chain(route.enacted.iter().map(|h| (*h, ChainRouteType::Enacted)))
		}).collect())
	}
}

impl ChainRoute {
	/// Create a new ChainRoute based on block hash and route type pairs.
	pub fn new(route: Vec<(H256, ChainRouteType)>) -> Self {
		let (enacted, retracted) = Self::to_enacted_retracted(&route);

		Self { route, enacted, retracted }
	}

	/// Gather all non-duplicate enacted and retracted blocks.
	fn to_enacted_retracted(route: &[(H256, ChainRouteType)]) -> (Vec<H256>, Vec<H256>) {
		fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
			map.into_iter().map(|(k, _v)| k).collect()
		}

		// Because we are doing multiple inserts some of the blocks that were enacted in import `k`
		// could be retracted in import `k+1`. This is why to understand if after all inserts
		// the block is enacted or retracted we iterate over all routes and at the end final state
		// will be in the hashmap
		let map = route.iter().fold(HashMap::new(), |mut map, route| {
			match &route.1 {
				&ChainRouteType::Enacted => {
					map.insert(route.0, true);
				},
				&ChainRouteType::Retracted => {
					map.insert(route.0, false);
				},
			}
			map
		});

		// Split to enacted retracted (using hashmap value)
		let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v);
		// And convert tuples to keys
		(map_to_vec(enacted), map_to_vec(retracted))
	}

	/// Consume route and return the enacted retracted form.
	pub fn into_enacted_retracted(self) -> (Vec<H256>, Vec<H256>) {
		(self.enacted, self.retracted)
	}

	/// All non-duplicate enacted blocks.
	pub fn enacted(&self) -> &[H256] {
		&self.enacted
	}

	/// All non-duplicate retracted blocks.
	pub fn retracted(&self) -> &[H256] {
		&self.retracted
	}

	/// All blocks in the route.
	pub fn route(&self) -> &[(H256, ChainRouteType)] {
		&self.route
	}
}

/// Used by `ChainNotify` `new_blocks()` and contains information about new blocks imported to the
/// chain.
pub struct NewBlocks {
	/// Imported blocks
	pub imported: Vec<H256>,
	/// Invalid blocks
	pub invalid: Vec<H256>,
	/// Route
	pub route: ChainRoute,
	/// Sealed
	pub sealed: Vec<H256>,
	/// Block bytes.
	pub proposed: Vec<Bytes>,
	/// Duration
	pub duration: Duration,
	/// Has more blocks to import
	pub has_more_blocks_to_import: bool,
}

impl NewBlocks {
	/// Constructor
	pub fn new(
		imported: Vec<H256>,
		invalid: Vec<H256>,
		route: ChainRoute,
		sealed: Vec<H256>,
		proposed: Vec<Bytes>,
		duration: Duration,
		has_more_blocks_to_import: bool,
	) -> NewBlocks {
		NewBlocks {
			imported,
			invalid,
			route,
			sealed,
			proposed,
			duration,
			has_more_blocks_to_import,
		}
	}
}