+ #[test]
+ fn blinding_point_skimmed_fee_malformed_ser() {
+ // Ensure that channel blinding points, skimmed fees, and malformed HTLCs are (de)serialized
+ // properly.
+ let logger = test_utils::TestLogger::new();
+ let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000});
+ let secp_ctx = Secp256k1::new();
+ let seed = [42; 32];
+ let network = Network::Testnet;
+ let best_block = BestBlock::from_network(network);
+ let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
+
+ let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+ let config = UserConfig::default();
+ let features = channelmanager::provided_init_features(&config);
+ let mut outbound_chan = OutboundV1Channel::<&TestKeysInterface>::new(
+ &feeest, &&keys_provider, &&keys_provider, node_b_node_id, &features, 10000000, 100000, 42, &config, 0, 42, None
+ ).unwrap();
+ let inbound_chan = InboundV1Channel::<&TestKeysInterface>::new(
+ &feeest, &&keys_provider, &&keys_provider, node_b_node_id, &channelmanager::provided_channel_type_features(&config),
+ &features, &outbound_chan.get_open_channel(ChainHash::using_genesis_block(network)), 7, &config, 0, &&logger, false
+ ).unwrap();
+ outbound_chan.accept_channel(&inbound_chan.get_accept_channel_message(), &config.channel_handshake_limits, &features).unwrap();
+ let tx = Transaction { version: 1, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+ value: 10000000, script_pubkey: outbound_chan.context.get_funding_redeemscript(),
+ }]};
+ let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
+ let funding_created = outbound_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap().unwrap();
+ let mut chan = match inbound_chan.funding_created(&funding_created, best_block, &&keys_provider, &&logger) {
+ Ok((chan, _, _)) => chan,
+ Err((_, e)) => panic!("{}", e),
+ };
+
+ let dummy_htlc_source = HTLCSource::OutboundRoute {
+ path: Path {
+ hops: vec![RouteHop {
+ pubkey: test_utils::pubkey(2), channel_features: ChannelFeatures::empty(),
+ node_features: NodeFeatures::empty(), short_channel_id: 0, fee_msat: 0,
+ cltv_expiry_delta: 0, maybe_announced_channel: false,
+ }],
+ blinded_tail: None
+ },
+ session_priv: test_utils::privkey(42),
+ first_hop_htlc_msat: 0,
+ payment_id: PaymentId([42; 32]),
+ };
+ let dummy_outbound_output = OutboundHTLCOutput {
+ htlc_id: 0,
+ amount_msat: 0,
+ payment_hash: PaymentHash([43; 32]),
+ cltv_expiry: 0,
+ state: OutboundHTLCState::Committed,
+ source: dummy_htlc_source.clone(),
+ skimmed_fee_msat: None,
+ blinding_point: None,
+ };
+ let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10];
+ for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() {
+ if idx % 2 == 0 {
+ htlc.blinding_point = Some(test_utils::pubkey(42 + idx as u8));
+ }
+ if idx % 3 == 0 {
+ htlc.skimmed_fee_msat = Some(1);
+ }
+ }
+ chan.context.pending_outbound_htlcs = pending_outbound_htlcs.clone();
+
+ let dummy_holding_cell_add_htlc = HTLCUpdateAwaitingACK::AddHTLC {
+ amount_msat: 0,
+ cltv_expiry: 0,
+ payment_hash: PaymentHash([43; 32]),
+ source: dummy_htlc_source.clone(),
+ onion_routing_packet: msgs::OnionPacket {
+ version: 0,
+ public_key: Ok(test_utils::pubkey(1)),
+ hop_data: [0; 20*65],
+ hmac: [0; 32]
+ },
+ skimmed_fee_msat: None,
+ blinding_point: None,
+ };
+ let dummy_holding_cell_claim_htlc = HTLCUpdateAwaitingACK::ClaimHTLC {
+ payment_preimage: PaymentPreimage([42; 32]),
+ htlc_id: 0,
+ };
+ let dummy_holding_cell_failed_htlc = |htlc_id| HTLCUpdateAwaitingACK::FailHTLC {
+ htlc_id, err_packet: msgs::OnionErrorPacket { data: vec![42] }
+ };
+ let dummy_holding_cell_malformed_htlc = |htlc_id| HTLCUpdateAwaitingACK::FailMalformedHTLC {
+ htlc_id, failure_code: INVALID_ONION_BLINDING, sha256_of_onion: [0; 32],
+ };
+ let mut holding_cell_htlc_updates = Vec::with_capacity(12);
+ for i in 0..12 {
+ if i % 5 == 0 {
+ holding_cell_htlc_updates.push(dummy_holding_cell_add_htlc.clone());
+ } else if i % 5 == 1 {
+ holding_cell_htlc_updates.push(dummy_holding_cell_claim_htlc.clone());
+ } else if i % 5 == 2 {
+ let mut dummy_add = dummy_holding_cell_add_htlc.clone();
+ if let HTLCUpdateAwaitingACK::AddHTLC {
+ ref mut blinding_point, ref mut skimmed_fee_msat, ..
+ } = &mut dummy_add {
+ *blinding_point = Some(test_utils::pubkey(42 + i));
+ *skimmed_fee_msat = Some(42);
+ } else { panic!() }
+ holding_cell_htlc_updates.push(dummy_add);
+ } else if i % 5 == 3 {
+ holding_cell_htlc_updates.push(dummy_holding_cell_malformed_htlc(i as u64));
+ } else {
+ holding_cell_htlc_updates.push(dummy_holding_cell_failed_htlc(i as u64));
+ }
+ }
+ chan.context.holding_cell_htlc_updates = holding_cell_htlc_updates.clone();
+
+ // Encode and decode the channel and ensure that the HTLCs within are the same.
+ let encoded_chan = chan.encode();
+ let mut s = crate::io::Cursor::new(&encoded_chan);
+ let mut reader = crate::util::ser::FixedLengthReader::new(&mut s, encoded_chan.len() as u64);
+ let features = channelmanager::provided_channel_type_features(&config);
+ let decoded_chan = Channel::read(&mut reader, (&&keys_provider, &&keys_provider, 0, &features)).unwrap();
+ assert_eq!(decoded_chan.context.pending_outbound_htlcs, pending_outbound_htlcs);
+ assert_eq!(decoded_chan.context.holding_cell_htlc_updates, holding_cell_htlc_updates);
+ }
+
+ #[cfg(all(feature = "_test_vectors", not(feature = "grind_signatures")))]