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
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![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())
    }
}