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
// Copyright (c) 2022 MASSA LABS <info@massa.net>

//! This module exports generic traits representing interfaces for interacting with the Execution worker

use crate::types::{
    ExecutionBlockMetadata, ExecutionQueryRequest, ExecutionQueryResponse, ReadOnlyExecutionRequest,
};

use crate::ExecutionError;
use crate::{ExecutionAddressInfo, ReadOnlyExecutionOutput};
use massa_models::address::Address;
use massa_models::amount::Amount;
use massa_models::block_id::BlockId;
use massa_models::denunciation::DenunciationIndex;
use massa_models::execution::EventFilter;
use massa_models::operation::OperationId;
use massa_models::output_event::SCOutputEvent;
use massa_models::prehash::PreHashMap;
use massa_models::slot::Slot;
use massa_models::stats::ExecutionStats;
use std::collections::BTreeMap;
use std::collections::HashMap;

#[cfg(feature = "execution-trace")]
use crate::types_trace_info::{AbiTrace, SlotAbiCallStack, Transfer};

#[cfg_attr(feature = "test-exports", mockall::automock)]
/// interface that communicates with the execution worker thread
pub trait ExecutionController: Send + Sync {
    /// Updates blockclique status by signaling newly finalized blocks and the latest blockclique.
    ///
    /// # Arguments
    /// * `finalized_blocks`: newly finalized blocks indexed by slot.
    /// * `blockclique`: new blockclique (if changed). Indexed by slot.
    /// * `block_metadata`: storage instances and metadata for new blocks. Each storage owns refs to the block and its ops/endorsements.
    fn update_blockclique_status(
        &self,
        finalized_blocks: HashMap<Slot, BlockId>,
        new_blockclique: Option<HashMap<Slot, BlockId>>,
        block_metadata: PreHashMap<BlockId, ExecutionBlockMetadata>,
    );

    /// Atomically query the execution state with multiple requests
    fn query_state(&self, req: ExecutionQueryRequest) -> ExecutionQueryResponse;

    /// Get execution events optionally filtered by:
    /// * start slot
    /// * end slot
    /// * emitter address
    /// * original caller address
    /// * operation id
    fn get_filtered_sc_output_event(&self, filter: EventFilter) -> Vec<SCOutputEvent>;

    /// Get the final and active values of balance.
    ///
    /// # Return value
    /// * `(final_balance, active_balance)`
    fn get_final_and_candidate_balance(
        &self,
        addresses: &[Address],
    ) -> Vec<(Option<Amount>, Option<Amount>)>;

    /// Get the execution status of a batch of operations.
    ///
    ///  Return value: vector of
    ///  `(Option<speculative_status>, Option<final_status>)`
    ///  If an Option is None it means that the op execution was not found.
    ///  Note that old op executions are forgotten.
    /// Otherwise, the status is a boolean indicating whether the execution was successful (true) or if there was an error (false.)
    fn get_ops_exec_status(&self, batch: &[OperationId]) -> Vec<(Option<bool>, Option<bool>)>;

    /// Get a copy of a single datastore entry with its final and active values
    ///
    /// # Return value
    /// * `(final_data_entry, active_data_entry)`
    #[allow(clippy::type_complexity)]
    fn get_final_and_active_data_entry(
        &self,
        input: Vec<(Address, Vec<u8>)>,
    ) -> Vec<(Option<Vec<u8>>, Option<Vec<u8>>)>;

    /// Returns for a given cycle the stakers taken into account
    /// by the selector. That correspond to the `roll_counts` in `cycle - 3`.
    ///
    /// By default it returns an empty map.
    fn get_cycle_active_rolls(&self, cycle: u64) -> BTreeMap<Address, u64>;

    /// Execute read-only SC function call without causing modifications to the consensus state
    ///
    /// # arguments
    /// * `req`: an instance of `ReadOnlyCallRequest` describing the parameters of the execution
    ///
    /// # returns
    /// An instance of `ExecutionOutput` containing a summary of the effects of the execution,
    /// or an error if the execution failed.
    fn execute_readonly_request(
        &self,
        req: ReadOnlyExecutionRequest,
    ) -> Result<ReadOnlyExecutionOutput, ExecutionError>;

    /// Check if a denunciation has been executed given a `DenunciationIndex`
    /// (speculative, final)
    fn get_denunciation_execution_status(
        &self,
        denunciation_index: &DenunciationIndex,
    ) -> (bool, bool);

    /// Gets information about a batch of addresses
    fn get_addresses_infos(
        &self,
        addresses: &[Address],
        deferred_credits_max_slot: std::ops::Bound<Slot>,
    ) -> Vec<ExecutionAddressInfo>;

    /// Get execution statistics
    fn get_stats(&self) -> ExecutionStats;

    #[cfg(feature = "execution-trace")]
    /// Get the abi call stack for a given operation id
    fn get_operation_abi_call_stack(&self, operation_id: OperationId) -> Option<Vec<AbiTrace>>;

    #[cfg(feature = "execution-trace")]
    /// Get the abi call stack for a given slot
    fn get_slot_abi_call_stack(&self, slot: Slot) -> Option<SlotAbiCallStack>;

    #[cfg(feature = "execution-trace")]
    /// Get the all transfers of MAS for a given slot
    fn get_transfers_for_slot(&self, slot: Slot) -> Option<Vec<Transfer>>;

    #[cfg(feature = "execution-trace")]
    /// Get the transfer of MAS for a given operation id
    fn get_transfer_for_op(&self, op_id: &OperationId) -> Option<Transfer>;

    /// Returns a boxed clone of self.
    /// Useful to allow cloning `Box<dyn ExecutionController>`.
    fn clone_box(&self) -> Box<dyn ExecutionController>;
}

/// Allow cloning `Box<dyn ExecutionController>`
/// Uses `ExecutionController::clone_box` internally
impl Clone for Box<dyn ExecutionController> {
    fn clone(&self) -> Box<dyn ExecutionController> {
        self.clone_box()
    }
}

/// Execution manager used to stop the execution thread
pub trait ExecutionManager {
    /// Stop the execution thread
    /// Note that we do not take self by value to consume it
    /// because it is not allowed to move out of `Box<dyn ExecutionManager>`
    /// This will improve if the `unsized_fn_params` feature stabilizes enough to be safely usable.
    fn stop(&mut self);
}