@@ -107,6 +107,14 @@ pub enum ConnectStyle {
107
107
/// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only
108
108
/// make a single `best_block_updated` call.
109
109
TransactionsFirstSkippingBlocks ,
110
+ /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only
111
+ /// make a single `best_block_updated` call. Further, we call transactions_confirmed multiple
112
+ /// times to ensure its idempotent.
113
+ TransactionsDuplicativelyFirstSkippingBlocks ,
114
+ /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only
115
+ /// make a single `best_block_updated` call. Further, we call transactions_confirmed multiple
116
+ /// times to ensure its idempotent.
117
+ HighlyRedundantTransactionsFirstSkippingBlocks ,
110
118
/// The same as `TransactionsFirst` when connecting blocks. During disconnection only
111
119
/// `transaction_unconfirmed` is called.
112
120
TransactionsFirstReorgsOnlyTip ,
@@ -121,14 +129,16 @@ impl ConnectStyle {
121
129
use core:: hash:: { BuildHasher , Hasher } ;
122
130
// Get a random value using the only std API to do so - the DefaultHasher
123
131
let rand_val = std:: collections:: hash_map:: RandomState :: new ( ) . build_hasher ( ) . finish ( ) ;
124
- let res = match rand_val % 7 {
132
+ let res = match rand_val % 9 {
125
133
0 => ConnectStyle :: BestBlockFirst ,
126
134
1 => ConnectStyle :: BestBlockFirstSkippingBlocks ,
127
135
2 => ConnectStyle :: BestBlockFirstReorgsOnlyTip ,
128
136
3 => ConnectStyle :: TransactionsFirst ,
129
137
4 => ConnectStyle :: TransactionsFirstSkippingBlocks ,
130
- 5 => ConnectStyle :: TransactionsFirstReorgsOnlyTip ,
131
- 6 => ConnectStyle :: FullBlockViaListen ,
138
+ 5 => ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks ,
139
+ 6 => ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks ,
140
+ 7 => ConnectStyle :: TransactionsFirstReorgsOnlyTip ,
141
+ 8 => ConnectStyle :: FullBlockViaListen ,
132
142
_ => unreachable ! ( ) ,
133
143
} ;
134
144
eprintln ! ( "Using Block Connection Style: {:?}" , res) ;
@@ -143,6 +153,7 @@ impl ConnectStyle {
143
153
pub fn connect_blocks < ' a , ' b , ' c , ' d > ( node : & ' a Node < ' b , ' c , ' d > , depth : u32 ) -> BlockHash {
144
154
let skip_intermediaries = match * node. connect_style . borrow ( ) {
145
155
ConnectStyle :: BestBlockFirstSkippingBlocks |ConnectStyle :: TransactionsFirstSkippingBlocks |
156
+ ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks |ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks |
146
157
ConnectStyle :: BestBlockFirstReorgsOnlyTip |ConnectStyle :: TransactionsFirstReorgsOnlyTip => true ,
147
158
_ => false ,
148
159
} ;
@@ -193,8 +204,32 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk
193
204
node. node . best_block_updated ( & block. header , height) ;
194
205
node. node . transactions_confirmed ( & block. header , & txdata, height) ;
195
206
} ,
196
- ConnectStyle :: TransactionsFirst |ConnectStyle :: TransactionsFirstSkippingBlocks |ConnectStyle :: TransactionsFirstReorgsOnlyTip => {
207
+ ConnectStyle :: TransactionsFirst |ConnectStyle :: TransactionsFirstSkippingBlocks |
208
+ ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks |ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks |
209
+ ConnectStyle :: TransactionsFirstReorgsOnlyTip => {
210
+ if * node. connect_style . borrow ( ) == ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks {
211
+ let mut connections = Vec :: new ( ) ;
212
+ for ( block, height) in node. blocks . lock ( ) . unwrap ( ) . iter ( ) {
213
+ if !block. txdata . is_empty ( ) {
214
+ // Reconnect all transactions we've ever seen to ensure transaction connection
215
+ // is *really* idempotent. This is a somewhat likely deployment for some
216
+ // esplora implementations of chain sync which try to reduce state and
217
+ // complexity as much as possible.
218
+ //
219
+ // Sadly we have to clone the block here to maintain lockorder. In the
220
+ // future we should consider Arc'ing the blocks to avoid this.
221
+ connections. push ( ( block. clone ( ) , * height) ) ;
222
+ }
223
+ }
224
+ for ( old_block, height) in connections {
225
+ node. chain_monitor . chain_monitor . transactions_confirmed ( & old_block. header ,
226
+ & old_block. txdata . iter ( ) . enumerate ( ) . collect :: < Vec < _ > > ( ) , height) ;
227
+ }
228
+ }
197
229
node. chain_monitor . chain_monitor . transactions_confirmed ( & block. header , & txdata, height) ;
230
+ if * node. connect_style . borrow ( ) == ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks {
231
+ node. chain_monitor . chain_monitor . transactions_confirmed ( & block. header , & txdata, height) ;
232
+ }
198
233
call_claimable_balances ( node) ;
199
234
node. chain_monitor . chain_monitor . best_block_updated ( & block. header , height) ;
200
235
node. node . transactions_confirmed ( & block. header , & txdata, height) ;
@@ -226,7 +261,8 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32)
226
261
node. chain_monitor . chain_monitor . block_disconnected ( & orig. 0 . header , orig. 1 ) ;
227
262
Listen :: block_disconnected ( node. node , & orig. 0 . header , orig. 1 ) ;
228
263
} ,
229
- ConnectStyle :: BestBlockFirstSkippingBlocks |ConnectStyle :: TransactionsFirstSkippingBlocks => {
264
+ ConnectStyle :: BestBlockFirstSkippingBlocks |ConnectStyle :: TransactionsFirstSkippingBlocks |
265
+ ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks |ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks => {
230
266
if i == count - 1 {
231
267
node. chain_monitor . chain_monitor . best_block_updated ( & prev. 0 . header , prev. 1 ) ;
232
268
node. node . best_block_updated ( & prev. 0 . header , prev. 1 ) ;
0 commit comments