multiversx_sc_modules/
ongoing_operation.rs1multiversx_sc::imports!();
2
3pub const DEFAULT_MIN_GAS_TO_SAVE_PROGRESS: u64 = 1_000_000;
4
5pub type LoopOp = bool;
6pub const CONTINUE_OP: bool = true;
7pub const STOP_OP: bool = false;
8
9#[multiversx_sc::module]
10pub trait OngoingOperationModule {
11 fn run_while_it_has_gas<Process>(
44 &self,
45 min_gas_to_save_progress: u64,
46 mut process: Process,
47 ) -> OperationCompletionStatus
48 where
49 Process: FnMut() -> LoopOp,
50 {
51 let mut gas_per_iteration = 0;
52 let mut gas_before = self.blockchain().get_gas_left();
53 loop {
54 let loop_op = process();
55 if loop_op == STOP_OP {
56 break;
57 }
58
59 let gas_after = self.blockchain().get_gas_left();
60 let current_iteration_cost = gas_before - gas_after;
61 if current_iteration_cost > gas_per_iteration {
62 gas_per_iteration = current_iteration_cost;
63 }
64
65 if !self.can_continue_operation(gas_per_iteration, min_gas_to_save_progress) {
66 return OperationCompletionStatus::InterruptedBeforeOutOfGas;
67 }
68
69 gas_before = gas_after;
70 }
71
72 self.clear_operation();
73
74 OperationCompletionStatus::Completed
75 }
76
77 #[inline]
78 fn can_continue_operation(&self, operation_cost: u64, min_gas_to_save_progress: u64) -> bool {
79 let gas_left = self.blockchain().get_gas_left();
80
81 gas_left > min_gas_to_save_progress + operation_cost
82 }
83
84 fn load_operation<T: TopDecode + Default>(&self) -> T {
87 let raw_buffer = self.current_ongoing_operation().get();
88 if raw_buffer.is_empty() {
89 return T::default();
90 }
91
92 match T::top_decode(raw_buffer) {
93 Result::Ok(op) => op,
94 Result::Err(err) => sc_panic!(err.message_str()),
95 }
96 }
97
98 fn save_progress<T: TopEncode>(&self, op: &T) {
100 let mut encoded_op = ManagedBuffer::new();
101 if let Result::Err(err) = op.top_encode(&mut encoded_op) {
102 sc_panic!(err.message_str());
103 }
104
105 self.current_ongoing_operation().set(&encoded_op);
106 }
107
108 #[inline]
110 fn clear_operation(&self) {
111 self.current_ongoing_operation().clear();
112 }
113
114 #[storage_mapper("ongoing_operation:currentOngoingOperation")]
115 fn current_ongoing_operation(&self) -> SingleValueMapper<ManagedBuffer>;
116}