Class Network

class Network ;

Constructors

NameDescription
this (lookupUpdate) Ctor

Methods

NameDescription
addChannel (chan_conf) Add a Channel to the network
getPaymentPath (from_pk, to_pk, amount, ignore_chans) Build a path between two nodes in the network
removeChannel (chan_conf) Remove a Channel from the network

Example

import std.range;
import std.algorithm;

auto ln = new Network((Hash chan_id, Point) {
    return ChannelUpdate(chan_id, PaymentDirection.TowardsPeer, Amount(1), Amount(0));
});
Point[] pks;
iota(5).each!(idx => pks ~= Scalar.random().toPoint());

ChannelConfig conf;
conf.capacity = 1.coins;
conf.funder_pk = pks[0];
conf.peer_pk = pks[1];
conf.chan_id = hashFull(1);
ln.addChannel(conf);
// #0 -- #1

conf.funder_pk = pks[0];
conf.peer_pk = pks[2];
conf.chan_id = hashFull(2);
ln.addChannel(conf);
// #0 -- #1
//    \__ #2

auto path = ln.getPaymentPath(pks[0], pks[1], Amount(1));
assert(path.length == 1);
assert(path[0].pub_key == pks[1]);
assert(path[0].chan_id == hashFull(1));

path = ln.getPaymentPath(pks[0], pks[2], Amount(1));
assert(path.length == 1);
assert(path[0].pub_key == pks[2]);
assert(path[0].chan_id == hashFull(2));

path = ln.getPaymentPath(pks[1], pks[2], Amount(1));
assert(path.length == 2);
assert(path[0].pub_key == pks[0]);
assert(path[0].chan_id == hashFull(1));
assert(path[1].pub_key == pks[2]);
assert(path[1].chan_id == hashFull(2));

conf.funder_pk = pks[3];
conf.peer_pk = pks[4];
conf.chan_id = hashFull(3);
ln.addChannel(conf);
// #0 -- #1
//    \__ #2    #3 -- #4

foreach (node1; 0 .. 3)
    foreach (node2; 3 .. 5)
        assert(ln.getPaymentPath(pks[node1], pks[node2], Amount(1)) == null);

path = ln.getPaymentPath(pks[3], pks[4], Amount(1));
assert(path.length == 1);
assert(path[0].pub_key == pks[4]);
assert(path[0].chan_id == hashFull(3));

conf.funder_pk = pks[1];
conf.peer_pk = pks[2];
conf.chan_id = hashFull(4);
ln.addChannel(conf);
// #0 -- #1
//   \    |
//    \__ #2    #3 -- #4

path = ln.getPaymentPath(pks[1], pks[2], Amount(1));
assert(path.length == 1);
assert(path[0].pub_key == pks[2]);
assert(path[0].chan_id == hashFull(4));

// Ignore the direct channel between #0 and #2
path = ln.getPaymentPath(pks[0], pks[2], Amount(1), Set!Hash.from([hashFull(2)]));
assert(path.length == 2);
assert(path[0].pub_key == pks[1]);
assert(path[0].chan_id == hashFull(1));
assert(path[1].pub_key == pks[2]);
assert(path[1].chan_id == hashFull(4));

// Can't route 2.coins
path = ln.getPaymentPath(pks[0], pks[2], 2.coins);
assert(path == null);

// unknown keys
path = ln.getPaymentPath(Scalar.random().toPoint(), pks[1], Amount(1));
assert(path is null);

conf.funder_pk = pks[2];
conf.peer_pk = pks[3];
conf.chan_id = hashFull(5);
conf.is_private = true;
ln.addChannel(conf);
// #0 -- #1
//   \    |
//    \__ #2 -p- #3 -- #4

// anything that should use private channel as a hop should fail
foreach (node1; 0 .. 2)
    assert(ln.getPaymentPath(pks[node1], pks[4], Amount(1)) == null);
foreach (node2; 0 .. 2)
    assert(ln.getPaymentPath(pks[4], pks[node2], Amount(1)) == null);

// should be able to route directly between #2 and #3
path = ln.getPaymentPath(pks[2], pks[3], Amount(1));
assert(path.length == 1);
assert(path[0].pub_key == pks[3]);
assert(path[0].chan_id == hashFull(5));

path = ln.getPaymentPath(pks[3], pks[2], Amount(1));
assert(path.length == 1);
assert(path[0].pub_key == pks[2]);
assert(path[0].chan_id == hashFull(5));

// should not be able to route from left part of the graph to #3
foreach (node1; 0 .. 2)
    assert(ln.getPaymentPath(pks[node1], pks[3], Amount(1)) == null);

// should be able to route from right part of the graph to #2
path = ln.getPaymentPath(pks[4], pks[2], Amount(1));
assert(path[$-1].pub_key == pks[2]);
assert(path[$-1].chan_id == hashFull(5));