Skip to content

Commit

Permalink
Merge pull request #43 from stakwork/kvv
Browse files Browse the repository at this point in the history
Kvv
  • Loading branch information
Evanfeenstra authored Sep 12, 2023
2 parents 8d02cde + 3289c70 commit 5de0f94
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 52 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ teststore2
.env
error.log
vls_mqtt_data
questions.md
questions.md
redb
12 changes: 7 additions & 5 deletions lss-connector/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ log = "0.4"
anyhow = { version = "1", default-features = false }
secp256k1 = { version = "0.24.0", default-features = false, features = ["bitcoin_hashes"] }
# broker libs
# lightning-storage-server = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "c4e91b17f94c0c521d8af941e3c258f573378af1", optional = true }
# vls-frontend = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "c4e91b17f94c0c521d8af941e3c258f573378af1", optional = true }
lightning-storage-server = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "4b2a00975a5c7ccdbcedf6dcf44728b90b296064", optional = true }
vls-frontend = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "4b2a00975a5c7ccdbcedf6dcf44728b90b296064", optional = true }
vls-protocol-signer = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "4b2a00975a5c7ccdbcedf6dcf44728b90b296064", default-features = false, features = ["secp-lowmemory"] }

# lightning-storage-server = { path = "../../vls/lightning-storage-server", optional = true }
# vls-frontend = { path = "../../vls/vls-frontend", optional = true }
vls-protocol-signer = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false, features = ["secp-lowmemory"] }
# vls-protocol-signer = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false, features = ["secp-lowmemory"] }
# vls-protocol-signer = { path = "../../vls/vls-protocol-signer", default-features = false, features = ["secp-lowmemory"] }
lightning-storage-server = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", optional = true }
vls-frontend = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", optional = true }
# lightning-storage-server = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", optional = true }
# vls-frontend = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", optional = true }
tokio = { version = "1.27", features = ["macros", "rt-multi-thread"], optional = true }

[[bin]]
Expand Down
38 changes: 26 additions & 12 deletions lss-connector/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use crate::msgs::*;
use anyhow::{anyhow, Result};
use lightning_signer::persist::ExternalPersistHelper;
use lightning_signer::persist::Mutations;
use lightning_signer::prelude::Mutex;
use lightning_signer::Arc;
use secp256k1::PublicKey;
use std::collections::BTreeMap;
use vls_protocol_signer::handler::{RootHandler, RootHandlerBuilder};
Expand Down Expand Up @@ -91,15 +89,18 @@ impl LssSigner {
state: Option<BTreeMap<String, (u64, Vec<u8>)>>,
) -> Result<(RootHandler, Vec<u8>)> {
// let helper = self.helper.lock().unwrap();
let has_muts = &c.muts.len() > &0;
let muts = Mutations::from_vec(c.muts);
let success = self.helper.check_hmac(
&muts,
c.server_hmac
.ok_or(anyhow!("build_with_lss: server_hmac is none"))?
.to_vec(),
);
if !success {
return Err(anyhow!("invalid server hmac"));
if has_muts {
let success = self.helper.check_hmac(
&muts,
c.server_hmac
.ok_or(anyhow!("build_with_lss: server_hmac is none"))?
.to_vec(),
);
if !success {
return Err(anyhow!("invalid server hmac"));
}
}

let mut sta = BTreeMap::new(); // state.unwrap_or_default();
Expand All @@ -111,11 +112,24 @@ impl LssSigner {
sta.insert(key, version_value);
}
}
let st = Arc::new(Mutex::new(sta));
let handler_builder = handler_builder.lss_state(st);

let muts: Vec<_> = sta
.iter()
.map(|(k, (v, vv))| (k.clone(), (*v, vv.clone())))
.collect();
let persister = handler_builder.persister();
persister
.put_batch_unlogged(Mutations::from_vec(muts))
.expect("put_batch_unlogged");

// let st = Arc::new(Mutex::new(sta));
// let handler_builder = handler_builder.lss_state(st);
let (handler, muts) = handler_builder
.build()
.map_err(|_| anyhow!("failed to build"))?;
persister
.commit()
.map_err(|_| anyhow!("failed to commit"))?;
let client_hmac = self.helper.client_hmac(&muts);

let res = Response::Created(SignerMutations {
Expand Down
18 changes: 8 additions & 10 deletions signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,21 @@ rand = { version = "0.8", default-features = false }
serde = { version = "1.0.168", default-features = false, features = ["derive"] }
hex = { version = "0.4.3", default-features = false }
anyhow = { version = "1", default-features = false }
fsdb = { git = "https://github.com/Evanfeenstra/fsdb.git", rev = "78e174941ea0a373c2bb0ef518317b40ac80abf9", optional = true }
fsdb = { git = "https://github.com/Evanfeenstra/fsdb.git", rev = "13f66653ec3c14280fc8ab330108c710c1df3006", optional = true }
thiserror = "1.0.44"
# vls
# vls-protocol-signer = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "c4e91b17f94c0c521d8af941e3c258f573378af1", default-features = false, features = ["secp-lowmemory"] }
# vls-protocol = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "c4e91b17f94c0c521d8af941e3c258f573378af1", default-features = false }
# vls-persist = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "c4e91b17f94c0c521d8af941e3c258f573378af1", default-features = false, features = ["memo"], optional = true }
vls-protocol-signer = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "4b2a00975a5c7ccdbcedf6dcf44728b90b296064", default-features = false, features = ["secp-lowmemory"] }
vls-protocol = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "4b2a00975a5c7ccdbcedf6dcf44728b90b296064", default-features = false }
vls-persist = { git = "https://gitlab.com/lightning-signer/validating-lightning-signer.git", rev = "4b2a00975a5c7ccdbcedf6dcf44728b90b296064", default-features = false, features = ["kvv"], optional = true }
# local
# vls-protocol-signer = { path = "../../vls/vls-protocol-signer", default-features = false, features = ["secp-lowmemory"] }
# vls-protocol = { path = "../../vls/vls-protocol" }
# vls-persist = { path = "../../vls/vls-persist", default-features = false, features = ["memo"], optional = true }
# vls-persist = { path = "../../vls/vls-persist", default-features = false, features = ["kvv"], optional = true }
# evanfeenstra1
vls-protocol-signer = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false, features = ["secp-lowmemory"] }
vls-protocol = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false }
vls-persist = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false, features = ["memo"], optional = true }
# vls-protocol-signer = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false, features = ["secp-lowmemory"] }
# vls-protocol = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false }
# vls-persist = { git = "https://gitlab.com/evanfeenstra1/validating-lightning-signer.git", rev = "dbaeb29b51f399ce993923cca3ef218b2029cd11", default-features = false, features = ["kvv"], optional = true }

[dev-dependencies]
simple_logger = "4.2.0"
bech32 = "0.9.1"
lightning-invoice = "0.24.0"
# lightning-invoice = { path = "../../../evanf/rust-lightning/lightning-invoice" }
197 changes: 197 additions & 0 deletions signer/src/kvv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use fsdb::{AnyBucket, Fsdb};
use lightning_signer::persist::Error;
use lightning_signer::SendSync;
use log::error;
use std::collections::BTreeMap;
use std::convert::TryInto;
pub use vls_persist::kvv::{cloud::CloudKVVStore, KVVPersister, KVVStore, KVV};
use vls_protocol_signer::lightning_signer;
extern crate alloc;
use std::sync::Mutex;

/// A key-version-value store backed by fsdb
pub struct FsKVVStore {
db: AnyBucket<Vec<u8>>,
versions: Mutex<BTreeMap<String, u64>>,
}

/// An iterator over a KVVStore range
pub struct Iter(alloc::vec::IntoIter<KVV>);

impl Iterator for Iter {
type Item = KVV;

fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}

impl SendSync for FsKVVStore {}

impl FsKVVStore {
pub fn new(path: &str, maxsize: Option<usize>) -> KVVPersister<Self> {
let db = Fsdb::new(path).expect("could not create db");
let bucket = db
.any_bucket::<Vec<u8>>(maxsize)
.expect("could not create bucket");

// seed the initial versions store
let mut versions = BTreeMap::new();
let fulllist = bucket.list_all().expect("could not list bucket");
for path in fulllist {
match bucket.get(&path) {
Ok(item) => {
let (version, _) = Self::decode_vv(&item);
versions.insert(path, version);
}
Err(e) => log::error!("failed to seed version {:?}", e),
}
}

KVVPersister(Self {
db: bucket,
versions: Mutex::new(versions),
})
}
fn decode_vv(vv: &[u8]) -> (u64, Vec<u8>) {
let version = u64::from_be_bytes(vv[..8].try_into().unwrap());
let value = vv[8..].to_vec();
(version, value)
}
fn encode_vv(version: u64, value: &[u8]) -> Vec<u8> {
let mut vv = Vec::with_capacity(value.len() + 8);
vv.extend_from_slice(&version.to_be_bytes());
vv.extend_from_slice(value);
vv
}
fn check_version(
&self,
key: &str,
version: u64,
prev: u64,
value: &[u8],
) -> Result<Vec<u8>, Error> {
let vv = Self::encode_vv(version, value);
if version < prev {
error!("version mismatch for {}: {} < {}", key, version, prev);
// version cannot go backwards
return Err(Error::VersionMismatch);
} else if version == prev {
// if same version, value must not have changed
if let Ok(existing) = self.db.get_raw(key) {
if existing != vv {
error!("value mismatch for {}: {}", key, version);
return Err(Error::VersionMismatch);
}
}
return Ok(vv);
}

Ok(vv)
}
}

impl KVVStore for FsKVVStore {
type Iter = Iter;

fn put(&self, key: &str, value: &[u8]) -> Result<(), Error> {
let v = self
.versions
.lock()
.unwrap()
.get(key)
.map(|v| v + 1)
.unwrap_or(0);
self.put_with_version(key, v, value)
}

fn put_with_version(&self, key: &str, version: u64, value: &[u8]) -> Result<(), Error> {
let mut vers = self.versions.lock().unwrap();
let vv = match vers.get(key) {
Some(prev) => self.check_version(key, version, *prev, value)?,
None => Self::encode_vv(version, value),
};
vers.insert(key.to_string(), version);
self.db
.put_raw(key, &vv)
.map_err(|_| Error::Internal("could not put".to_string()))?;
Ok(())
}
fn put_batch(&self, kvvs: &[&KVV]) -> Result<(), Error> {
let mut found_version_mismatch = false;
let mut staged_vvs: Vec<(String, u64, Vec<u8>)> = Vec::new();

let mut vers = self.versions.lock().unwrap();
for kvv in kvvs.into_iter() {
let key = kvv.0.clone();
let ver = kvv.1 .0;
let val = &kvv.1 .1;
match vers.get(&key) {
Some(prev) => match self.check_version(&key, ver, *prev, val) {
Ok(vv) => staged_vvs.push((key.clone(), ver, vv)),
Err(_) => found_version_mismatch = true,
},
None => {
let vv = Self::encode_vv(ver, val);
staged_vvs.push((key.clone(), ver, vv));
}
}
}
if found_version_mismatch {
// abort the transaction
return Err(Error::VersionMismatch);
} else {
for vv in staged_vvs {
self.db
.put_raw(&vv.0, &vv.2)
.map_err(|_| Error::Internal("could not put".to_string()))?;
vers.insert(vv.0, vv.1);
}
}
Ok(())
}
fn get(&self, key: &str) -> Result<Option<(u64, Vec<u8>)>, Error> {
if let Ok(vv) = self.db.get_raw(key) {
let (version, value) = Self::decode_vv(&vv);
Ok(Some((version, value)))
} else {
Ok(None)
}
}
fn get_version(&self, key: &str) -> Result<Option<u64>, Error> {
Ok(self.versions.lock().unwrap().get(key).copied())
}
fn get_prefix(&self, prefix: &str) -> Result<Self::Iter, Error> {
let items = self
.db
.list(prefix)
.map_err(|_| Error::Internal("could not list".to_string()))?;
let mut result = Vec::new();
for mut item in items {
if item.starts_with("/") {
item.remove(0);
}
let key = format!("{}/{}", prefix, item);
log::info!("LIST RES {:?}", key);
let vv = self
.db
.get(&key)
.map_err(|_| Error::Internal("could not get".to_string()))?;
let (version, value) = Self::decode_vv(&vv);
result.push(KVV(key, (version, value)));
}
Ok(Iter(result.into_iter()))
}
fn delete(&self, key: &str) -> Result<(), Error> {
Ok(self
.db
.remove(key)
.map_err(|_| Error::Internal("could not remove".to_string()))?)
}
fn clear_database(&self) -> Result<(), Error> {
Ok(self
.db
.clear()
.map_err(|_| Error::Internal("could not clear".to_string()))?)
}
}
3 changes: 3 additions & 0 deletions signer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub mod policy;
#[cfg(feature = "fspersist")]
pub mod persist;

#[cfg(feature = "fspersist")]
pub mod kvv;

pub use lss_connector;
pub use sphinx_glyph;
pub use vls_protocol;
Expand Down
Loading

0 comments on commit 5de0f94

Please sign in to comment.