lsp_plugin: add u64 getter and setter to tlvs
What changed, and why it matters
This commit adds ordinary helper functions for reading and writing 64-bit unsigned integers inside a type-length-value (TLV) data structure used by a Lightning Network plugin. It is a straightforward feature addition with no visible security bug or fix.
No security action required; review as normal code-quality/feature addition.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces set_u64() and get_u64() methods on TlvStream in plugins/lsps-plugin/src/lsps2/cln.rs, mirroring the existing set_tu64()/get_tu64() helpers but using fixed 8-byte big-endian encoding instead of variable-length truncated encoding. Unit tests verify insertion, overwrite, canonical ordering, and missing-record behavior. No existing behavior is changed, and no vulnerability is addressed in the diff.
Changed components
plugins/lsps-plugin/src/lsps2/cln.rsInspect captured patch +71 / −0
diff --git a/plugins/lsps-plugin/src/lsps2/cln.rs b/plugins/lsps-plugin/src/lsps2/cln.rs
index 6e3d6d23..fcda49f7 100644
--- a/plugins/lsps-plugin/src/lsps2/cln.rs
+++ b/plugins/lsps-plugin/src/lsps2/cln.rs
@@ -324,6 +324,32 @@ pub mod tlv {
Ok(None)
}
}
+
+ /// Insert or override a `u64` value for `type_` (keeps cannonical TLV
+ /// order).
+ pub fn set_u64(&mut self, type_: u64, value: u64) {
+ let enc = value.to_be_bytes().to_vec();
+ if let Some(rec) = self.0.iter_mut().find(|r| r.type_ == type_) {
+ rec.value = enc;
+ } else {
+ self.0.push(TlvRecord { type_, value: enc });
+ self.0.sort_by_key(|r| r.type_);
+ }
+ }
+
+ /// Read a `u64` if present.Returns Ok(None) if the type isn't present.
+ pub fn get_u64(&self, type_: u64) -> Result<Option<u64>, TlvError> {
+ if let Some(rec) = self.0.iter().find(|r| r.type_ == type_) {
+ let value = u64::from_be_bytes(
+ rec.value[..]
+ .try_into()
+ .map_err(|e| TlvError::Other(format!("failed not decode to u64: {e}")))?,
+ );
+ Ok(Some(value))
+ } else {
+ Ok(None)
+ }
+ }
}
impl Serialize for TlvStream {
@@ -622,6 +648,44 @@ pub mod tlv {
);
}
+ #[test]
+ fn set_and_get_u64_basic() -> Result<()> {
+ let mut s = TlvStream::default();
+ s.set_u64(42, 123456789);
+ assert_eq!(s.get_u64(42)?, Some(123456789));
+ Ok(())
+ }
+
+ #[test]
+ fn set_u64_overwrite_keeps_order() -> Result<()> {
+ let mut s = TlvStream(vec![
+ TlvRecord {
+ type_: 1,
+ value: vec![0xaa],
+ },
+ TlvRecord {
+ type_: 10,
+ value: vec![0xbb],
+ },
+ ]);
+
+ // insert between 1 and 10
+ s.set_u64(5, 7);
+ assert_eq!(
+ s.0.iter().map(|r| r.type_).collect::<Vec<_>>(),
+ vec![1, 5, 10]
+ );
+ assert_eq!(s.get_u64(5)?, Some(7));
+
+ // overwrite existing 5 (no duplicate, order preserved)
+ s.set_u64(5, 9);
+ let types: Vec<u64> = s.0.iter().map(|r| r.type_).collect();
+ assert_eq!(types, vec![1, 5, 10]);
+ assert_eq!(s.0.iter().filter(|r| r.type_ == 5).count(), 1);
+ assert_eq!(s.get_u64(5)?, Some(9));
+ Ok(())
+ }
+
#[test]
fn set_and_get_tu64_basic() -> Result<()> {
let mut s = TlvStream::default();
@@ -630,6 +694,13 @@ pub mod tlv {
Ok(())
}
+ #[test]
+ fn get_u64_missing_returns_none() -> Result<()> {
+ let s = TlvStream::default();
+ assert_eq!(s.get_u64(999)?, None);
+ Ok(())
+ }
+
#[test]
fn set_tu64_overwrite_keeps_order() -> Result<()> {
let mut s = TlvStream(vec![
Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.