use crate::chain::tracker::{ChainTracker, ListenSlot};
use alloc::sync::Arc;
use bitcoin::hashes::sha256::Hash as Sha256Hash;
use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine};
use bitcoin::secp256k1::PublicKey;
use bitcoin::OutPoint;
use core::fmt::Debug;
use core::ops::Index;
use lightning::sign::EntropySource;
use crate::channel::{Channel, ChannelId, ChannelStub};
use crate::monitor::{ChainMonitor, State as ChainMonitorState};
use crate::node::{NodeConfig, NodeState};
use crate::policy::validator::ValidatorFactory;
use crate::prelude::*;
pub mod model;
#[derive(Clone)]
#[must_use]
pub struct Mutations(Vec<(String, (u64, Vec<u8>))>);
impl Mutations {
pub fn new() -> Self {
Mutations(vec![])
}
pub fn from_vec(mutations: Vec<(String, (u64, Vec<u8>))>) -> Self {
Mutations(mutations)
}
pub fn add(&mut self, key: String, version: u64, value: Vec<u8>) {
self.0.push((key, (version, value)));
}
pub fn inner(&self) -> &Vec<(String, (u64, Vec<u8>))> {
&self.0
}
pub fn into_inner(self) -> Vec<(String, (u64, Vec<u8>))> {
self.0
}
pub fn iter(&self) -> impl Iterator<Item = &(String, (u64, Vec<u8>))> {
self.0.iter()
}
pub fn into_iter(self) -> impl Iterator<Item = (String, (u64, Vec<u8>))> {
self.0.into_iter()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl Index<usize> for Mutations {
type Output = (String, (u64, Vec<u8>));
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl Debug for Mutations {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_list()
.entries(self.0.iter().map(|(k, v)| (k.clone(), (&v.0, DebugBytes(&v.1[..])))))
.finish()
}
}
#[derive(Clone, Debug)]
pub enum Error {
Unavailable(String),
NotFound(String),
AlreadyExists(String),
Internal(String),
VersionMismatch,
SerdeError(String),
}
pub struct ChainTrackerListenerEntry(pub OutPoint, pub (ChainMonitorState, ListenSlot));
pub type SignerId = [u8; 16];
pub trait Persist: SendSync {
fn enter(&self) -> Result<(), Error> {
Ok(())
}
fn prepare(&self) -> Mutations {
Mutations::new()
}
fn commit(&self) -> Result<(), Error> {
Ok(())
}
fn put_batch_unlogged(&self, _m: Mutations) -> Result<(), Error> {
unimplemented!("put_batch_unlogged is only implemented for KVV persisters")
}
fn new_node(
&self,
node_id: &PublicKey,
config: &NodeConfig,
state: &NodeState,
) -> Result<(), Error>;
fn update_node(&self, node_id: &PublicKey, state: &NodeState) -> Result<(), Error>;
fn delete_node(&self, node_id: &PublicKey) -> Result<(), Error>;
fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), Error>;
fn delete_channel(&self, node_id: &PublicKey, channel: &ChannelId) -> Result<(), Error>;
fn new_tracker(
&self,
node_id: &PublicKey,
tracker: &ChainTracker<ChainMonitor>,
) -> Result<(), Error>;
fn update_tracker(
&self,
node_id: &PublicKey,
tracker: &ChainTracker<ChainMonitor>,
) -> Result<(), Error>;
fn get_tracker(
&self,
node_id: PublicKey,
validator_factory: Arc<dyn ValidatorFactory>,
) -> Result<(ChainTracker<ChainMonitor>, Vec<ChainTrackerListenerEntry>), Error>;
fn update_channel(&self, node_id: &PublicKey, channel: &Channel) -> Result<(), Error>;
fn get_channel(
&self,
node_id: &PublicKey,
channel_id: &ChannelId,
) -> Result<model::ChannelEntry, Error>;
fn get_node_channels(
&self,
node_id: &PublicKey,
) -> Result<Vec<(ChannelId, model::ChannelEntry)>, Error>;
fn update_node_allowlist(
&self,
node_id: &PublicKey,
allowlist: Vec<String>,
) -> Result<(), Error>;
fn get_node_allowlist(&self, node_id: &PublicKey) -> Result<Vec<String>, Error>;
fn get_nodes(&self) -> Result<Vec<(PublicKey, model::NodeEntry)>, Error>;
fn clear_database(&self) -> Result<(), Error>;
fn on_initial_restore(&self) -> bool {
false
}
fn recovery_required(&self) -> bool {
false
}
fn signer_id(&self) -> SignerId;
}
pub struct DummyPersister;
impl SendSync for DummyPersister {}
#[allow(unused_variables)]
impl Persist for DummyPersister {
fn new_node(
&self,
node_id: &PublicKey,
config: &NodeConfig,
state: &NodeState,
) -> Result<(), Error> {
Ok(())
}
fn update_node(&self, node_id: &PublicKey, state: &NodeState) -> Result<(), Error> {
Ok(())
}
fn delete_node(&self, node_id: &PublicKey) -> Result<(), Error> {
Ok(())
}
fn new_channel(&self, node_id: &PublicKey, stub: &ChannelStub) -> Result<(), Error> {
Ok(())
}
fn delete_channel(&self, node_id: &PublicKey, channel_id: &ChannelId) -> Result<(), Error> {
Ok(())
}
fn new_tracker(
&self,
node_id: &PublicKey,
tracker: &ChainTracker<ChainMonitor>,
) -> Result<(), Error> {
Ok(())
}
fn update_tracker(
&self,
node_id: &PublicKey,
tracker: &ChainTracker<ChainMonitor>,
) -> Result<(), Error> {
Ok(())
}
fn get_tracker(
&self,
node_id: PublicKey,
validator_factory: Arc<dyn ValidatorFactory>,
) -> Result<(ChainTracker<ChainMonitor>, Vec<ChainTrackerListenerEntry>), Error> {
Err(Error::Internal(format!("get_tracker unimplemented")))
}
fn update_channel(&self, node_id: &PublicKey, channel: &Channel) -> Result<(), Error> {
Ok(())
}
fn get_channel(
&self,
node_id: &PublicKey,
channel_id: &ChannelId,
) -> Result<model::ChannelEntry, Error> {
Err(Error::Internal(format!("get_channel unimplemented")))
}
fn get_node_channels(
&self,
node_id: &PublicKey,
) -> Result<Vec<(ChannelId, model::ChannelEntry)>, Error> {
Ok(Vec::new())
}
fn update_node_allowlist(
&self,
node_id: &PublicKey,
allowlist: Vec<String>,
) -> Result<(), Error> {
Ok(())
}
fn get_node_allowlist(&self, node_id: &PublicKey) -> Result<Vec<String>, Error> {
Ok(Vec::new())
}
fn get_nodes(&self) -> Result<Vec<(PublicKey, model::NodeEntry)>, Error> {
Ok(Vec::new())
}
fn clear_database(&self) -> Result<(), Error> {
Ok(())
}
fn signer_id(&self) -> [u8; 16] {
todo!()
}
}
pub trait SeedPersist: Sync + Send {
fn put(&self, key: &str, seed: &[u8]);
fn get(&self, key: &str) -> Option<Vec<u8>>;
fn list(&self) -> Vec<String>;
}
pub struct DummySeedPersister;
impl SeedPersist for DummySeedPersister {
fn put(&self, _key: &str, _seed: &[u8]) {}
fn get(&self, _key: &str) -> Option<Vec<u8>> {
None
}
fn list(&self) -> Vec<String> {
Vec::new()
}
}
pub struct MemorySeedPersister {
seed: Vec<u8>,
}
impl MemorySeedPersister {
pub fn new(seed: Vec<u8>) -> Self {
Self { seed }
}
}
impl SeedPersist for MemorySeedPersister {
fn put(&self, _key: &str, _seed: &[u8]) {
unimplemented!()
}
fn get(&self, _key: &str) -> Option<Vec<u8>> {
Some(self.seed.clone())
}
fn list(&self) -> Vec<String> {
Vec::new()
}
}
#[cfg(feature = "std")]
pub mod fs {
use crate::persist::SeedPersist;
use bitcoin::hashes::hex::{FromHex, ToHex};
use std::fs;
use std::path::PathBuf;
pub struct FileSeedPersister {
path: PathBuf,
}
impl FileSeedPersister {
pub fn new<P: Into<PathBuf>>(path: P) -> Self {
Self { path: path.into() }
}
fn seed_path_for_key(&self, node_id: &str) -> PathBuf {
let mut path = self.path.clone();
path.push(format!("{}.seed", node_id));
path
}
}
impl SeedPersist for FileSeedPersister {
fn put(&self, key: &str, seed: &[u8]) {
write_seed(self.seed_path_for_key(key), seed);
}
fn get(&self, key: &str) -> Option<Vec<u8>> {
read_seed(self.seed_path_for_key(key))
}
fn list(&self) -> Vec<String> {
let mut keys = Vec::new();
for entry in fs::read_dir(&self.path).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if let Some(fileext) = path.extension() {
if fileext == "seed" {
let key = path.file_stem().unwrap().to_str().unwrap();
keys.push(key.to_string());
}
}
}
keys
}
}
fn write_seed(path: PathBuf, seed: &[u8]) {
fs::write(path, seed.to_hex()).unwrap();
}
fn read_seed(path: PathBuf) -> Option<Vec<u8>> {
fs::read_to_string(path).ok().map(|s| Vec::from_hex(s.trim()).expect("bad hex seed"))
}
}
#[derive(Clone)]
pub struct ExternalPersistHelper {
shared_secret: [u8; 32],
last_nonce: [u8; 32],
}
impl ExternalPersistHelper {
pub fn new(shared_secret: [u8; 32]) -> Self {
Self { shared_secret, last_nonce: [0; 32] }
}
pub fn new_nonce(&mut self, entropy_source: &dyn EntropySource) -> [u8; 32] {
let nonce = entropy_source.get_secure_random_bytes();
self.last_nonce = nonce;
nonce
}
pub fn client_hmac(&self, kvs: &Mutations) -> [u8; 32] {
compute_shared_hmac(&self.shared_secret, &[0x01], kvs)
}
pub fn server_hmac(&self, kvs: &Mutations) -> [u8; 32] {
compute_shared_hmac(&self.shared_secret, &[0x02], kvs)
}
pub fn check_hmac(&self, kvs: &Mutations, received_hmac: Vec<u8>) -> bool {
let hmac = compute_shared_hmac(&self.shared_secret, &self.last_nonce, &kvs); received_hmac == hmac
}
}
use crate::util::debug_utils::DebugBytes;
#[cfg(feature = "std")]
pub use simple_entropy::SimpleEntropy;
#[cfg(feature = "std")]
mod simple_entropy {
use super::EntropySource;
use bitcoin::secp256k1::rand::{self, RngCore};
pub struct SimpleEntropy {}
impl SimpleEntropy {
pub fn new() -> Self {
Self {}
}
}
impl EntropySource for SimpleEntropy {
fn get_secure_random_bytes(&self) -> [u8; 32] {
let mut bytes = [0u8; 32];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut bytes);
bytes
}
}
}
pub fn compute_shared_hmac(secret: &[u8], nonce: &[u8], kvs: &Mutations) -> [u8; 32] {
let mut hmac_engine = HmacEngine::<Sha256Hash>::new(&secret);
hmac_engine.input(secret);
hmac_engine.input(nonce);
for (key, (version, value)) in kvs.iter() {
add_to_hmac(key, *version, value, &mut hmac_engine);
}
Hmac::from_engine(hmac_engine).into_inner()
}
fn add_to_hmac(key: &str, version: u64, value: &[u8], hmac: &mut HmacEngine<Sha256Hash>) {
hmac.input(key.as_bytes());
hmac.input(&version.to_be_bytes());
hmac.input(&value);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hmac_test() {
let shared_secret = [0; 32];
let mut helper = ExternalPersistHelper::new(shared_secret);
let mut kvs = Mutations::new();
kvs.add("foo".to_string(), 0, vec![0x01]);
kvs.add("bar".to_string(), 0, vec![0x02]);
let nonce = helper.new_nonce(&SimpleEntropy::new());
let hmac = compute_shared_hmac(&shared_secret, &nonce, &kvs);
assert!(helper.check_hmac(&kvs, hmac.to_vec()));
kvs.add("baz".to_string(), 0, vec![0x03]);
assert!(!helper.check_hmac(&kvs, hmac.to_vec()));
}
}