1
1
use crate :: { ChainStore , StoreTransaction } ;
2
- use ckb_error:: Error ;
3
- use ckb_types:: { core:: BlockView , packed, prelude:: * } ;
2
+ use ckb_error:: { Error , InternalErrorKind } ;
3
+ use ckb_types:: {
4
+ core:: { BlockNumber , BlockView } ,
5
+ packed,
6
+ prelude:: * ,
7
+ utilities:: merkle_mountain_range:: { hash_out_point_and_status, TxoStatus } ,
8
+ } ;
4
9
use std:: collections:: HashMap ;
5
10
6
11
/**
@@ -26,6 +31,39 @@ use std::collections::HashMap;
26
31
pub fn attach_block_cell ( txn : & StoreTransaction , block : & BlockView ) -> Result < ( ) , Error > {
27
32
let transactions = block. transactions ( ) ;
28
33
34
+ // update txo root mmr
35
+ let block_number = block. header ( ) . number ( ) ;
36
+ let mut txo_root_mmr = txn. txo_root_mmr ( block_number) ;
37
+ for tx in transactions. iter ( ) {
38
+ for input in tx. inputs ( ) . into_iter ( ) {
39
+ let out_point = input. previous_output ( ) ;
40
+ // cellbase and genesis block's tx may not have previous output
41
+ if let Some ( mut txo_status) = txn. get_txo_mmr_status ( & out_point) {
42
+ txo_root_mmr
43
+ . update (
44
+ txo_status. mmr_position ,
45
+ hash_out_point_and_status ( & out_point, txo_status. created_by , block_number) ,
46
+ )
47
+ . map_err ( |e| InternalErrorKind :: MMR . other ( e) ) ?;
48
+ txo_status. mark_as_consumed ( block_number) ;
49
+ txn. insert_txo_root_mmr_status ( & out_point, & txo_status) ?;
50
+ }
51
+ }
52
+
53
+ for out_point in tx. output_pts ( ) . into_iter ( ) {
54
+ let hash = hash_out_point_and_status ( & out_point, block_number, BlockNumber :: MAX ) ;
55
+ let mmr_position = txo_root_mmr
56
+ . push ( hash)
57
+ . map_err ( |e| InternalErrorKind :: MMR . other ( e) ) ?;
58
+ let txo_status = TxoStatus :: new ( mmr_position, block_number) ;
59
+ txn. insert_txo_root_mmr_status ( & out_point, & txo_status) ?;
60
+ }
61
+ }
62
+ txo_root_mmr
63
+ . commit ( )
64
+ . map_err ( |e| InternalErrorKind :: MMR . other ( e) ) ?;
65
+ txn. insert_txo_root_mmr_size ( block_number, txo_root_mmr. mmr_size ( ) ) ?;
66
+
29
67
// add new live cells
30
68
let new_cells = transactions
31
69
. iter ( )
@@ -84,6 +122,46 @@ pub fn attach_block_cell(txn: &StoreTransaction, block: &BlockView) -> Result<()
84
122
/// Undoes the effects of this block on the live cell set.
85
123
pub fn detach_block_cell ( txn : & StoreTransaction , block : & BlockView ) -> Result < ( ) , Error > {
86
124
let transactions = block. transactions ( ) ;
125
+
126
+ // undo txo root mmr updates
127
+ let block_number = block. header ( ) . number ( ) ;
128
+ let mut txo_root_mmr = txn. txo_root_mmr ( block_number) ;
129
+
130
+ for tx in transactions. iter ( ) {
131
+ for input in tx. inputs ( ) . into_iter ( ) {
132
+ let out_point = input. previous_output ( ) ;
133
+ if let Some ( mut txo_status) = txn. get_txo_mmr_status ( & out_point) {
134
+ txo_root_mmr
135
+ . update (
136
+ txo_status. mmr_position ,
137
+ hash_out_point_and_status (
138
+ & out_point,
139
+ txo_status. created_by ,
140
+ BlockNumber :: MAX ,
141
+ ) ,
142
+ )
143
+ . map_err ( |e| InternalErrorKind :: MMR . other ( e) ) ?;
144
+ txo_status. mark_as_live ( ) ;
145
+ txn. insert_txo_root_mmr_status ( & out_point, & txo_status) ?;
146
+ }
147
+ }
148
+
149
+ for out_point in tx. output_pts ( ) . into_iter ( ) {
150
+ txn. delete_txo_root_mmr_status ( & out_point) ?;
151
+ }
152
+ }
153
+ txo_root_mmr
154
+ . commit ( )
155
+ . map_err ( |e| InternalErrorKind :: MMR . other ( e) ) ?;
156
+
157
+ let current_mmr_size = txn. get_txo_mmr_size ( block_number) ;
158
+ let pre_mmr_size = txn. get_txo_mmr_size ( block_number - 1 ) ;
159
+ for pos in pre_mmr_size..current_mmr_size {
160
+ txn. delete_txo_root_mmr_element ( pos, block_number) ?;
161
+ }
162
+ txn. delete_txo_root_mmr_size ( block_number) ?;
163
+
164
+ // restore inputs
87
165
let mut input_pts = HashMap :: with_capacity ( transactions. len ( ) ) ;
88
166
89
167
for tx in transactions. iter ( ) . skip ( 1 ) {
@@ -95,7 +173,6 @@ pub fn detach_block_cell(txn: &StoreTransaction, block: &BlockView) -> Result<()
95
173
}
96
174
}
97
175
98
- // restore inputs
99
176
// skip cellbase
100
177
let undo_deads = input_pts
101
178
. iter ( )
0 commit comments