1use crate::config::NodeInfo;
5use crate::pb::{hsm_server::Hsm, Empty, HsmRequest, HsmResponse, NodeConfig};
6use crate::stager;
7use anyhow::{Context, Result};
8use futures::TryFutureExt;
9use log::{debug, info, trace, warn};
10use std::path::PathBuf;
11use std::sync::Arc;
12use tonic::{Request, Response, Status};
13
14#[derive(Clone)]
18pub struct StagingHsmServer {
19 stage: Arc<stager::Stage>,
20 hsmd_sock_path: PathBuf,
21 node_info: NodeInfo,
22 node_config: NodeConfig,
23}
24
25impl StagingHsmServer {
26 pub fn new(
27 hsmd_sock_path: PathBuf,
28 stage: Arc<stager::Stage>,
29 node_info: NodeInfo,
30 node_config: NodeConfig,
31 ) -> StagingHsmServer {
32 StagingHsmServer {
33 stage,
34 hsmd_sock_path,
35 node_info,
36 node_config,
37 }
38 }
39
40 fn find_canned_response(&self, msg: &Vec<u8>) -> Option<Vec<u8>> {
42 self.node_config
43 .startupmsgs
44 .iter()
45 .find(|m| &m.request == msg)
46 .map(|m| m.response.clone())
47 }
48}
49
50#[tonic::async_trait]
51impl Hsm for StagingHsmServer {
52 async fn request(&self, request: Request<HsmRequest>) -> Result<Response<HsmResponse>, Status> {
53 let req = request.into_inner();
54 debug!("Received request from hsmproxy: {:?}", req);
55
56 if let Some(response) = self.find_canned_response(&req.raw) {
58 debug!(
59 "Returning canned response={:?} for request={:?}",
60 response, req.raw
61 );
62 return Ok(Response::new(HsmResponse {
63 request_id: req.request_id,
64 raw: response,
65 signer_state: Vec::new(),
66 error: "".into(),
67 }));
68 } else if req.get_type() == 11 {
69 debug!("Returning stashed init msg: {:?}", self.node_info.initmsg);
70 return Ok(Response::new(HsmResponse {
71 request_id: req.request_id,
72 raw: self.node_info.initmsg.clone(),
73 signer_state: Vec::new(), error: "".into(),
75 }));
76 } else if req.get_type() == 33 {
77 debug!("Returning stashed dev-memleak response");
78 return Ok(Response::new(HsmResponse {
79 request_id: req.request_id,
80 raw: vec![0, 133, 0],
81 signer_state: Vec::new(), error: "".into(),
83 }));
84 }
85
86 let mut chan = match self.stage.send(req).await {
87 Err(e) => {
88 return Err(Status::unknown(format!(
89 "Error while queuing request from node: {:?}",
90 e
91 )))
92 }
93 Ok(c) => c,
94 };
95
96 let res = match chan.recv().await {
97 None => {
98 return Err(Status::unknown(format!(
99 "Channel closed while waiting for response",
100 )))
101 }
102 Some(r) => r,
103 };
104
105 Ok(Response::new(res))
106 }
107
108 async fn ping(&self, _request: Request<Empty>) -> Result<Response<Empty>, Status> {
109 trace!("Got a ping");
110 Ok(Response::new(Empty::default()))
111 }
112}
113
114impl StagingHsmServer {
115 pub async fn run(self) -> Result<()> {
116 let mut path = std::path::PathBuf::new();
117 path.push(std::env::current_dir().unwrap());
118 path.push(&self.hsmd_sock_path);
119 info!(
120 "Configuring hsmd interface to listen on {}",
121 path.to_str().unwrap()
122 );
123 std::fs::create_dir_all(std::path::Path::new(&path).parent().unwrap())?;
124
125 if path.exists() {
126 warn!(
127 "Socket path {} already exists, deleting",
128 path.to_string_lossy()
129 );
130 std::fs::remove_file(&path).context("removing stale hsmd socket")?;
131 }
132 let incoming = {
133 let uds = tokio::net::UnixListener::bind(path)?;
134
135 async_stream::stream! {
136 loop {
137 yield uds.accept().map_ok(|(st, _)| crate::unix::UnixStream(st)).await;
138 }
139 }
140 };
141
142 info!("HSM server interface starting.");
143 tonic::transport::Server::builder()
144 .add_service(crate::pb::hsm_server::HsmServer::new(self))
145 .serve_with_incoming(incoming)
146 .await
147 .context("serving HsmServer interface")
148 }
149}