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
multiversx_sc::imports!();
pub const DEFAULT_MIN_GAS_TO_SAVE_PROGRESS: u64 = 1_000_000;
pub type LoopOp = bool;
pub const CONTINUE_OP: bool = true;
pub const STOP_OP: bool = false;
#[multiversx_sc::module]
pub trait OngoingOperationModule {
fn run_while_it_has_gas<Process>(
&self,
min_gas_to_save_progress: u64,
mut process: Process,
) -> OperationCompletionStatus
where
Process: FnMut() -> LoopOp,
{
let mut gas_per_iteration = 0;
let mut gas_before = self.blockchain().get_gas_left();
loop {
let loop_op = process();
if loop_op == STOP_OP {
break;
}
let gas_after = self.blockchain().get_gas_left();
let current_iteration_cost = gas_before - gas_after;
if current_iteration_cost > gas_per_iteration {
gas_per_iteration = current_iteration_cost;
}
if !self.can_continue_operation(gas_per_iteration, min_gas_to_save_progress) {
return OperationCompletionStatus::InterruptedBeforeOutOfGas;
}
gas_before = gas_after;
}
self.clear_operation();
OperationCompletionStatus::Completed
}
#[inline]
fn can_continue_operation(&self, operation_cost: u64, min_gas_to_save_progress: u64) -> bool {
let gas_left = self.blockchain().get_gas_left();
gas_left > min_gas_to_save_progress + operation_cost
}
fn load_operation<T: TopDecode + Default>(&self) -> T {
let raw_buffer = self.current_ongoing_operation().get();
if raw_buffer.is_empty() {
return T::default();
}
match T::top_decode(raw_buffer) {
Result::Ok(op) => op,
Result::Err(err) => sc_panic!(err.message_str()),
}
}
fn save_progress<T: TopEncode>(&self, op: &T) {
let mut encoded_op = ManagedBuffer::new();
if let Result::Err(err) = op.top_encode(&mut encoded_op) {
sc_panic!(err.message_str());
}
self.current_ongoing_operation().set(&encoded_op);
}
#[inline]
fn clear_operation(&self) {
self.current_ongoing_operation().clear();
}
#[storage_mapper("ongoing_operation:currentOngoingOperation")]
fn current_ongoing_operation(&self) -> SingleValueMapper<ManagedBuffer>;
}