massa_execution_exports/
types.rs

1// Copyright (c) 2022 MASSA LABS <info@massa.net>
2
3//! This file exports useful types used to interact with the execution worker
4
5use crate::error::ExecutionQueryError;
6use crate::event_store::EventStore;
7use crate::execution_info::{ExecutionInfoForSlot, TransferInfo};
8use massa_deferred_calls::DeferredCall;
9use massa_final_state::StateChanges;
10use massa_hash::Hash;
11use massa_models::block_id::BlockId;
12use massa_models::bytecode::Bytecode;
13use massa_models::datastore::Datastore;
14use massa_models::deferred_calls::DeferredCallId;
15use massa_models::denunciation::DenunciationIndex;
16use massa_models::execution::EventFilter;
17use massa_models::operation::OperationId;
18use massa_models::output_event::SCOutputEvent;
19use massa_models::prehash::PreHashSet;
20use massa_models::{
21    address::Address, address::ExecutionAddressCycleInfo, amount::Amount, slot::Slot,
22};
23use massa_pos_exports::ProductionStats;
24use massa_storage::Storage;
25use serde::Serialize;
26use std::collections::{BTreeMap, BTreeSet};
27use std::ops::Bound;
28
29#[cfg(feature = "execution-trace")]
30use crate::types_trace_info::{SlotAbiCallStack, Transfer};
31
32/// Metadata needed to execute the block
33#[derive(Clone, Debug)]
34pub struct ExecutionBlockMetadata {
35    /// Address of the creator of the parent in the same thread
36    pub same_thread_parent_creator: Option<Address>,
37    /// Storage referencing the block and its contents
38    pub storage: Option<Storage>,
39}
40
41/// Request to atomically execute a batch of execution state queries
42pub struct ExecutionQueryRequest {
43    /// List of requests
44    pub requests: Vec<ExecutionQueryRequestItem>,
45    /// Maximum aggregate size (bytes) of large payload items
46    /// (`Bytecode`, `DatastoreValue`, `Events`, datastore keys)
47    /// allowed in the response. Callers should pass their transport limit
48    /// (e.g. JSON-RPC `max_response_body_size` or gRPC `max_encoding_message_size`).
49    /// Other response variants are treated as zero-cost for this budget.
50    pub max_response_size: usize,
51    /// Event budget for the whole batch: each `Events` item takes
52    /// `min(remaining, per-item cap)` and decrements what it returns; an `Events`
53    /// item past zero gets a per-item `TooLargeResponse` error instead of being
54    /// fetched. `None` means unbounded (explicit opt-out, e.g. tests and empty
55    /// requests — never for transport-facing batches).
56    pub max_event_count: Option<usize>,
57    /// Wall-clock deadline for the whole batch, in milliseconds. Past the
58    /// deadline, remaining items return a per-item `TooLargeResponse` error;
59    /// already-computed items stay valid. `None` means no deadline (explicit
60    /// opt-out, e.g. tests and empty requests — never for transport-facing
61    /// batches). Safety net against lock contention, not the main bound.
62    pub query_state_deadline_ms: Option<u64>,
63}
64
65/// Response to a list of execution queries
66pub struct ExecutionQueryResponse {
67    /// List of responses
68    pub responses: Vec<Result<ExecutionQueryResponseItem, ExecutionQueryError>>,
69    /// Last executed candidate slot
70    pub candidate_cursor: Slot,
71    /// Last executed final slot
72    pub final_cursor: Slot,
73    /// Final state hash
74    pub final_state_fingerprint: Hash,
75}
76
77/// Execution state query item
78pub enum ExecutionQueryRequestItem {
79    /// checks if address exists (candidate) returns ExecutionQueryResponseItem::Boolean(true) if it does
80    AddressExistsCandidate(Address),
81    /// checks if address exists (final) returns ExecutionQueryResponseItem::Boolean(true) if it does
82    AddressExistsFinal(Address),
83    /// gets the balance (candidate) of an address, returns ExecutionQueryResponseItem::Amount(balance) or an error if the address is not found
84    AddressBalanceCandidate(Address),
85    /// gets the balance (final) of an address, returns ExecutionQueryResponseItem::Amount(balance) or an error if the address is not found
86    AddressBalanceFinal(Address),
87    /// gets the bytecode (candidate) of an address, returns ExecutionQueryResponseItem::Bytecode(bytecode) or an error if the address is not found
88    AddressBytecodeCandidate(Address),
89    /// gets the bytecode (final) of an address, returns ExecutionQueryResponseItem::Bytecode(bytecode) or an error if the address is not found
90    AddressBytecodeFinal(Address),
91    /// gets the datastore keys (candidate) of an address, returns ExecutionQueryResponseItem::AddressDatastoreKeys(keys, addr, is_final) or an error if the address is not found
92    AddressDatastoreKeysCandidate {
93        /// Address for which to query the datastore
94        address: Address,
95        /// Filter only entries whose key starts with a prefix
96        prefix: Vec<u8>,
97        /// Bound to start from
98        start_key: Bound<Vec<u8>>,
99        /// End bound
100        end_key: Bound<Vec<u8>>,
101        /// Maximum number of keys to return
102        count: Option<u32>,
103    },
104    /// gets the datastore keys (final) of an address, returns ExecutionQueryResponseItem::AddressDatastoreKeys(keys, addr, is_final) or an error if the address is not found
105    AddressDatastoreKeysFinal {
106        /// Address for which to query the datastore
107        address: Address,
108        /// Filter only entries whose key starts with a prefix
109        prefix: Vec<u8>,
110        /// Bound to start from
111        start_key: Bound<Vec<u8>>,
112        /// End bound
113        end_key: Bound<Vec<u8>>,
114        /// Maximum number of keys to return
115        count: Option<u32>,
116    },
117    /// gets a datastore value (candidate) for an address, returns ExecutionQueryResponseItem::DatastoreValue(keys) or an error if the address or key is not found
118    AddressDatastoreValueCandidate {
119        /// Address for which to query the datastore
120        addr: Address,
121        /// Key of the entry
122        key: Vec<u8>,
123    },
124    /// gets a datastore value (final) for an address, returns ExecutionQueryResponseItem::DatastoreValue(keys) or an error if the address or key is not found
125    AddressDatastoreValueFinal {
126        /// Address for which to query the datastore
127        addr: Address,
128        /// Key of the entry
129        key: Vec<u8>,
130    },
131
132    /// gets the execution status (candidate) for an operation, returns ExecutionQueryResponseItem::ExecutionStatus(status)
133    OpExecutionStatusCandidate(OperationId),
134    /// gets the execution status (final) for an operation, returns ExecutionQueryResponseItem::ExecutionStatus(status)
135    OpExecutionStatusFinal(OperationId),
136
137    /// gets the deferred call quote (candidate) for a slot, returns ExecutionQueryResponseItem::DeferredCallQuote(available, price)
138    DeferredCallQuote {
139        /// slot to query
140        target_slot: Slot,
141        /// gas request
142        max_gas_request: u64,
143        /// params size
144        params_size: u64,
145    },
146    /// get info of deferred calls
147    DeferredCallInfo(DeferredCallId),
148    /// retrieves the deferred call for given slot
149    DeferredCallsBySlot(Slot),
150
151    /// gets the execution status (candidate) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status)
152    DenunciationExecutionStatusCandidate(DenunciationIndex),
153    /// gets the execution status (final) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status)
154    DenunciationExecutionStatusFinal(DenunciationIndex),
155
156    /// gets the roll count (candidate) of an address, returns ExecutionQueryResponseItem::RollCount(rolls) or an error if the address is not found
157    AddressRollsCandidate(Address),
158    /// gets the roll count (final) of an address, returns ExecutionQueryResponseItem::RollCount(rolls) or an error if the address is not found
159    AddressRollsFinal(Address),
160    /// gets the deferred credits (candidate) of an address, returns ExecutionQueryResponseItem::DeferredCredits(deferred_credits) or an error if the address is not found
161    AddressDeferredCreditsCandidate(Address),
162    /// gets the deferred credits (final) of an address, returns ExecutionQueryResponseItem::DeferredCredits(deferred_credits) or an error if the address is not found
163    AddressDeferredCreditsFinal(Address),
164
165    /// get all information for a given cycle, returns ExecutionQueryResponseItem::CycleInfos(cycle_infos) or an error if the cycle is not found
166    CycleInfos {
167        /// cycle to query
168        cycle: u64,
169        /// optionally restrict the query to a set of addresses. If None, the info for all addresses will be returned.
170        restrict_to_addresses: Option<PreHashSet<Address>>,
171    },
172
173    /// get filtered events. Returns ExecutionQueryResponseItem::Events
174    Events(EventFilter),
175}
176
177/// Execution state query response item
178pub enum ExecutionQueryResponseItem {
179    /// boolean value
180    Boolean(bool),
181    /// roll counts value
182    RollCount(u64),
183    /// amount value
184    Amount(Amount),
185    /// bytecode
186    Bytecode(Bytecode),
187    /// datastore value
188    DatastoreValue(Vec<u8>),
189    /// list of keys (keys, address, is_final)
190    AddressDatastoreKeys(BTreeSet<Vec<u8>>, Address, bool),
191    /// deferred call quote (target_slot, gas_request, available, price)
192    DeferredCallQuote(Slot, u64, bool, Amount),
193    /// deferred call info value
194    DeferredCallInfo(DeferredCallId, DeferredCall),
195    /// deferred call slot calls value
196    DeferredCallsBySlot(Slot, Vec<DeferredCallId>),
197    /// deferred credits value
198    DeferredCredits(BTreeMap<Slot, Amount>),
199    /// execution status value
200    ExecutionStatus(ExecutionQueryExecutionStatus),
201    /// cycle infos value
202    CycleInfos(ExecutionQueryCycleInfos),
203    /// Events
204    Events(Vec<SCOutputEvent>),
205}
206
207/// Execution status of an operation or denunciation
208pub enum ExecutionQueryExecutionStatus {
209    /// The operation or denunciation was found as successfully executed in the active history
210    AlreadyExecutedWithSuccess,
211    /// The operation or denunciation was found as executed with errors in the active history
212    AlreadyExecutedWithFailure,
213    /// No information about the operation or denunciation execution were found in the node.
214    /// However the node only keeps execution information until the operation or denunciation expires
215    /// in order to prevent it from being re-executed during its validity time.
216    /// ExecutableOrExpired means that the operation or denunciations was either never executed,
217    /// or was executed previously and ran out of its validify period.
218    /// In other terms, the operation or denunciation can still be executed unless it has expired.
219    ExecutableOrExpired,
220}
221
222/// Information about cycles
223pub struct ExecutionQueryCycleInfos {
224    /// cycle number
225    pub cycle: u64,
226    /// whether the cycle is final
227    pub is_final: bool,
228    /// infos for each PoS-participating address among the ones that were asked
229    pub staker_infos: BTreeMap<Address, ExecutionQueryStakerInfo>,
230}
231
232/// Staker information for a given cycle
233pub struct ExecutionQueryStakerInfo {
234    /// active roll count
235    pub active_rolls: u64,
236    /// production stats
237    pub production_stats: ProductionStats,
238}
239
240/// Execution info about an address
241#[derive(Clone, Debug)]
242pub struct ExecutionAddressInfo {
243    /// candidate balance of the address
244    pub candidate_balance: Amount,
245    /// final balance of the address
246    pub final_balance: Amount,
247
248    /// final number of rolls the address has
249    pub final_roll_count: u64,
250    /// final datastore keys of the address
251    pub final_datastore_keys: BTreeSet<Vec<u8>>,
252
253    /// candidate number of rolls the address has
254    pub candidate_roll_count: u64,
255    /// candidate datastore keys of the address
256    pub candidate_datastore_keys: BTreeSet<Vec<u8>>,
257
258    /// future deferred credits
259    pub future_deferred_credits: BTreeMap<Slot, Amount>,
260
261    /// cycle information
262    pub cycle_infos: Vec<ExecutionAddressCycleInfo>,
263}
264
265/// structure describing the output of the execution of a slot
266#[derive(Debug, Clone)]
267pub enum SlotExecutionOutput {
268    /// Executed slot output
269    ExecutedSlot(ExecutionOutput),
270
271    /// Finalized slot output
272    FinalizedSlot(ExecutionOutput),
273}
274
275/// structure storing a block id + network versions (from a block header)
276#[derive(Debug, Clone, Serialize)]
277pub struct ExecutedBlockInfo {
278    /// Block id
279    pub block_id: BlockId,
280    /// Current network version (see Versioning doc)
281    pub current_version: u32,
282    /// Announced network version (see Versioning doc)
283    pub announced_version: Option<u32>,
284}
285
286/// structure describing the output of a single execution
287#[derive(Debug, Clone, Serialize)]
288pub struct ExecutionOutput {
289    /// slot
290    pub slot: Slot,
291    /// optional executed block info at that slot (None if miss)
292    pub block_info: Option<ExecutedBlockInfo>,
293    /// state changes caused by the execution step
294    pub state_changes: StateChanges,
295    /// events emitted by the execution step
296    pub events: EventStore,
297    /// slot trace
298    #[cfg(feature = "execution-trace")]
299    pub slot_trace: Option<(SlotAbiCallStack, Vec<Transfer>)>,
300    /// storage
301    #[cfg(feature = "dump-block")]
302    #[serde(skip_serializing)]
303    pub storage: Option<Storage>,
304    /// Deferred credits execution (empty if execution-info feature is NOT enabled)
305    pub deferred_credits_execution: Vec<(Address, Result<Amount, String>)>,
306    /// Cancel async message execution (empty if execution-info feature is NOT enabled)
307    pub cancel_async_message_execution: Vec<(Address, Result<Amount, String>)>,
308    /// Auto sell roll execution (empty if execution-info feature is NOT enabled)
309    pub auto_sell_execution: Vec<(Address, Amount)>,
310    /// history of transfers (empty if execution-info feature is NOT enabled)
311    pub transfers_history: Vec<TransferInfo>,
312    /// Per-slot execution info (rewards, denunciations, roll ops, async /
313    /// deferred call results, etc.) gathered during `execute_slot` and
314    /// carried on the `ExecutionOutput` so that finalization can broadcast
315    /// it with the correct slot metadata even when multiple active slots
316    /// have been speculatively executed ahead of the finalized one.
317    ///
318    /// Not serialized: `ExecutionInfoForSlot` bundles traces that are not
319    /// `Serialize`. The slot-replayer dump path (which is the only user
320    /// of `ExecutionOutput`'s `Serialize`) doesn't need this field.
321    ///
322    /// Populated only when the `execution-info` feature is enabled in the
323    /// execution worker — `None` otherwise.
324    #[serde(skip)]
325    pub execution_info: Option<ExecutionInfoForSlot>,
326}
327
328/// structure describing the output of a read only execution
329#[derive(Debug, Clone)]
330pub struct ReadOnlyExecutionOutput {
331    /// Output of a single execution
332    pub out: ExecutionOutput,
333    /// Gas cost for this execution, with needed adjustments
334    pub gas_cost: u64,
335    /// Returned value from the module call
336    pub call_result: Vec<u8>,
337}
338
339/// structure describing different types of read-only execution request
340#[derive(Debug, Clone)]
341pub struct ReadOnlyExecutionRequest {
342    /// Maximum gas to spend in the execution.
343    pub max_gas: u64,
344    /// Call stack to simulate, older caller first
345    pub call_stack: Vec<ExecutionStackElement>,
346    /// Target of the request
347    pub target: ReadOnlyExecutionTarget,
348    /// Coins transferred to the target address during the call
349    pub coins: Option<Amount>,
350    /// Fee
351    pub fee: Option<Amount>,
352}
353
354/// structure describing different possible targets of a read-only execution request
355#[derive(Debug, Clone)]
356pub enum ReadOnlyExecutionTarget {
357    /// Execute the main function of a bytecode
358    BytecodeExecution(Vec<u8>),
359
360    /// Execute a function call
361    FunctionCall {
362        /// Target address
363        target_addr: Address,
364        /// Target function
365        target_func: String,
366        /// Parameter to pass to the target function
367        parameter: Vec<u8>,
368    },
369}
370
371/// structure describing a read-only call
372#[derive(Debug, Clone)]
373pub struct ReadOnlyCallRequest {
374    /// Maximum gas to spend in the execution.
375    pub max_gas: u64,
376    /// Call stack to simulate, older caller first. Target should be last.
377    pub call_stack: Vec<ExecutionStackElement>,
378    /// Target address
379    pub target_addr: Address,
380    /// Target function
381    pub target_func: String,
382    /// Parameter to pass to the target function
383    pub parameter: String,
384    /// execution start state
385    ///
386    /// Whether to start execution from final or active state
387    pub is_final: bool,
388}
389
390/// Structure describing an element of the execution stack.
391/// Every time a function is called from bytecode,
392/// a new `ExecutionStackElement` is pushed at the top of the execution stack
393/// to represent the local execution context of the called function,
394/// instead of the caller's which should lie just below in the stack.
395#[derive(Debug, Clone)]
396pub struct ExecutionStackElement {
397    /// Called address
398    pub address: Address,
399    /// Coins transferred to the target address during the call
400    pub coins: Amount,
401    /// List of addresses owned by the current call, and on which the current call has write access.
402    /// This list should contain `ExecutionStackElement::address` in the sense that an address should have write access to itself.
403    /// This list should also contain all addresses created previously during the call
404    /// to allow write access on newly created addresses in order to set them up,
405    /// but only within the scope of the current stack element.
406    /// That way, only the current scope and neither its caller not the functions it calls gain this write access,
407    /// which is important for security.
408    /// Note that we use a vector instead of a pre-hashed set to ensure order determinism,
409    /// the performance hit of linear search remains minimal because `owned_addresses` will always contain very few elements.
410    pub owned_addresses: Vec<Address>,
411    /// Datastore (key value store) for `ExecuteSC` Operation
412    pub operation_datastore: Option<Datastore>,
413}