Skip to content

Commit 58d3a74

Browse files
committed
fuzz: add deferred chanmon checkpoints
Track deferred monitor writes in the harness and checkpoint the ChannelManager state before flushing them to the persister. This extends setup, reload, and settle paths to model deferred ChainMonitor persistence ordering.
1 parent 9938884 commit 58d3a74

1 file changed

Lines changed: 67 additions & 21 deletions

File tree

fuzz/src/chanmon_consistency.rs

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,7 @@ struct HarnessNode<'a> {
817817
fee_estimator: Arc<FuzzEstimator>,
818818
wallet: TestWalletSource,
819819
persistence_style: ChannelMonitorUpdateStatus,
820+
deferred: bool,
820821
serialized_manager: Vec<u8>,
821822
height: u32,
822823
last_htlc_clear_fee: u32,
@@ -847,7 +848,7 @@ impl<'a> HarnessNode<'a> {
847848
fn build_chain_monitor(
848849
broadcaster: &Arc<TestBroadcaster>, fee_estimator: &Arc<FuzzEstimator>,
849850
keys_manager: &Arc<KeyProvider>, logger: Arc<dyn Logger + MaybeSend + MaybeSync>,
850-
persister: &Arc<HarnessPersister>,
851+
persister: &Arc<HarnessPersister>, deferred: bool,
851852
) -> Arc<TestChainMonitor> {
852853
Arc::new(chainmonitor::ChainMonitor::new(
853854
None,
@@ -857,14 +858,14 @@ impl<'a> HarnessNode<'a> {
857858
Arc::clone(persister),
858859
Arc::clone(keys_manager),
859860
keys_manager.get_peer_storage_key(),
860-
false,
861+
deferred,
861862
))
862863
}
863864

864865
fn new<Out: Output + MaybeSend + MaybeSync>(
865866
node_id: u8, wallet: TestWalletSource, fee_estimator: Arc<FuzzEstimator>,
866867
broadcaster: Arc<TestBroadcaster>, persistence_style: ChannelMonitorUpdateStatus,
867-
out: &Out, router: &'a FuzzRouter, chan_type: ChanType,
868+
deferred: bool, out: &Out, router: &'a FuzzRouter, chan_type: ChanType,
868869
) -> Self {
869870
let logger = Self::build_logger(node_id, out);
870871
let node_secret = SecretKey::from_slice(&[
@@ -884,6 +885,7 @@ impl<'a> HarnessNode<'a> {
884885
&keys_manager,
885886
Arc::clone(&logger),
886887
&persister,
888+
deferred,
887889
);
888890
let network = Network::Bitcoin;
889891
let best_block_timestamp = genesis_block(network).header.time;
@@ -913,6 +915,7 @@ impl<'a> HarnessNode<'a> {
913915
fee_estimator,
914916
wallet,
915917
persistence_style,
918+
deferred,
916919
serialized_manager: Vec::new(),
917920
height: 0,
918921
last_htlc_clear_fee: 253,
@@ -969,15 +972,33 @@ impl<'a> HarnessNode<'a> {
969972
}
970973
}
971974

972-
fn refresh_serialized_manager(&mut self) -> bool {
975+
fn checkpoint_manager_persistence(&mut self) -> bool {
973976
if self.node.get_and_clear_needs_persistence() {
977+
let pending_monitor_writes = self.monitor.pending_operation_count();
974978
self.serialized_manager = self.node.encode();
979+
if self.deferred {
980+
self.monitor.flush(pending_monitor_writes, &self.logger);
981+
} else {
982+
assert_eq!(pending_monitor_writes, 0);
983+
}
975984
true
976985
} else {
986+
assert_eq!(self.monitor.pending_operation_count(), 0);
977987
false
978988
}
979989
}
980990

991+
fn force_checkpoint_manager_persistence(&mut self) {
992+
let pending_monitor_writes = self.monitor.pending_operation_count();
993+
self.serialized_manager = self.node.encode();
994+
self.node.get_and_clear_needs_persistence();
995+
if self.deferred {
996+
self.monitor.flush(pending_monitor_writes, &self.logger);
997+
} else {
998+
assert_eq!(pending_monitor_writes, 0);
999+
}
1000+
}
1001+
9811002
fn bump_fee_estimate(&mut self, chan_type: ChanType) {
9821003
let mut max_feerate = self.last_htlc_clear_fee;
9831004
if matches!(chan_type, ChanType::Legacy) {
@@ -1086,6 +1107,7 @@ impl<'a> HarnessNode<'a> {
10861107
&self.keys_manager,
10871108
Arc::clone(&logger),
10881109
&persister,
1110+
self.deferred,
10891111
);
10901112

10911113
let mut monitors = new_hash_map();
@@ -1132,13 +1154,22 @@ impl<'a> HarnessNode<'a> {
11321154

11331155
let manager = <(BlockLocator, ChanMan)>::read(&mut &self.serialized_manager[..], read_args)
11341156
.expect("Failed to read manager");
1157+
let expected_status = if self.deferred {
1158+
ChannelMonitorUpdateStatus::InProgress
1159+
} else {
1160+
self.persistence_style
1161+
};
11351162
for (channel_id, mon) in monitors.drain() {
1136-
assert_eq!(chain_monitor.watch_channel(channel_id, mon), Ok(self.persistence_style));
1163+
assert_eq!(chain_monitor.watch_channel(channel_id, mon), Ok(expected_status));
11371164
}
11381165
self.node = manager.1;
11391166
self.monitor = chain_monitor;
11401167
self.persister = persister;
11411168
self.logger = logger;
1169+
// In deferred mode, the startup watch_channel registrations above queue monitor operations
1170+
// even if the reloaded ChannelManager does not need persistence. Always checkpoint here so
1171+
// those registrations can be flushed against the manager snapshot they belong to.
1172+
self.force_checkpoint_manager_persistence();
11421173
}
11431174
}
11441175

@@ -1937,9 +1968,12 @@ fn connect_peers(source: &ChanMan<'_>, dest: &ChanMan<'_>) {
19371968
}
19381969

19391970
fn make_channel(
1940-
source: &HarnessNode<'_>, dest: &HarnessNode<'_>, chan_id: i32, trusted_open: bool,
1941-
trusted_accept: bool, chain_state: &mut ChainState,
1971+
nodes: &mut [HarnessNode<'_>; 3], source_idx: usize, dest_idx: usize, chan_id: i32,
1972+
trusted_open: bool, trusted_accept: bool, chain_state: &mut ChainState,
19421973
) {
1974+
assert!(source_idx < dest_idx);
1975+
let (left, right) = nodes.split_at_mut(dest_idx);
1976+
let (source, dest) = (&mut left[source_idx], &mut right[0]);
19431977
if trusted_open {
19441978
source
19451979
.create_channel_to_trusted_peer_0reserve(
@@ -2050,7 +2084,8 @@ fn make_channel(
20502084
}
20512085
};
20522086
dest.handle_funding_created(source.get_our_node_id(), &funding_created);
2053-
// Complete any pending monitor persistence callbacks for dest after watch_channel.
2087+
dest.checkpoint_manager_persistence();
2088+
// Complete any monitor persistence callbacks made available for dest after watch_channel.
20542089
dest.complete_all_pending_monitor_updates();
20552090

20562091
let (funding_signed, channel_id) = {
@@ -2071,7 +2106,8 @@ fn make_channel(
20712106
}
20722107

20732108
source.handle_funding_signed(dest.get_our_node_id(), &funding_signed);
2074-
// Complete any pending monitor persistence callbacks for source after watch_channel.
2109+
source.checkpoint_manager_persistence();
2110+
// Complete any monitor persistence callbacks made available for source after watch_channel.
20752111
source.complete_all_pending_monitor_updates();
20762112

20772113
let events = source.get_and_clear_pending_events();
@@ -2143,6 +2179,12 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
21432179
ChannelMonitorUpdateStatus::Completed
21442180
},
21452181
];
2182+
let deferred = [
2183+
config_byte & 0b0010_0000 != 0,
2184+
config_byte & 0b0100_0000 != 0,
2185+
config_byte & 0b1000_0000 != 0,
2186+
];
2187+
21462188
let wallet_a = TestWalletSource::new(SecretKey::from_slice(&[1; 32]).unwrap());
21472189
let wallet_b = TestWalletSource::new(SecretKey::from_slice(&[2; 32]).unwrap());
21482190
let wallet_c = TestWalletSource::new(SecretKey::from_slice(&[3; 32]).unwrap());
@@ -2179,6 +2221,7 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
21792221
Arc::clone(&fee_est_a),
21802222
Arc::clone(&broadcast_a),
21812223
persistence_styles[0],
2224+
deferred[0],
21822225
&out,
21832226
router,
21842227
chan_type,
@@ -2189,6 +2232,7 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
21892232
Arc::clone(&fee_est_b),
21902233
Arc::clone(&broadcast_b),
21912234
persistence_styles[1],
2235+
deferred[1],
21922236
&out,
21932237
router,
21942238
chan_type,
@@ -2199,6 +2243,7 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
21992243
Arc::clone(&fee_est_c),
22002244
Arc::clone(&broadcast_c),
22012245
persistence_styles[2],
2246+
deferred[2],
22022247
&out,
22032248
router,
22042249
chan_type,
@@ -2217,14 +2262,14 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
22172262
// channel gets its own txid and funding outpoint.
22182263
// A-B: channel 2 A and B have 0-reserve (trusted open + trusted accept),
22192264
// channel 3 A has 0-reserve (trusted accept), if channels are non-legacy.
2220-
make_channel(&nodes[0], &nodes[1], 1, false, false, &mut chain_state);
2221-
make_channel(&nodes[0], &nodes[1], 2, set_0reserve, set_0reserve, &mut chain_state);
2222-
make_channel(&nodes[0], &nodes[1], 3, false, set_0reserve, &mut chain_state);
2265+
make_channel(&mut nodes, 0, 1, 1, false, false, &mut chain_state);
2266+
make_channel(&mut nodes, 0, 1, 2, set_0reserve, set_0reserve, &mut chain_state);
2267+
make_channel(&mut nodes, 0, 1, 3, false, set_0reserve, &mut chain_state);
22232268
// B-C: channel 4 B has 0-reserve (via trusted accept),
22242269
// channel 5 C has 0-reserve (via trusted open), if channels are non-legacy.
2225-
make_channel(&nodes[1], &nodes[2], 4, false, set_0reserve, &mut chain_state);
2226-
make_channel(&nodes[1], &nodes[2], 5, set_0reserve, false, &mut chain_state);
2227-
make_channel(&nodes[1], &nodes[2], 6, false, false, &mut chain_state);
2270+
make_channel(&mut nodes, 1, 2, 4, false, set_0reserve, &mut chain_state);
2271+
make_channel(&mut nodes, 1, 2, 5, set_0reserve, false, &mut chain_state);
2272+
make_channel(&mut nodes, 1, 2, 6, false, false, &mut chain_state);
22282273

22292274
// Wipe the transactions-broadcasted set to make sure we don't broadcast
22302275
// any transactions during normal operation after setup.
@@ -2251,7 +2296,7 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
22512296
};
22522297

22532298
for node in &mut nodes {
2254-
node.serialized_manager = node.encode();
2299+
node.force_checkpoint_manager_persistence();
22552300
}
22562301

22572302
Self {
@@ -2750,7 +2795,7 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
27502795
"It may take may iterations to settle the state, but it should not take forever"
27512796
);
27522797
}
2753-
let mut made_progress = self.refresh_serialized_managers();
2798+
let mut made_progress = self.checkpoint_manager_persistences();
27542799
// Next, make sure no monitor completion callbacks are pending.
27552800
made_progress |= self.ab_link.complete_all_monitor_updates(&self.nodes);
27562801
made_progress |= self.bc_link.complete_all_monitor_updates(&self.nodes);
@@ -2899,10 +2944,10 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
28992944
self.nodes[2].record_last_htlc_clear_fee();
29002945
}
29012946

2902-
fn refresh_serialized_managers(&mut self) -> bool {
2947+
fn checkpoint_manager_persistences(&mut self) -> bool {
29032948
let mut made_progress = false;
29042949
for node in &mut self.nodes {
2905-
made_progress |= node.refresh_serialized_manager();
2950+
made_progress |= node.checkpoint_manager_persistence();
29062951
}
29072952
made_progress
29082953
}
@@ -2911,9 +2956,10 @@ impl<'a, Out: Output + MaybeSend + MaybeSync> Harness<'a, Out> {
29112956
#[inline]
29122957
pub fn do_test<Out: Output + MaybeSend + MaybeSync>(data: &[u8], out: Out) {
29132958
let router = FuzzRouter {};
2914-
// Read initial monitor styles and channel type from fuzz input byte 0:
2959+
// Read initial monitor styles, channel type, and deferred write mode from fuzz input byte 0:
29152960
// bits 0-2: monitor styles (1 bit per node)
29162961
// bits 3-4: channel type (0=Legacy, 1=KeyedAnchors, 2=ZeroFeeCommitments)
2962+
// bits 5-7: deferred monitor write mode (1 bit per node)
29172963
let config_byte = if !data.is_empty() { data[0] } else { 0 };
29182964
let mut harness = Harness::new(config_byte, out, &router);
29192965
let mut read_pos = 1; // First byte was consumed for initial config.
@@ -3325,7 +3371,7 @@ pub fn do_test<Out: Output + MaybeSend + MaybeSync>(data: &[u8], out: Out) {
33253371
_ => break 'fuzz_loop,
33263372
}
33273373

3328-
harness.refresh_serialized_managers();
3374+
harness.checkpoint_manager_persistences();
33293375
}
33303376
harness.finish();
33313377
}

0 commit comments

Comments
 (0)