diff --git a/CHANGELOG.md b/CHANGELOG.md index bc81ab806..18e3105d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Fixed + + - Fixed `signmessage` hanging forever and blocking all subsequent signing operations. The signer refuses `SIGN_MESSAGE` requests by design, so the node now rejects the RPC with an `Unimplemented` ("not supported") error instead of forwarding it to the serial hsmd queue. ([#739](https://github.com/Blockstream/greenlight/issues/739)) + ## [0.4.0] - 2026-05-21 ### Fixed diff --git a/libs/gl-plugin/src/node/wrapper.rs b/libs/gl-plugin/src/node/wrapper.rs index 6c573daea..cce884150 100644 --- a/libs/gl-plugin/src/node/wrapper.rs +++ b/libs/gl-plugin/src/node/wrapper.rs @@ -498,11 +498,22 @@ impl Node for WrappedNodeServer { self.inner.set_channel(r).await } + /// `signmessage` is not part of the API we support: the signer + /// refuses `SIGN_MESSAGE` (hsmd type 23) by design, since we use + /// that message to attest TLS certificates. Forwarding the call to + /// the node would enqueue an hsmd request that never gets a + /// response, and since hsmd is a serial queue that blocks all + /// subsequent signing operations until the node restarts. We + /// therefore reject the call here, before it can reach hsmd. async fn sign_message( &self, - r: Request, + _r: Request, ) -> Result, Status> { - self.inner.sign_message(r).await + Err(Status::unimplemented( + "signmessage is not supported by Greenlight: the signer \ + refuses to sign arbitrary messages, so the call can never \ + complete.", + )) } async fn stop( diff --git a/libs/gl-testing/tests/test_node.py b/libs/gl-testing/tests/test_node.py index 02c4f4ec8..e4afd0c2d 100644 --- a/libs/gl-testing/tests/test_node.py +++ b/libs/gl-testing/tests/test_node.py @@ -52,6 +52,34 @@ def test_node_signer(clients, executor): h.shutdown() +def test_node_signmessage_rejected(clients): + """`signmessage` is rejected outright and does not wedge the node. + + The signer refuses `SIGN_MESSAGE` (hsmd type 23) by design, so + forwarding the RPC to the node would leave a request pending in the + serial hsmd queue forever, blocking all subsequent signing + operations. + """ + c = clients.new() + c.register(configure=True) + n = c.node() + h = c.signer().run_in_thread() + + req = clnpb.SignmessageRequest(message="hello world").SerializeToString() + with pytest.raises(ValueError, match="not supported by Greenlight"): + n.inner.call("/cln.Node/SignMessage", req) + + # The rejection must not have consumed a slot in the hsmd queue, + # so signing operations still work afterwards. + inv = n.invoice( + label="test", + amount_msat=clnpb.AmountOrAny(amount=clnpb.Amount(msat=42000)), + description="desc", + ) + assert inv.bolt11 + h.shutdown() + + @pytest.mark.skip(reason="routehints seem to be missing in regtest") def test_node_network(node_factory, clients, bitcoind): """Setup a small network and check that we can send/receive payments.