package itest import ( "fmt" "time" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lnwire" "github.com/stretchr/testify/require" ) // testCustomMessage tests sending and receiving of overridden custom message // types (within the message type range usually reserved for protocol messages) // via the send and subscribe custom message APIs. func testCustomMessage(ht *lntest.HarnessTest) { alice, bob := ht.Alice, ht.Bob var ( overrideType1 uint32 = 554 overrideType2 uint32 = 555 msgOverrideArg = "--protocol.custom-message=%v" ) // Update Alice to accept custom protocol messages with type 1 but do // not allow Bob to handle them yet. extraArgs := []string{ fmt.Sprintf(msgOverrideArg, overrideType1), } ht.RestartNodeWithExtraArgs(alice, extraArgs) // Subscribe Alice to custom messages before we send any, so that we // don't miss any. msgClient, cancel := alice.RPC.SubscribeCustomMessages() defer cancel() // Create a channel to receive custom messages on. messages := make(chan *lnrpc.CustomMessage) go func() { for { // If we fail to receive, just exit. The test should // fail elsewhere if it doesn't get a message that it // was expecting. msg, err := msgClient.Recv() if err != nil { return } // Deliver the message into our channel or exit if the // test is shutting down. select { case messages <- msg: case <-ht.Context().Done(): return } } }() // Connect alice and bob so that they can exchange messages. ht.EnsureConnected(alice, bob) // Create a custom message that is within our allowed range. msgType := uint32(lnwire.CustomTypeStart + 1) msgData := []byte{1, 2, 3} // Send it from Bob to Alice. bobMsg := &lnrpc.SendCustomMessageRequest{ Peer: alice.PubKey[:], Type: msgType, Data: msgData, } bob.RPC.SendCustomMessage(bobMsg) // Wait for Alice to receive the message. It should come through // because it is within our allowed range. select { case msg := <-messages: // Check our type and data and (sanity) check the peer we got // it from. require.Equal(ht, msgType, msg.Type, "first msg type wrong") require.Equal(ht, msgData, msg.Data, "first msg data wrong") require.Equal(ht, bob.PubKey[:], msg.Peer, "first msg "+ "peer wrong") case <-time.After(lntest.DefaultTimeout): ht.Fatalf("alice did not receive first custom message: %v", msgType) } // Try to send a message from Bob to Alice which has a message type // outside of the custom type range and assert that it fails. bobMsg = &lnrpc.SendCustomMessageRequest{ Peer: alice.PubKey[:], Type: overrideType1, Data: msgData, } _, err := bob.RPC.LN.SendCustomMessage(ht.Context(), bobMsg) require.Error(ht, err, "bob should not be able to send type 1") // Now, restart Bob with the ability to send two different custom // protocol messages. extraArgs = []string{ fmt.Sprintf(msgOverrideArg, overrideType1), fmt.Sprintf(msgOverrideArg, overrideType2), } ht.RestartNodeWithExtraArgs(bob, extraArgs) // Make sure Bob and Alice are connected after his restart. ht.EnsureConnected(alice, bob) // Send a message from Bob to Alice with a type that Bob is allowed to // send, but Alice will not handle as a custom message. bobMsg = &lnrpc.SendCustomMessageRequest{ Peer: alice.PubKey[:], Type: overrideType2, Data: msgData, } bob.RPC.SendCustomMessage(bobMsg) // Do a quick check that Alice did not receive this message in her // stream. Note that this is an instant check, so could miss the // message being received. We'll also check below that she didn't get // it, this is just a sanity check. select { case msg := <-messages: ht.Fatalf("unexpected message: %v", msg) default: } // Finally, send a custom message with a type that Bob is allowed to // send and Alice is configured to receive. bobMsg = &lnrpc.SendCustomMessageRequest{ Peer: alice.PubKey[:], Type: overrideType1, Data: msgData, } bob.RPC.SendCustomMessage(bobMsg) // Wait to receive a message from Bob. This check serves to ensure that // our message type 1 was delivered, and assert that the preceding one // was not (we could have missed it in our check above). When we // receive the second message, we know that the first one did not go // through, because we expect our messages to deliver in order. select { case msg := <-messages: // Check our type and data and (sanity) check the peer we got // it from. require.Equal(ht, overrideType1, msg.Type, "second message "+ "type") require.Equal(ht, msgData, msg.Data, "second message data") require.Equal(ht, bob.PubKey[:], msg.Peer, "second "+ "message peer") case <-time.After(lntest.DefaultTimeout): ht.Fatalf("alice did not receive second custom message") } }