@@ -8,9 +8,9 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
88use bitcoin:: { OutPoint , ScriptBuf } ;
99use smite:: bitcoin:: { BitcoinCli , Utxo } ;
1010use smite:: bolt:: {
11- AcceptChannel , AnnouncementSignatures , ChannelAnnouncement , ChannelId , ChannelUpdate ,
12- FundingCreated , FundingSigned , Message , NodeAnnouncement , OpenChannel , OpenChannelTlvs , Pong ,
13- ShortChannelId , msg_type,
11+ AcceptChannel , AnnouncementSignatures , ChannelAnnouncement , ChannelId , ChannelReady ,
12+ ChannelReadyTlvs , ChannelUpdate , FundingCreated , FundingSigned , Message , NodeAnnouncement ,
13+ OpenChannel , OpenChannelTlvs , Pong , ShortChannelId , msg_type,
1414} ;
1515use smite:: channel_tx:: {
1616 ChannelConfig , ChannelPartyConfig , ChannelState , FundingTransaction , HolderIdentity , Side ,
@@ -276,6 +276,17 @@ impl<C: Connection, B: BitcoinRpc> Executor<C, B> {
276276 Some ( Variable :: FundingCreatedMessage ( encoded) )
277277 }
278278
279+ Operation :: BuildChannelReady { include_alias } => {
280+ let cr = build_channel_ready (
281+ & variables,
282+ & instr. inputs ,
283+ * include_alias,
284+ & mut self . channel_states ,
285+ ) ;
286+ let encoded = Message :: ChannelReady ( cr) . encode ( ) ;
287+ Some ( Variable :: Message ( encoded) )
288+ }
289+
279290 Operation :: BuildChannelAnnouncement => {
280291 let ca = build_channel_announcement ( & variables, & instr. inputs ) ;
281292 let encoded = Message :: ChannelAnnouncement ( ca) . encode ( ) ;
@@ -728,11 +739,7 @@ fn build_funding_created(
728739 // has already been established (and possibly advanced).
729740 channel_states
730741 . entry ( channel_id)
731- . or_insert_with ( || ChannelState {
732- config,
733- holder,
734- commitment : state,
735- } ) ;
742+ . or_insert_with ( || ChannelState :: new ( config, holder, state) ) ;
736743
737744 Ok ( FundingCreated {
738745 temporary_channel_id,
@@ -742,6 +749,39 @@ fn build_funding_created(
742749 } )
743750}
744751
752+ /// Builds a `ChannelReady` from 3 input variables (wire order).
753+ fn build_channel_ready (
754+ variables : & [ Option < Variable > ] ,
755+ inputs : & [ usize ] ,
756+ include_alias : bool ,
757+ channel_states : & mut HashMap < ChannelId , ChannelState > ,
758+ ) -> ChannelReady {
759+ let channel_id = resolve_channel_id ( variables, inputs[ 0 ] ) ;
760+ let second_per_commitment_point = resolve_pubkey ( variables, inputs[ 1 ] ) ;
761+ let short_channel_id = include_alias. then ( || resolve_short_channel_id ( variables, inputs[ 2 ] ) ) ;
762+
763+ // Record the holder's next per-commitment point from the first locally-sent
764+ // `channel_ready`'s `second_per_commitment_point`. We only do so when the
765+ // channel is tracked, the commitment number is still 0, and the point is not
766+ // yet recorded: `channel_ready` may be resent, but BOLT peers ignore
767+ // redundant ones, so recording a resend would leave us with the wrong point
768+ // and make us reject a valid received commitment signature as invalid.
769+ if let Some ( state) = channel_states. get_mut ( & channel_id)
770+ && state. commitment . commitment_number == 0
771+ {
772+ let next_point = state. next_holder_per_commitment_point_mut ( ) ;
773+ if next_point. is_none ( ) {
774+ * next_point = Some ( second_per_commitment_point) ;
775+ }
776+ }
777+
778+ ChannelReady {
779+ channel_id,
780+ second_per_commitment_point,
781+ tlvs : ChannelReadyTlvs { short_channel_id } ,
782+ }
783+ }
784+
745785/// Builds a signed `ChannelAnnouncement` from 7 input variables.
746786fn build_channel_announcement (
747787 variables : & [ Option < Variable > ] ,
@@ -2553,6 +2593,108 @@ mod tests {
25532593 ) ) ;
25542594 }
25552595
2596+ #[ test]
2597+ fn execute_build_channel_ready ( ) {
2598+ let channel_id = ChannelId :: v1_from_funding_outpoint ( OutPoint {
2599+ txid : "09b0549b35f14ee862f63bd75811c6c27963c4dea6766ec6836952ec78df1e7e"
2600+ . parse ( )
2601+ . unwrap ( ) ,
2602+ vout : 0 ,
2603+ } ) ;
2604+ let alias = ShortChannelId :: new ( 538_532 , 845 , 1 ) ;
2605+ let mock_cli = MockBitcoinCli {
2606+ utxos : vec ! [ sample_utxo( ) ] ,
2607+ change_spk : sample_change_spk ( ) ,
2608+ ..Default :: default ( )
2609+ } ;
2610+
2611+ let mut instrs = send_funding_created_and_recv_funding_signed_instructions ( ) ;
2612+ instrs. extend ( [
2613+ Instruction {
2614+ operation : Operation :: LoadShortChannelId ( alias. as_u64 ( ) ) ,
2615+ inputs : vec ! [ ] ,
2616+ } ,
2617+ Instruction {
2618+ operation : Operation :: BuildChannelReady {
2619+ include_alias : false ,
2620+ } ,
2621+ inputs : vec ! [ 17 , 1 , 18 ] ,
2622+ } ,
2623+ Instruction {
2624+ operation : Operation :: SendMessage ,
2625+ inputs : vec ! [ 19 ] ,
2626+ } ,
2627+ Instruction {
2628+ operation : Operation :: BuildChannelReady {
2629+ include_alias : true ,
2630+ } ,
2631+ inputs : vec ! [ 17 , 3 , 18 ] ,
2632+ } ,
2633+ Instruction {
2634+ operation : Operation :: SendMessage ,
2635+ inputs : vec ! [ 21 ] ,
2636+ } ,
2637+ ] ) ;
2638+
2639+ let program = Program {
2640+ instructions : instrs,
2641+ } ;
2642+
2643+ // We also need to send this `funding_signed`, since the instructions reused
2644+ // by this test expect one to be present in the executor's receive queue.
2645+ // The expected signature here was computed using LDK as the source of
2646+ // truth.
2647+ let fs_bytes = Message :: FundingSigned ( FundingSigned {
2648+ channel_id,
2649+ signature : "304402203dbf3dbf337b042a72576488c1fb019086089d8d790a47f652346cff2511b6e70220395fdf700cb82b0abfcfe8e0b7c822181f2ee72409c82c3ff8e04e36593662c7" . parse ( ) . unwrap ( ) ,
2650+ } )
2651+ . encode ( ) ;
2652+ let mut executor = Executor :: new ( MockConnection :: new ( ) , mock_cli, sample_context ( ) ) ;
2653+ executor. conn . queue_recv ( fs_bytes) ;
2654+ executor
2655+ . execute ( & program, std:: time:: Instant :: now ( ) )
2656+ . unwrap ( ) ;
2657+
2658+ // The instructions send 1 `funding_created` and 2 `channel_ready` messages.
2659+ assert_eq ! ( executor. conn. sent. len( ) , 3 ) ;
2660+
2661+ // The first channel_ready was built with include_alias = false, so it must
2662+ // not carry the short_channel_id TLV.
2663+ let cr1 = match Message :: decode ( & executor. conn . sent [ 1 ] ) . expect ( "valid message" ) {
2664+ Message :: ChannelReady ( cr) => cr,
2665+ other => panic ! ( "expected ChannelReady, got type {}" , other. msg_type( ) ) ,
2666+ } ;
2667+ let expected_pcp1 = PublicKey :: from_str (
2668+ "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb" ,
2669+ )
2670+ . unwrap ( ) ;
2671+ assert_eq ! ( cr1. channel_id, channel_id) ;
2672+ assert_eq ! ( cr1. second_per_commitment_point, expected_pcp1) ;
2673+ assert ! ( cr1. tlvs. short_channel_id. is_none( ) ) ;
2674+
2675+ // The second channel_ready was built with include_alias = true, so it must
2676+ // carry the alias SCID we loaded in its short_channel_id TLV.
2677+ let cr2 = match Message :: decode ( & executor. conn . sent [ 2 ] ) . expect ( "valid message" ) {
2678+ Message :: ChannelReady ( cr) => cr,
2679+ other => panic ! ( "expected ChannelReady, got type {}" , other. msg_type( ) ) ,
2680+ } ;
2681+ let expected_pcp2 = PublicKey :: from_str (
2682+ "030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1" ,
2683+ )
2684+ . unwrap ( ) ;
2685+ assert_eq ! ( cr2. channel_id, channel_id) ;
2686+ assert_eq ! ( cr2. second_per_commitment_point, expected_pcp2) ;
2687+ assert_eq ! ( cr2. tlvs. short_channel_id, Some ( alias) ) ;
2688+
2689+ // The holder's next per-commitment point must hold the first
2690+ // `channel_ready`'s point, not any subsequent one.
2691+ let state = executor. channel_states . get_mut ( & channel_id) . unwrap ( ) ;
2692+ assert_eq ! (
2693+ * state. next_holder_per_commitment_point( ) ,
2694+ Some ( expected_pcp1)
2695+ ) ;
2696+ }
2697+
25562698 // -- extract_field tests --
25572699
25582700 // TODO: Once we can actually construct and send accept_channel messages, it
0 commit comments