Adjacencies

This commit is contained in:
chriseth 2022-08-31 00:42:53 +02:00
parent 587bfc4577
commit cb125bf64e
5 changed files with 106 additions and 19 deletions

View file

@ -1,3 +1,95 @@
struct Adjacencies { use crate::flow::Node;
use crate::types::{Address, Edge, U256};
use std::cmp::Reverse;
use std::collections::HashMap;
use std::collections::HashSet;
} struct Adjacencies<'a> {
edges: &'a HashMap<Address, Vec<Edge>>,
lazy_adjacencies: HashMap<Node, HashMap<Node, U256>>,
capacity_adjustments: HashMap<Node, HashMap<Node, U256>>,
}
fn pseudo_node(edge: Edge) -> Node {
Node::TokenEdge(edge.from, edge.token)
}
fn source_address_of(node: &Node) -> &Address {
match node {
Node::Node(addr) => addr,
Node::TokenEdge(from, _) => from,
}
}
impl<'a> Adjacencies<'a> {
pub fn new(edges: &'a HashMap<Address, Vec<Edge>>) -> Self {
Adjacencies {
edges,
lazy_adjacencies: HashMap::new(),
capacity_adjustments: HashMap::new(),
}
}
pub fn outgoing_edges_sorted_by_capacity(&mut self, from: &Node) -> Vec<(Node, U256)> {
let mut adjacencies = self.adjacencies_from(from);
if let Some(adjustments) = self.capacity_adjustments.get(from) {
for (node, c) in adjustments {
*adjacencies.entry(node.clone()).or_default() += *c;
}
}
let mut result = adjacencies.into_iter().collect::<Vec<(Node, U256)>>();
result.sort_unstable_by_key(|(_, capacity)| Reverse(*capacity));
result
}
pub fn adjust_capacity(&mut self, from: Node, to: Node, adjustment: U256) {
*self
.capacity_adjustments
.entry(from)
.or_default()
.entry(to)
.or_default() += adjustment;
}
pub fn is_adjacent(&mut self, from: &Node, to: &Node) -> bool {
// TODO More efficiently?
if let Some(capacity) = self.adjacencies_from(from).get(to) {
*capacity > U256::from(0)
} else {
false
}
}
fn adjacencies_from(&mut self, from: &Node) -> HashMap<Node, U256> {
self.lazy_adjacencies
.entry(from.clone())
.or_insert_with(|| {
let mut result: HashMap<Node, U256> = HashMap::new();
for edge in &self.edges[source_address_of(from)] {
match from {
Node::Node(_) => {
// One edge from "from" to "from x token" with a capacity
// as the max over all contributing edges (the balance of the sender)
result
.entry(pseudo_node(*edge))
.and_modify(|c| {
if edge.capacity > *c {
*c = edge.capacity;
}
})
.or_insert(edge.capacity);
}
Node::TokenEdge(_, _) => {
// Another edge from "from x token" to "to" with its
// own capacity (based on the trust)
if pseudo_node(*edge) == *from {
result.insert(Node::Node(edge.to), edge.capacity);
}
}
}
}
result
})
.clone()
}
}

View file

@ -1,12 +1,9 @@
use crate::address::Address; mod adjacencies;
use crate::edge::Edge;
use crate::u256::U256;
use crate::types::{Address, Edge, U256};
#[derive(Eq, PartialEq, Hash, Clone)]
enum Node { enum Node {
Node(Address), Node(Address),
TokenEdge(Address, Address), TokenEdge(Address, Address),
} }
fn pseudoNode(edge: Edge) -> Node {
Node::TokenEdge(edge.from, edge.to)
}

View file

@ -6,7 +6,7 @@ use std::io::Read;
use crate::types::{Address, Edge, U256}; use crate::types::{Address, Edge, U256};
pub fn read_edges_binary(path: &String) -> Result<HashSet<Edge>, io::Error> { pub fn read_edges_binary(path: &String) -> Result<HashMap<Address, Vec<Edge>>, io::Error> {
let mut f = File::open(path)?; let mut f = File::open(path)?;
let address_index = read_address_index(&mut f)?; let address_index = read_address_index(&mut f)?;
read_edges(&mut f, &address_index) read_edges(&mut f, &address_index)
@ -55,15 +55,15 @@ fn read_u256(file: &mut File) -> Result<U256, io::Error> {
fn read_edges( fn read_edges(
file: &mut File, file: &mut File,
address_index: &HashMap<u32, Address>, address_index: &HashMap<u32, Address>,
) -> Result<HashSet<Edge>, io::Error> { ) -> Result<HashMap<Address, Vec<Edge>>, io::Error> {
let edge_count = read_u32(file)?; let edge_count = read_u32(file)?;
let mut edges = HashSet::new(); let mut edges: HashMap<Address, Vec<Edge>> = HashMap::new();
for _i in 0..edge_count { for _i in 0..edge_count {
let from = read_address(file, address_index)?; let from = read_address(file, address_index)?;
let to = read_address(file, address_index)?; let to = read_address(file, address_index)?;
let token = read_address(file, address_index)?; let token = read_address(file, address_index)?;
let capacity = read_u256(file)?; let capacity = read_u256(file)?;
edges.insert(Edge { edges.entry(from).or_insert(vec![]).push(Edge {
from, from,
to, to,
token, token,

View file

@ -1,4 +1,4 @@
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, PartialOrd)]
pub struct Address([u8; 20]); pub struct Address([u8; 20]);
impl From<[u8; 20]> for Address { impl From<[u8; 20]> for Address {

View file

@ -2,7 +2,7 @@ use std::fmt::Display;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct U256([u128; 2]); pub struct U256([u128; 2]);
impl U256 { impl U256 {
@ -56,11 +56,9 @@ impl Add for U256 {
type Output = Self; type Output = Self;
fn add(self, rhs: Self) -> Self { fn add(self, rhs: Self) -> Self {
let (low, carry) = self.0[1].overflowing_add(rhs.0[1]); let (low, carry) = self.0[1].overflowing_add(rhs.0[1]);
let (mut high, mut overflow) = self.0[0].overflowing_add(rhs.0[0]); let mut high = self.0[0].wrapping_add(rhs.0[0]);
assert!(!overflow);
if carry { if carry {
(high, overflow) = high.overflowing_add(1); high = high.wrapping_add(1);
assert!(!overflow);
} }
Self([high, low]) Self([high, low])
} }