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
#![forbid(unsafe_code)]
use crate::execution_strategies::types::{Block, Executor, ExecutorResult};
use diem_types::transaction::TransactionOutput;
use std::{collections::BTreeMap, error::Error, fmt};
#[derive(Debug)]
pub enum MultiResult<E: Error> {
NonMatchingOutput(TransactionOutput, TransactionOutput),
OtherResult(E),
}
impl<E: Error> std::fmt::Display for MultiResult<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MultiResult::OtherResult(err) => std::fmt::Display::fmt(&err, f),
MultiResult::NonMatchingOutput(output1, output2) => {
write!(f, "{:?} != {:?}", output1, output2)
}
}
}
}
impl<E: Error> Error for MultiResult<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
MultiResult::OtherResult(err) => err.source(),
MultiResult::NonMatchingOutput(_output1, _output2) => None,
}
}
}
pub struct MultiExecutor<TxnType, E: Error> {
executors: Vec<Box<dyn Executor<Txn = TxnType, BlockResult = E>>>,
}
impl<TxnType, E: Error> Default for MultiExecutor<TxnType, E> {
fn default() -> Self {
Self::new()
}
}
impl<TxnType, E: Error> MultiExecutor<TxnType, E> {
pub fn new() -> Self {
Self {
executors: Vec::new(),
}
}
pub fn add_executor(
&mut self,
executor: impl Executor<Txn = TxnType, BlockResult = E> + 'static,
) {
self.executors.push(Box::new(executor))
}
}
impl<TxnType: Clone, E: Error> Executor for MultiExecutor<TxnType, E> {
type BlockResult = MultiResult<E>;
type Txn = TxnType;
fn execute_block(&mut self, block: Block<Self::Txn>) -> ExecutorResult<Self::BlockResult> {
let mut results = BTreeMap::new();
for executor in self.executors.iter_mut() {
let block = match executor.execute_block(block.clone()) {
Err(err) => return Err(MultiResult::OtherResult(err)),
Ok(block) => block,
};
for (index, output) in block.into_iter().enumerate() {
match results.get(&index) {
None => {
results.insert(index, output);
}
Some(previous_output) => {
if &output != previous_output {
return Err(MultiResult::NonMatchingOutput(
output,
previous_output.clone(),
));
}
}
}
}
}
Ok(results.into_iter().map(|(_, v)| v).collect())
}
}