broker: cache preapproves

largely copied from
https://gitlab.com/lightning-signer/validating-lightning-signer/-/merge_requests/564
This commit is contained in:
irriden
2023-11-28 01:53:59 +00:00
parent 226c35b518
commit be2917b045
3 changed files with 90 additions and 6 deletions

12
broker/Cargo.lock generated
View File

@@ -1687,6 +1687,15 @@ dependencies = [
"hashbrown 0.14.0", "hashbrown 0.14.0",
] ]
[[package]]
name = "lru"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7"
dependencies = [
"hashbrown 0.14.0",
]
[[package]] [[package]]
name = "lss-connector" name = "lss-connector"
version = "0.1.0" version = "0.1.0"
@@ -3316,6 +3325,7 @@ dependencies = [
"fern", "fern",
"hex", "hex",
"log", "log",
"lru 0.12.1",
"lss-connector", "lss-connector",
"once_cell", "once_cell",
"pretty_env_logger", "pretty_env_logger",
@@ -4149,7 +4159,7 @@ dependencies = [
"hyper", "hyper",
"lightning-storage-server", "lightning-storage-server",
"log", "log",
"lru", "lru 0.11.0",
"nix", "nix",
"prost", "prost",
"serde", "serde",

View File

@@ -17,6 +17,7 @@ confy = "0.4.0"
fern = { version = "0.6", features = ["colored"] } fern = { version = "0.6", features = ["colored"] }
hex = "0.4.3" hex = "0.4.3"
log = "0.4" log = "0.4"
lru = "0.12.1"
once_cell = "1.12.0" once_cell = "1.12.0"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
rocket = { version = "0.5.0-rc.2", features = ["json"] } rocket = { version = "0.5.0-rc.2", features = ["json"] }

View File

@@ -4,11 +4,24 @@ use crate::conn::{ChannelRequest, LssReq};
use crate::handle::handle_message; use crate::handle::handle_message;
use crate::secp256k1::PublicKey; use crate::secp256k1::PublicKey;
use log::*; use log::*;
use lru::LruCache;
use rocket::tokio::sync::mpsc; use rocket::tokio::sync::mpsc;
use sphinx_signer::lightning_signer::bitcoin::hashes::{sha256::Hash as Sha256Hash, Hash};
use std::num::NonZeroUsize;
use std::thread; use std::thread;
use std::time::Duration;
use std::time::SystemTime;
use vls_protocol::{msgs, msgs::Message, Error, Result}; use vls_protocol::{msgs, msgs::Message, Error, Result};
use vls_proxy::client::Client; use vls_proxy::client::Client;
const PREAPPROVE_CACHE_TTL: Duration = Duration::from_secs(60);
const PREAPPROVE_CACHE_SIZE: usize = 6;
struct PreapprovalCacheEntry {
tstamp: SystemTime,
reply_bytes: Vec<u8>,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ClientId { pub struct ClientId {
pub peer_id: PublicKey, pub peer_id: PublicKey,
@@ -22,6 +35,7 @@ pub struct SignerLoop<C: 'static + Client> {
vls_tx: mpsc::Sender<ChannelRequest>, vls_tx: mpsc::Sender<ChannelRequest>,
lss_tx: mpsc::Sender<LssReq>, lss_tx: mpsc::Sender<LssReq>,
client_id: Option<ClientId>, client_id: Option<ClientId>,
preapproval_cache: LruCache<Sha256Hash, PreapprovalCacheEntry>,
} }
impl<C: 'static + Client> SignerLoop<C> { impl<C: 'static + Client> SignerLoop<C> {
@@ -32,12 +46,14 @@ impl<C: 'static + Client> SignerLoop<C> {
lss_tx: mpsc::Sender<LssReq>, lss_tx: mpsc::Sender<LssReq>,
) -> Self { ) -> Self {
let log_prefix = format!("{}/{}", std::process::id(), client.id()); let log_prefix = format!("{}/{}", std::process::id(), client.id());
let preapproval_cache = LruCache::new(NonZeroUsize::new(PREAPPROVE_CACHE_SIZE).unwrap());
Self { Self {
client, client,
log_prefix, log_prefix,
vls_tx, vls_tx,
lss_tx, lss_tx,
client_id: None, client_id: None,
preapproval_cache,
} }
} }
@@ -49,12 +65,14 @@ impl<C: 'static + Client> SignerLoop<C> {
client_id: ClientId, client_id: ClientId,
) -> Self { ) -> Self {
let log_prefix = format!("{}/{}", std::process::id(), client.id()); let log_prefix = format!("{}/{}", std::process::id(), client.id());
let preapproval_cache = LruCache::new(NonZeroUsize::new(PREAPPROVE_CACHE_SIZE).unwrap());
Self { Self {
client, client,
log_prefix, log_prefix,
vls_tx, vls_tx,
lss_tx, lss_tx,
client_id: Some(client_id), client_id: Some(client_id),
preapproval_cache,
} }
} }
@@ -98,7 +116,7 @@ impl<C: 'static + Client> SignerLoop<C> {
self.client.write(reply)?; self.client.write(reply)?;
} }
msg => { msg => {
if let Message::HsmdInit(m) = msg { if let Message::HsmdInit(ref m) = msg {
if let Some(net) = network { if let Some(net) = network {
if ChainHash::using_genesis_block(net).as_bytes() if ChainHash::using_genesis_block(net).as_bytes()
!= m.chain_params.as_ref() != m.chain_params.as_ref()
@@ -109,10 +127,65 @@ impl<C: 'static + Client> SignerLoop<C> {
log::error!("No Network provided"); log::error!("No Network provided");
} }
} }
let reply = // check if we got the same preapprove message less than PREAPPROVE_CACHE_TTL seconds ago
handle_message(&self.client_id, raw_msg, &self.vls_tx, &self.lss_tx); if let Message::PreapproveInvoice(_) | Message::PreapproveKeysend(_) = msg {
// Write the reply to CLN let now = SystemTime::now();
let req_hash = Sha256Hash::hash(&raw_msg);
if let Some(entry) = self.preapproval_cache.get(&req_hash) {
let age = now.duration_since(entry.tstamp).expect("age");
if age < PREAPPROVE_CACHE_TTL {
debug!("{} found in preapproval cache", self.log_prefix);
let reply = entry.reply_bytes.clone();
self.client.write_vec(reply)?; self.client.write_vec(reply)?;
continue;
}
}
}
let reply_bytes = handle_message(
&self.client_id,
raw_msg.clone(),
&self.vls_tx,
&self.lss_tx,
);
// post signer response processing
let reply = msgs::from_vec(reply_bytes.clone()).expect("parse reply failed");
match reply {
// did we just preapprove a keysend ? if so add it to the cache
Message::PreapproveKeysendReply(pkr) => {
if pkr.result {
debug!("{} adding keysend to preapproval cache", self.log_prefix);
let now = SystemTime::now();
let req_hash = Sha256Hash::hash(&raw_msg);
self.preapproval_cache.put(
req_hash,
PreapprovalCacheEntry {
tstamp: now,
reply_bytes: reply_bytes.clone(),
},
);
}
}
// did we just preapprove an invoice ? if so add it to the cache
Message::PreapproveInvoiceReply(pir) => {
if pir.result {
debug!("{} adding invoice to preapproval cache", self.log_prefix);
let now = SystemTime::now();
let req_hash = Sha256Hash::hash(&raw_msg);
self.preapproval_cache.put(
req_hash,
PreapprovalCacheEntry {
tstamp: now,
reply_bytes: reply_bytes.clone(),
},
);
}
}
_ => {} // for future messages needing post signer response processing
}
// write the reply to CLN
self.client.write_vec(reply_bytes)?;
} }
} }
} }