@@ -11,8 +11,11 @@ use ic_stable_structures::{
11
11
use serde:: Deserialize ;
12
12
use std:: cell:: RefCell ;
13
13
14
- const LOG_INDEX_MEMORY_ID : MemoryId = MemoryId :: new ( 0 ) ;
15
- const LOG_DATA_MEMORY_ID : MemoryId = MemoryId :: new ( 1 ) ;
14
+ const V0_LOG_INDEX_MEMORY_ID : MemoryId = MemoryId :: new ( 0 ) ;
15
+ const V0_LOG_DATA_MEMORY_ID : MemoryId = MemoryId :: new ( 1 ) ;
16
+
17
+ const V1_LOG_INDEX_MEMORY_ID : MemoryId = MemoryId :: new ( 2 ) ;
18
+ const V1_LOG_DATA_MEMORY_ID : MemoryId = MemoryId :: new ( 3 ) ;
16
19
17
20
type VMem = VirtualMemory < DefaultMemoryImpl > ;
18
21
type EventLog = StableLog < Vec < u8 > , VMem , VMem > ;
@@ -22,13 +25,24 @@ thread_local! {
22
25
MemoryManager :: init( DefaultMemoryImpl :: default ( ) )
23
26
) ;
24
27
25
- /// The log of the ckBTC state modifications.
26
- static EVENTS : RefCell <EventLog > = MEMORY_MANAGER
28
+ /// The v0 log of the ckBTC state modifications that should be migrated to v1 and then set to empty.
29
+ static V0_EVENTS : RefCell <EventLog > = MEMORY_MANAGER
30
+ . with( |m|
31
+ RefCell :: new(
32
+ StableLog :: init(
33
+ m. borrow( ) . get( V0_LOG_INDEX_MEMORY_ID ) ,
34
+ m. borrow( ) . get( V0_LOG_DATA_MEMORY_ID )
35
+ ) . expect( "failed to initialize stable log" )
36
+ )
37
+ ) ;
38
+
39
+ /// The latest log of the ckBTC state modifications.
40
+ static V1_EVENTS : RefCell <EventLog > = MEMORY_MANAGER
27
41
. with( |m|
28
42
RefCell :: new(
29
43
StableLog :: init(
30
- m. borrow( ) . get( LOG_INDEX_MEMORY_ID ) ,
31
- m. borrow( ) . get( LOG_DATA_MEMORY_ID )
44
+ m. borrow( ) . get( V1_LOG_INDEX_MEMORY_ID ) ,
45
+ m. borrow( ) . get( V1_LOG_DATA_MEMORY_ID )
32
46
) . expect( "failed to initialize stable log" )
33
47
)
34
48
) ;
@@ -43,7 +57,7 @@ impl Iterator for EventIterator {
43
57
type Item = Event ;
44
58
45
59
fn next ( & mut self ) -> Option < Event > {
46
- EVENTS . with ( |events| {
60
+ V1_EVENTS . with ( |events| {
47
61
let events = events. borrow ( ) ;
48
62
49
63
match events. read_entry ( self . pos , & mut self . buf ) {
@@ -63,7 +77,7 @@ impl Iterator for EventIterator {
63
77
}
64
78
65
79
/// Encodes an event into a byte array.
66
- fn encode_event ( event : & Event ) -> Vec < u8 > {
80
+ pub fn encode_event ( event : & Event ) -> Vec < u8 > {
67
81
let mut buf = Vec :: new ( ) ;
68
82
ciborium:: ser:: into_writer ( event, & mut buf) . expect ( "failed to encode a minter event" ) ;
69
83
buf
@@ -72,7 +86,7 @@ fn encode_event(event: &Event) -> Vec<u8> {
72
86
/// # Panics
73
87
///
74
88
/// This function panics if the event decoding fails.
75
- fn decode_event ( buf : & [ u8 ] ) -> Event {
89
+ pub fn decode_event ( buf : & [ u8 ] ) -> Event {
76
90
// For backwards compatibility, we have to handle two cases:
77
91
// 1. Legacy events: raw instances of the event type enum
78
92
// 2. New events: a struct containing a timestamp and an event type
@@ -101,9 +115,49 @@ pub fn events() -> impl Iterator<Item = Event> {
101
115
}
102
116
}
103
117
118
+ pub fn migrate_old_events_if_not_empty ( ) -> Option < u64 > {
119
+ let mut num_events_removed = None ;
120
+ V0_EVENTS . with ( |old_events| {
121
+ let mut old = old_events. borrow_mut ( ) ;
122
+ if old. len ( ) > 0 {
123
+ V1_EVENTS . with ( |new| {
124
+ num_events_removed = Some ( migrate_events ( & old, & new. borrow ( ) ) ) ;
125
+ } ) ;
126
+ * old = MEMORY_MANAGER . with ( |m| {
127
+ StableLog :: new (
128
+ m. borrow ( ) . get ( V0_LOG_INDEX_MEMORY_ID ) ,
129
+ m. borrow ( ) . get ( V0_LOG_DATA_MEMORY_ID ) ,
130
+ )
131
+ } ) ;
132
+ }
133
+ } ) ;
134
+ assert_eq ! (
135
+ V0_EVENTS . with( |events| events. borrow( ) . len( ) ) ,
136
+ 0 ,
137
+ "Old events is not emptied after data migration"
138
+ ) ;
139
+ num_events_removed
140
+ }
141
+
142
+ pub fn migrate_events ( old_events : & EventLog , new_events : & EventLog ) -> u64 {
143
+ let mut removed = 0 ;
144
+ for bytes in old_events. iter ( ) {
145
+ let event = decode_event ( & bytes) ;
146
+ match event. payload {
147
+ EventType :: ReceivedUtxos { utxos, .. } if utxos. is_empty ( ) => removed += 1 ,
148
+ _ => {
149
+ new_events
150
+ . append ( & bytes)
151
+ . expect ( "failed to append an entry to the new event log" ) ;
152
+ }
153
+ }
154
+ }
155
+ removed
156
+ }
157
+
104
158
/// Returns the current number of events in the log.
105
159
pub fn count_events ( ) -> u64 {
106
- EVENTS . with ( |events| events. borrow ( ) . len ( ) )
160
+ V1_EVENTS . with ( |events| events. borrow ( ) . len ( ) )
107
161
}
108
162
109
163
/// Records a new minter event.
@@ -112,7 +166,7 @@ pub fn record_event<R: CanisterRuntime>(payload: EventType, runtime: &R) {
112
166
timestamp : Some ( runtime. time ( ) ) ,
113
167
payload,
114
168
} ) ;
115
- EVENTS . with ( |events| {
169
+ V1_EVENTS . with ( |events| {
116
170
events
117
171
. borrow ( )
118
172
. append ( & bytes)
0 commit comments