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
use super::{Call, ExecStep, FixedCParams};
use crate::operation::RWCounter;

#[derive(Debug, Default, Clone)]
pub struct Chunk {
    /// current context
    pub ctx: ChunkContext,
    /// fixed param for the chunk
    pub fixed_param: FixedCParams,
    /// Begin op of a chunk
    pub begin_chunk: Option<ExecStep>,
    /// End op of a chunk
    pub end_chunk: Option<ExecStep>,
    /// Padding step that is repeated after the last transaction and before
    /// reaching the last EVM row.
    pub padding: Option<ExecStep>,
    ///
    pub prev_last_call: Option<Call>,
}

/// Context of chunking, used to track the current chunk index and inner rw counter
/// also the global rw counter from start to end.
#[derive(Debug, Clone)]
pub struct ChunkContext {
    /// Index of current chunk, start from 0
    pub idx: usize,
    /// Used to track the inner chunk counter in every operation in the chunk.
    /// it will be reset for every new chunk.
    /// Contains the next available value.
    pub rwc: RWCounter,
    /// Number of chunks
    pub total_chunks: usize,
    /// Initial global rw counter
    pub initial_rwc: usize,
    /// End global rw counter
    pub end_rwc: usize,
    /// tx range in block: [initial_tx_index, end_tx_index)
    pub initial_tx_index: usize,
    ///
    pub end_tx_index: usize,
    ///  copy range in block: [initial_copy_index, end_copy_index)
    pub initial_copy_index: usize,
    ///
    pub end_copy_index: usize,
}

impl Default for ChunkContext {
    fn default() -> Self {
        Self::new(1)
    }
}

impl ChunkContext {
    /// Create a new Self
    pub fn new(total_chunks: usize) -> Self {
        Self {
            rwc: RWCounter::new(),
            idx: 0,
            total_chunks,
            initial_rwc: 1, // rw counter start from 1
            end_rwc: 0,     // end_rwc should be set in later phase
            initial_tx_index: 0,
            end_tx_index: 0,
            initial_copy_index: 0,
            end_copy_index: 0,
        }
    }

    /// New chunking context with one chunk
    pub fn new_one_chunk() -> Self {
        Self {
            rwc: RWCounter::new(),
            idx: 0,
            total_chunks: 1,
            initial_rwc: 1, // rw counter start from 1
            end_rwc: 0,     // end_rwc should be set in later phase
            initial_tx_index: 0,
            end_tx_index: 0,
            initial_copy_index: 0,
            end_copy_index: 0,
        }
    }

    /// Proceed the context to next chunk, record the initial rw counter
    /// update the chunk idx and reset the inner rw counter
    pub fn bump(&mut self, initial_rwc: usize, initial_tx: usize, initial_copy: usize) {
        assert!(self.idx + 1 < self.total_chunks, "Exceed total chunks");
        self.idx += 1;
        self.rwc = RWCounter::new();
        self.initial_rwc = initial_rwc;
        self.initial_tx_index = initial_tx;
        self.initial_copy_index = initial_copy;
        self.end_rwc = 0;
        self.end_tx_index = 0;
        self.end_copy_index = 0;
    }

    /// Is first chunk
    pub fn is_first_chunk(&self) -> bool {
        self.idx == 0
    }

    /// Is last chunk
    pub fn is_last_chunk(&self) -> bool {
        self.total_chunks - self.idx - 1 == 0
    }
}