Skip to content

Commit

Permalink
feat: add the possiblity to add a node and a channel
Browse files Browse the repository at this point in the history
Signed-off-by: Vincenzo Palazzo <[email protected]>
  • Loading branch information
vincenzopalazzo committed Jun 13, 2023
1 parent ffee883 commit ef60de4
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 128 deletions.
6 changes: 4 additions & 2 deletions gossip_map/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ edition = "2021"

[dependencies]
byteorder = "1.4.3"
fundamentals = "^0.0.1-alpha.2"
fundamentals-derive = "^0.0.1-alpha.1"
hex = "0.4.3"
bitcoin = { version = "0.30.0" }
fundamentals = "^0.0.1-alpha.3"
fundamentals-derive = "^0.0.1-alpha.2"
7 changes: 3 additions & 4 deletions gossip_map/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ pub static GOSSIP_STORE_MAJOR_VERSION: u16 = 0 << 5;
pub static GOSSIP_STORE_MAJOR_VERSION_MASK: u16 = 0xE0;

/// Deleted fields should be ignored: on restart, they will be removed as the gossip_store is rewritten.
pub static GOSSIP_STORE_LEN_DELETED_BIT: u32 = 0x80000000;
pub const GOSSIP_STORE_LEN_DELETED_BIT: u16 = 0x8000;
/// The push flag indicates gossip which is generated locally: this is important for gossip timestamp filtering,
/// where peers request gossip and we always send our own gossip messages even if the timestamp wasn't within their
/// request.pub static GOSSIP_STORE_LEN_PUSH_BIT: u32 = 0x40000000;
pub static GOSSIP_STORE_LEN_RATELIMIT_BIT: u32 = 0x20000000;
pub const GOSSIP_STORE_LEN_PUSH_BIT: u16 = 0x4000;
/// The ratelimit flag indicates that this gossip message came too fast.
/// The message are corded in the gossip map, but don't relay it to peers.
pub static GOSSIP_STORE_LEN_MASK: u16 = 0x0000FFFF;
pub const GOSSIP_STORE_LEN_RATELIMIT_BIT: u16 = 0x2000;

// These duplicate constants in lightning/gossipd/gossip_store_wiregen.h
pub const WIRE_GOSSIP_STORE_PRIVATE_CHANNEL: u16 = 4104;
Expand Down
2 changes: 1 addition & 1 deletion gossip_map/src/gossip_store_msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct GossipStoreChannelAmount {
#[warn(dead_code)]
#[msg_type = 4101]
ty: u16,
satoshis: u16,
pub satoshis: u64,
}

#[derive(DecodeWire, EncodeWire, Debug)]
Expand Down
168 changes: 139 additions & 29 deletions gossip_map/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use std::{
collections::{HashMap, HashSet},
fs::File,
io::{BufReader, Error, ErrorKind},
};
#![allow(dead_code)]
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, Error, ErrorKind};

use fundamentals::{
bolt::bolt7::ChannelAnnouncement,
prelude::bolt7::{ChannelUpdate, NodeAnnouncement},
};
use fundamentals::{core::FromWire, types::ShortChannelId};
use fundamentals::core::FromWire;
use fundamentals::prelude::bolt7::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement};
use fundamentals::types::ShortChannelId;

mod flags;
mod gossip_store_msg;
Expand All @@ -20,27 +17,28 @@ use flags::{
WIRE_GOSSIP_STORE_PRIVATE_UPDATE,
};
use gossip_store_msg::*;
use types::{GossipChannel, GossipNode, GossipNodeId};
use types::{GossipChannel, GossipNode, GossipNodeId, GossipStoredHeader};

/// Gossip map implementation, that allow you to manage the gossip_store
/// written by core lightning.
struct GossipMap<'a> {
#[derive(Debug)]
struct GossipMap {
version: u8,
stream: Option<BufReader<File>>,
nodes: HashMap<GossipNodeId, GossipNode<'a>>,
channels: HashMap<ShortChannelId, GossipChannel<'a>>,
orphan_channel_updates: HashSet<ChannelUpdate>,
nodes: HashMap<GossipNodeId, GossipNode>,
channels: HashMap<ShortChannelId, GossipChannel>,
orphan_channel_updates: HashMap<ShortChannelId, ChannelUpdate>,
}

impl GossipMap<'_> {
impl GossipMap {
// Create a new instance of the gossip map.
pub fn new(version: u8) -> Self {
GossipMap {
version,
stream: None,
nodes: HashMap::new(),
channels: HashMap::new(),
orphan_channel_updates: HashSet::new(),
orphan_channel_updates: HashMap::new(),
}
}

Expand All @@ -52,23 +50,27 @@ impl GossipMap<'_> {
stream: Some(stream),
nodes: HashMap::new(),
channels: HashMap::new(),
orphan_channel_updates: HashSet::new(),
orphan_channel_updates: HashMap::new(),
};
gossip_map.refresh()?;
Ok(gossip_map)
}

pub fn get_channel(&self, short_chananel_id: &str) -> Option<&'static GossipChannel> {
pub fn get_channel(&self, short_chananel_id: &str) -> Option<&GossipChannel> {
self.channels.get(short_chananel_id.as_bytes())
}

pub fn get_node(&self, node_id: &str) -> Option<&'static GossipNode> {
// FIXME: store the node as String?
self.nodes.get(&GossipNodeId {
node_id: node_id.to_owned(),
})
pub fn get_node(&self, node_id: &str) -> Option<&GossipNode> {
let node_id = GossipNodeId::from(node_id);
self.nodes.get(&node_id)
}

/// add a node announcement message inside the gossip map
fn add_node_announcement(&mut self, node_announce: NodeAnnouncement) {}

/// add a channel announcement message inside the gossip map.
fn add_channel_announcement(&mut self, channel_announce: ChannelAnnouncement) {}

fn refresh(&mut self) -> std::io::Result<()> {
let mut stream = self.stream.as_mut().unwrap();
let version = u8::from_wire(&mut stream)? as u16;
Expand All @@ -79,38 +81,146 @@ impl GossipMap<'_> {
));
}
self.version = version as u8;
println!("version {version}");

while let Ok(chunk) = u8::from_wire(&mut stream) {
match chunk as u16 {
let mut last_short_channel_id: Option<ShortChannelId> = None;
loop {
let Ok(header) = GossipStoredHeader::from_wire(&mut stream) else {
break; // EOF?
};
match header.flag() {
flags::GOSSIP_STORE_LEN_DELETED_BIT | flags::GOSSIP_STORE_LEN_RATELIMIT_BIT => {
continue
}
_ => {}
}

println!("header {:?}", header);
let chunk = u16::from_wire(&mut stream)?;
println!("chunk {chunk}");
match chunk {
// channel announcement!
256 => {
let channel_announcement = ChannelAnnouncement::from_wire(&mut stream)?;
let node_one = GossipNodeId::from_bytes(&channel_announcement.node_id_1)?;
let node_two = GossipNodeId::from_bytes(&channel_announcement.node_id_2)?;
if !self.nodes.contains_key(&node_one) {
let node = GossipNode::new(node_one.clone(), None);
self.nodes.insert(node_one.clone(), node);
}

if !self.nodes.contains_key(&node_two) {
let node = GossipNode::new(node_two.clone(), None);
self.nodes.insert(node_two.clone(), node);
}
println!("{:?}", self.nodes);
last_short_channel_id = Some(channel_announcement.short_channel_id);
let channel = GossipChannel::new(channel_announcement, &node_one, &node_two);
// SAFETY: this is sage because the node is always present, due the
// previous checks.
let node_one = self.nodes.get_mut(&node_one).unwrap();
node_one.add_channel(&channel.clone());
let node_two = self.nodes.get_mut(&node_two).unwrap();
node_two.add_channel(&channel.clone());
self.channels
.insert(last_short_channel_id.unwrap(), channel);
}
WIRE_GOSSIP_STORE_PRIVATE_CHANNEL => {
let private_channel = GossipStorePrivateChannel::from_wire(&mut stream)?;
let _ = stream.seek_relative(2 + 8 + 2)?;
let channel_announcement = ChannelAnnouncement::from_wire(&mut stream)?;

let node_one = GossipNodeId::from_bytes(&channel_announcement.node_id_1)?;
let node_two = GossipNodeId::from_bytes(&channel_announcement.node_id_2)?;
if !self.nodes.contains_key(&node_one) {
let node = GossipNode::new(node_one.clone(), None);
self.nodes.insert(node_one.clone(), node);
}

if !self.nodes.contains_key(&node_two) {
let node = GossipNode::new(node_two.clone(), None);
self.nodes.insert(node_two.clone(), node);
}

last_short_channel_id = Some(channel_announcement.short_channel_id);
let mut channel =
GossipChannel::new(channel_announcement, &node_one, &node_two);
// SAFETY: this is sage because the node is always present, due the
// previous checks.
let node_one = self.nodes.get_mut(&node_one).unwrap();
node_one.add_channel(&channel.clone());
let node_two = self.nodes.get_mut(&node_two).unwrap();
node_two.add_channel(&channel.clone());
channel.set_private(true);
self.channels
.insert(last_short_channel_id.unwrap(), channel);
}
WIRE_GOSSIP_STORE_CHANNEL_AMOUNT => {
let channel_amount = GossipStoreChannelAmount::from_wire(&mut stream)?;
//FIXME: remove the unwrap().
assert!(last_short_channel_id.is_some());
let channel = self
.channels
.get_mut(&last_short_channel_id.unwrap())
.unwrap();
channel.set_amount(channel_amount);
}
WIRE_GOSSIP_STORE_PRIVATE_UPDATE => {
let private_update = GossipStorePrivateUpdate::from_wire(&mut stream)?;
unimplemented!()
}
WIRE_GOSSIP_STORE_DELETE_CHAN => {
let del_chan = GossipStoreDeleteChan::from_wire(&mut stream)?;
unimplemented!()
}
WIRE_GOSSIP_STORE_ENDED => {
let eof = GossipStoreEnded::from_wire(&mut stream)?;
let _ = GossipStoreEnded::from_wire(&mut stream)?;
break;
}
257 => {
let node_announcement = NodeAnnouncement::from_wire(&mut stream)?;
let node_id = GossipNodeId::from_bytes(&node_announcement.node_id)?;
if !self.nodes.contains_key(&node_id) {
let node = GossipNode::new(node_id.clone(), Some(node_announcement));
self.nodes.insert(node_id, node);
}
}
258 => {
let channel_update = ChannelUpdate::from_wire(&mut stream)?;
if self.channels.contains_key(&channel_update.short_channel_id) {
// SAFETY: we check the existence before!
let channel = self
.channels
.get_mut(&channel_update.short_channel_id)
.unwrap();
channel.channel_update(&channel_update)
} else {
self.orphan_channel_updates
.insert(channel_update.short_channel_id, channel_update);
}
}
_ => continue,
_ => assert!(false),
}
println!("----------------------------------------------------");
}

Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn read_gossipmap_from_file() {
let path = "/run/media/vincent/VincentSSD/.lightning/testnet/gossip_store";
let pubkey = "03b39d1ddf13ce486de74e9e44e0538f960401a9ec75534ba9cfe4100d65426880";
let map = GossipMap::from_file(path);
assert!(map.is_ok(), "{:?}", map);
let map = map.unwrap();
assert!(
map.get_node(pubkey).is_some(),
"node with id `{pubkey}` not found!"
);
}
}
Loading

0 comments on commit ef60de4

Please sign in to comment.