routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
package routing
|
|
|
|
|
|
|
|
import (
|
2017-06-16 23:45:24 +03:00
|
|
|
"bytes"
|
2018-06-09 23:36:48 +03:00
|
|
|
"crypto/sha256"
|
2017-06-16 23:45:24 +03:00
|
|
|
"encoding/binary"
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"io/ioutil"
|
2018-04-19 17:32:24 +03:00
|
|
|
"math"
|
2017-03-09 01:24:59 +03:00
|
|
|
"math/big"
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2018-06-05 04:34:16 +03:00
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/btcsuite/btcutil"
|
2018-07-31 10:17:17 +03:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2017-03-09 07:44:32 +03:00
|
|
|
|
|
|
|
prand "math/rand"
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// basicGraphFilePath is the file path for a basic graph used within
|
|
|
|
// the tests. The basic graph consists of 5 nodes with 5 channels
|
|
|
|
// connecting them.
|
2017-03-09 01:24:59 +03:00
|
|
|
basicGraphFilePath = "testdata/basic_graph.json"
|
|
|
|
|
|
|
|
// excessiveHopsGraphFilePath is a file path which stores the JSON dump
|
|
|
|
// of a graph which was previously triggering an erroneous excessive
|
|
|
|
// hops error. The error has since been fixed, but a test case
|
|
|
|
// exercising it is kept around to guard against regressions.
|
2017-02-01 18:48:30 +03:00
|
|
|
excessiveHopsGraphFilePath = "testdata/excessive_hops.json"
|
2017-10-19 08:10:00 +03:00
|
|
|
|
|
|
|
// specExampleFilePath is a file path which stores an example which
|
|
|
|
// implementations will use in order to ensure that they're calculating
|
|
|
|
// the payload for each hop in path properly.
|
|
|
|
specExampleFilePath = "testdata/spec_example.json"
|
2018-04-19 17:32:24 +03:00
|
|
|
|
|
|
|
// noFeeLimit is the maximum value of a payment through Lightning. We
|
|
|
|
// can use this value to signal there is no fee limit since payments
|
|
|
|
// should never be larger than this.
|
|
|
|
noFeeLimit = lnwire.MilliSatoshi(math.MaxUint32)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
)
|
|
|
|
|
2017-03-09 01:24:59 +03:00
|
|
|
var (
|
|
|
|
randSource = prand.NewSource(time.Now().Unix())
|
|
|
|
randInts = prand.New(randSource)
|
|
|
|
testSig = &btcec.Signature{
|
|
|
|
R: new(big.Int),
|
|
|
|
S: new(big.Int),
|
|
|
|
}
|
|
|
|
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
|
|
|
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
|
|
|
|
|
|
|
testAuthProof = channeldb.ChannelAuthProof{
|
2018-01-31 07:26:26 +03:00
|
|
|
NodeSig1Bytes: testSig.Serialize(),
|
|
|
|
NodeSig2Bytes: testSig.Serialize(),
|
|
|
|
BitcoinSig1Bytes: testSig.Serialize(),
|
|
|
|
BitcoinSig2Bytes: testSig.Serialize(),
|
2017-03-09 01:24:59 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// testGraph is the struct which corresponds to the JSON format used to encode
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// graphs within the files in the testdata directory.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): add test graph auto-generator
|
|
|
|
type testGraph struct {
|
|
|
|
Info []string `json:"info"`
|
|
|
|
Nodes []testNode `json:"nodes"`
|
|
|
|
Edges []testChan `json:"edges"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// testNode represents a node within the test graph above. We skip certain
|
|
|
|
// information such as the node's IP address as that information isn't needed
|
|
|
|
// for our tests.
|
|
|
|
type testNode struct {
|
|
|
|
Source bool `json:"source"`
|
|
|
|
PubKey string `json:"pubkey"`
|
|
|
|
Alias string `json:"alias"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// testChan represents the JSON version of a payment channel. This struct
|
|
|
|
// matches the Json that's encoded under the "edges" key within the test graph.
|
|
|
|
type testChan struct {
|
2017-10-19 07:22:49 +03:00
|
|
|
Node1 string `json:"node_1"`
|
|
|
|
Node2 string `json:"node_2"`
|
|
|
|
ChannelID uint64 `json:"channel_id"`
|
|
|
|
ChannelPoint string `json:"channel_point"`
|
|
|
|
Flags uint16 `json:"flags"`
|
|
|
|
Expiry uint16 `json:"expiry"`
|
|
|
|
MinHTLC int64 `json:"min_htlc"`
|
|
|
|
FeeBaseMsat int64 `json:"fee_base_msat"`
|
|
|
|
FeeRate int64 `json:"fee_rate"`
|
|
|
|
Capacity int64 `json:"capacity"`
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// makeTestGraph creates a new instance of a channeldb.ChannelGraph for testing
|
|
|
|
// purposes. A callback which cleans up the created temporary directories is
|
|
|
|
// also returned and intended to be executed after the test completes.
|
|
|
|
func makeTestGraph() (*channeldb.ChannelGraph, func(), error) {
|
|
|
|
// First, create a temporary directory to be used for the duration of
|
|
|
|
// this test.
|
|
|
|
tempDirName, err := ioutil.TempDir("", "channeldb")
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next, create channeldb for the first time.
|
|
|
|
cdb, err := channeldb.Open(tempDirName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanUp := func() {
|
|
|
|
cdb.Close()
|
|
|
|
os.RemoveAll(tempDirName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return cdb.ChannelGraph(), cleanUp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// aliasMap is a map from a node's alias to its public key. This type is
|
2018-02-07 06:11:11 +03:00
|
|
|
// provided in order to allow easily look up from the human memorable alias
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// to an exact node's public key.
|
|
|
|
type aliasMap map[string]*btcec.PublicKey
|
|
|
|
|
|
|
|
// parseTestGraph returns a fully populated ChannelGraph given a path to a JSON
|
|
|
|
// file which encodes a test graph.
|
|
|
|
func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, error) {
|
2017-02-23 22:56:47 +03:00
|
|
|
graphJSON, err := ioutil.ReadFile(path)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// First unmarshal the JSON graph into an instance of the testGraph
|
|
|
|
// struct. Using the struct tags created above in the struct, the JSON
|
|
|
|
// will be properly parsed into the struct above.
|
|
|
|
var g testGraph
|
2017-02-23 22:56:47 +03:00
|
|
|
if err := json.Unmarshal(graphJSON, &g); err != nil {
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// We'll use this fake address for the IP address of all the nodes in
|
|
|
|
// our tests. This value isn't needed for path finding so it doesn't
|
|
|
|
// need to be unique.
|
2017-02-17 12:29:23 +03:00
|
|
|
var testAddrs []net.Addr
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888")
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
2017-02-17 12:29:23 +03:00
|
|
|
testAddrs = append(testAddrs, testAddr)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
|
|
|
|
// Next, create a temporary graph database for usage within the test.
|
|
|
|
graph, cleanUp, err := makeTestGraph()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
aliasMap := make(map[string]*btcec.PublicKey)
|
|
|
|
var source *channeldb.LightningNode
|
|
|
|
|
|
|
|
// First we insert all the nodes within the graph as vertexes.
|
|
|
|
for _, node := range g.Nodes {
|
|
|
|
pubBytes, err := hex.DecodeString(node.PubKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
dbNode := &channeldb.LightningNode{
|
2017-07-14 22:32:00 +03:00
|
|
|
HaveNodeAnnouncement: true,
|
2018-01-31 07:26:26 +03:00
|
|
|
AuthSigBytes: testSig.Serialize(),
|
2017-07-14 22:32:00 +03:00
|
|
|
LastUpdate: time.Now(),
|
|
|
|
Addresses: testAddrs,
|
|
|
|
Alias: node.Alias,
|
|
|
|
Features: testFeatures,
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
2018-01-31 07:26:26 +03:00
|
|
|
copy(dbNode.PubKeyBytes[:], pubBytes)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
|
|
|
|
// We require all aliases within the graph to be unique for our
|
|
|
|
// tests.
|
|
|
|
if _, ok := aliasMap[node.Alias]; ok {
|
|
|
|
return nil, nil, nil, errors.New("aliases for nodes " +
|
|
|
|
"must be unique!")
|
|
|
|
}
|
|
|
|
|
2018-01-31 07:26:26 +03:00
|
|
|
pub, err := btcec.ParsePubKey(pubBytes, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2017-02-23 22:56:47 +03:00
|
|
|
// If the alias is unique, then add the node to the
|
|
|
|
// alias map for easy lookup.
|
|
|
|
aliasMap[node.Alias] = pub
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// If the node is tagged as the source, then we create a
|
|
|
|
// pointer to is so we can mark the source in the graph
|
|
|
|
// properly.
|
|
|
|
if node.Source {
|
|
|
|
// If we come across a node that's marked as the
|
|
|
|
// source, and we've already set the source in a prior
|
|
|
|
// iteration, then the JSON has an error as only ONE
|
|
|
|
// node can be the source in the graph.
|
|
|
|
if source != nil {
|
|
|
|
return nil, nil, nil, errors.New("JSON is invalid " +
|
|
|
|
"multiple nodes are tagged as the source")
|
|
|
|
}
|
|
|
|
|
|
|
|
source = dbNode
|
|
|
|
}
|
|
|
|
|
|
|
|
// With the node fully parsed, add it as a vertex within the
|
|
|
|
// graph.
|
|
|
|
if err := graph.AddLightningNode(dbNode); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-19 07:29:42 +03:00
|
|
|
if source != nil {
|
|
|
|
// Set the selected source node
|
|
|
|
if err := graph.SetSourceNode(source); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// With all the vertexes inserted, we can now insert the edges into the
|
|
|
|
// test graph.
|
|
|
|
for _, edge := range g.Edges {
|
|
|
|
node1Bytes, err := hex.DecodeString(edge.Node1)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
node2Bytes, err := hex.DecodeString(edge.Node2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
fundingTXID := strings.Split(edge.ChannelPoint, ":")[0]
|
2017-01-06 00:56:27 +03:00
|
|
|
txidBytes, err := chainhash.NewHashFromStr(fundingTXID)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
fundingPoint := wire.OutPoint{
|
|
|
|
Hash: *txidBytes,
|
|
|
|
Index: 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
// We first insert the existence of the edge between the two
|
|
|
|
// nodes.
|
2017-03-09 01:24:59 +03:00
|
|
|
edgeInfo := channeldb.ChannelEdgeInfo{
|
|
|
|
ChannelID: edge.ChannelID,
|
|
|
|
AuthProof: &testAuthProof,
|
|
|
|
ChannelPoint: fundingPoint,
|
|
|
|
Capacity: btcutil.Amount(edge.Capacity),
|
|
|
|
}
|
2018-01-31 07:26:26 +03:00
|
|
|
|
|
|
|
copy(edgeInfo.NodeKey1Bytes[:], node1Bytes)
|
|
|
|
copy(edgeInfo.NodeKey2Bytes[:], node2Bytes)
|
|
|
|
copy(edgeInfo.BitcoinKey1Bytes[:], node1Bytes)
|
|
|
|
copy(edgeInfo.BitcoinKey2Bytes[:], node2Bytes)
|
|
|
|
|
2017-10-19 07:29:14 +03:00
|
|
|
err = graph.AddChannelEdge(&edgeInfo)
|
|
|
|
if err != nil && err != channeldb.ErrEdgeAlreadyExist {
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2017-03-09 01:24:59 +03:00
|
|
|
edgePolicy := &channeldb.ChannelEdgePolicy{
|
2018-01-31 07:26:26 +03:00
|
|
|
SigBytes: testSig.Serialize(),
|
2017-12-01 09:24:27 +03:00
|
|
|
Flags: lnwire.ChanUpdateFlag(edge.Flags),
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
ChannelID: edge.ChannelID,
|
|
|
|
LastUpdate: time.Now(),
|
2017-03-09 01:24:59 +03:00
|
|
|
TimeLockDelta: edge.Expiry,
|
2017-08-22 09:43:20 +03:00
|
|
|
MinHTLC: lnwire.MilliSatoshi(edge.MinHTLC),
|
|
|
|
FeeBaseMSat: lnwire.MilliSatoshi(edge.FeeBaseMsat),
|
|
|
|
FeeProportionalMillionths: lnwire.MilliSatoshi(edge.FeeRate),
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
2017-03-09 01:24:59 +03:00
|
|
|
if err := graph.UpdateEdgePolicy(edgePolicy); err != nil {
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return graph, cleanUp, aliasMap, nil
|
|
|
|
}
|
|
|
|
|
2018-06-09 23:36:48 +03:00
|
|
|
type testChannelPolicy struct {
|
|
|
|
Expiry uint16
|
|
|
|
MinHTLC lnwire.MilliSatoshi
|
|
|
|
FeeBaseMsat lnwire.MilliSatoshi
|
|
|
|
FeeRate lnwire.MilliSatoshi
|
|
|
|
}
|
|
|
|
|
|
|
|
type testChannelEnd struct {
|
|
|
|
Alias string
|
|
|
|
testChannelPolicy
|
|
|
|
}
|
|
|
|
|
|
|
|
func defaultTestChannelEnd(alias string) *testChannelEnd {
|
|
|
|
return &testChannelEnd{
|
|
|
|
Alias: alias,
|
|
|
|
testChannelPolicy: testChannelPolicy{
|
|
|
|
Expiry: 144,
|
|
|
|
MinHTLC: lnwire.MilliSatoshi(1000),
|
|
|
|
FeeBaseMsat: lnwire.MilliSatoshi(1000),
|
|
|
|
FeeRate: lnwire.MilliSatoshi(1),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func symmetricTestChannel(alias1 string, alias2 string, capacity btcutil.Amount,
|
|
|
|
policy *testChannelPolicy) *testChannel {
|
|
|
|
return &testChannel{
|
|
|
|
Capacity: capacity,
|
|
|
|
Node1: &testChannelEnd{
|
|
|
|
Alias: alias1,
|
|
|
|
testChannelPolicy: *policy,
|
|
|
|
},
|
|
|
|
Node2: &testChannelEnd{
|
|
|
|
Alias: alias2,
|
|
|
|
testChannelPolicy: *policy,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type testChannel struct {
|
|
|
|
Node1 *testChannelEnd
|
|
|
|
Node2 *testChannelEnd
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
}
|
|
|
|
|
|
|
|
// createTestGraph returns a fully populated ChannelGraph based on a set of
|
|
|
|
// test channels. Additional required information like keys are derived in
|
|
|
|
// a deterministical way and added to the channel graph. A list of nodes is
|
|
|
|
// not required and derived from the channel data. The goal is to keep
|
|
|
|
// instantiating a test channel graph as light weight as possible.
|
|
|
|
func createTestGraph(testChannels []*testChannel) (*channeldb.ChannelGraph, func(), aliasMap, error) {
|
|
|
|
// We'll use this fake address for the IP address of all the nodes in
|
|
|
|
// our tests. This value isn't needed for path finding so it doesn't
|
|
|
|
// need to be unique.
|
|
|
|
var testAddrs []net.Addr
|
|
|
|
testAddr, err := net.ResolveTCPAddr("tcp", "192.0.0.1:8888")
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
testAddrs = append(testAddrs, testAddr)
|
|
|
|
|
|
|
|
// Next, create a temporary graph database for usage within the test.
|
|
|
|
graph, cleanUp, err := makeTestGraph()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
aliasMap := make(map[string]*btcec.PublicKey)
|
|
|
|
|
|
|
|
nodeIndex := byte(0)
|
|
|
|
addNodeWithAlias := func(alias string) (*channeldb.LightningNode, error) {
|
|
|
|
keyBytes := make([]byte, 32)
|
|
|
|
keyBytes = []byte{
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, nodeIndex + 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, pubKey := btcec.PrivKeyFromBytes(btcec.S256(),
|
|
|
|
keyBytes)
|
|
|
|
|
|
|
|
dbNode := &channeldb.LightningNode{
|
|
|
|
HaveNodeAnnouncement: true,
|
|
|
|
AuthSigBytes: testSig.Serialize(),
|
|
|
|
LastUpdate: time.Now(),
|
|
|
|
Addresses: testAddrs,
|
|
|
|
Alias: alias,
|
|
|
|
Features: testFeatures,
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(dbNode.PubKeyBytes[:], pubKey.SerializeCompressed())
|
|
|
|
|
|
|
|
// With the node fully parsed, add it as a vertex within the
|
|
|
|
// graph.
|
|
|
|
if err := graph.AddLightningNode(dbNode); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
aliasMap[alias] = pubKey
|
|
|
|
nodeIndex++
|
|
|
|
|
|
|
|
return dbNode, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var source *channeldb.LightningNode
|
|
|
|
if source, err = addNodeWithAlias("roasbeef"); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the source node
|
|
|
|
if err := graph.SetSourceNode(source); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
channelID := uint64(0)
|
|
|
|
for _, testChannel := range testChannels {
|
|
|
|
for _, alias := range []string{
|
|
|
|
testChannel.Node1.Alias, testChannel.Node2.Alias} {
|
|
|
|
|
|
|
|
_, exists := aliasMap[alias]
|
|
|
|
if !exists {
|
|
|
|
addNodeWithAlias(alias)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var hash [sha256.Size]byte
|
|
|
|
hash[len(hash)-1] = byte(channelID)
|
|
|
|
|
|
|
|
fundingPoint := &wire.OutPoint{
|
|
|
|
Hash: chainhash.Hash(hash),
|
|
|
|
Index: 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
// We first insert the existence of the edge between the two
|
|
|
|
// nodes.
|
|
|
|
edgeInfo := channeldb.ChannelEdgeInfo{
|
|
|
|
ChannelID: channelID,
|
|
|
|
AuthProof: &testAuthProof,
|
|
|
|
ChannelPoint: *fundingPoint,
|
|
|
|
Capacity: testChannel.Capacity,
|
|
|
|
}
|
|
|
|
|
|
|
|
node1Bytes := aliasMap[testChannel.Node1.Alias].SerializeCompressed()
|
|
|
|
node2Bytes := aliasMap[testChannel.Node2.Alias].SerializeCompressed()
|
|
|
|
|
|
|
|
copy(edgeInfo.NodeKey1Bytes[:], node1Bytes)
|
|
|
|
copy(edgeInfo.NodeKey2Bytes[:], node2Bytes)
|
|
|
|
copy(edgeInfo.BitcoinKey1Bytes[:], node1Bytes)
|
|
|
|
copy(edgeInfo.BitcoinKey2Bytes[:], node2Bytes)
|
|
|
|
|
|
|
|
err = graph.AddChannelEdge(&edgeInfo)
|
|
|
|
if err != nil && err != channeldb.ErrEdgeAlreadyExist {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
edgePolicy := &channeldb.ChannelEdgePolicy{
|
|
|
|
SigBytes: testSig.Serialize(),
|
|
|
|
Flags: lnwire.ChanUpdateFlag(0),
|
|
|
|
ChannelID: channelID,
|
|
|
|
LastUpdate: time.Now(),
|
|
|
|
TimeLockDelta: testChannel.Node1.Expiry,
|
|
|
|
MinHTLC: testChannel.Node1.MinHTLC,
|
|
|
|
FeeBaseMSat: testChannel.Node1.FeeBaseMsat,
|
|
|
|
FeeProportionalMillionths: testChannel.Node1.FeeRate,
|
|
|
|
}
|
|
|
|
if err := graph.UpdateEdgePolicy(edgePolicy); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
edgePolicy = &channeldb.ChannelEdgePolicy{
|
|
|
|
SigBytes: testSig.Serialize(),
|
|
|
|
Flags: lnwire.ChanUpdateFlag(lnwire.ChanUpdateDirection),
|
|
|
|
ChannelID: channelID,
|
|
|
|
LastUpdate: time.Now(),
|
|
|
|
TimeLockDelta: testChannel.Node2.Expiry,
|
|
|
|
MinHTLC: testChannel.Node2.MinHTLC,
|
|
|
|
FeeBaseMSat: testChannel.Node2.FeeBaseMsat,
|
|
|
|
FeeProportionalMillionths: testChannel.Node2.FeeRate,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := graph.UpdateEdgePolicy(edgePolicy); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
channelID++
|
|
|
|
}
|
|
|
|
|
|
|
|
return graph, cleanUp, aliasMap, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestFindLowestFeePath tests that out of two routes with identical total
|
|
|
|
// time lock values, the route with the lowest total fee should be returned.
|
|
|
|
// The fee rates are chosen such that the test failed on the previous edge
|
|
|
|
// weight function where one of the terms was fee squared.
|
|
|
|
func TestFindLowestFeePath(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// Set up a test graph with two paths from roasbeef to target. Both
|
|
|
|
// paths have equal total time locks, but the path through b has lower
|
|
|
|
// fees (700 compared to 800 for the path through a).
|
|
|
|
testChannels := []*testChannel{
|
2018-06-04 23:10:05 +03:00
|
|
|
symmetricTestChannel("roasbeef", "first", 100000, &testChannelPolicy{
|
|
|
|
Expiry: 144,
|
|
|
|
FeeRate: 400,
|
|
|
|
MinHTLC: 1,
|
|
|
|
}),
|
|
|
|
symmetricTestChannel("first", "a", 100000, &testChannelPolicy{
|
2018-06-09 23:36:48 +03:00
|
|
|
Expiry: 144,
|
|
|
|
FeeRate: 400,
|
|
|
|
MinHTLC: 1,
|
|
|
|
}),
|
|
|
|
symmetricTestChannel("a", "target", 100000, &testChannelPolicy{
|
|
|
|
Expiry: 144,
|
|
|
|
FeeRate: 400,
|
|
|
|
MinHTLC: 1,
|
|
|
|
}),
|
2018-06-04 23:10:05 +03:00
|
|
|
symmetricTestChannel("first", "b", 100000, &testChannelPolicy{
|
2018-06-09 23:36:48 +03:00
|
|
|
Expiry: 144,
|
|
|
|
FeeRate: 100,
|
|
|
|
MinHTLC: 1,
|
|
|
|
}),
|
|
|
|
symmetricTestChannel("b", "target", 100000, &testChannelPolicy{
|
|
|
|
Expiry: 144,
|
|
|
|
FeeRate: 600,
|
|
|
|
MinHTLC: 1,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
graph, cleanUp, aliases, err := createTestGraph(testChannels)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
sourceVertex := Vertex(sourceNode.PubKeyBytes)
|
|
|
|
|
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
|
|
|
|
|
|
|
const (
|
|
|
|
startingHeight = 100
|
|
|
|
finalHopCLTV = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
|
|
|
target := aliases["target"]
|
|
|
|
path, err := findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, paymentAmt, noFeeLimit, nil,
|
2018-06-09 23:36:48 +03:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find path: %v", err)
|
|
|
|
}
|
|
|
|
route, err := newRoute(
|
2018-07-31 10:20:22 +03:00
|
|
|
paymentAmt, infinity, sourceVertex, path, startingHeight,
|
2018-06-09 23:36:48 +03:00
|
|
|
finalHopCLTV)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create path: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-07-31 10:20:22 +03:00
|
|
|
// Assert that the lowest fee route is returned.
|
2018-06-04 23:10:05 +03:00
|
|
|
if !bytes.Equal(route.Hops[1].Channel.Node.PubKeyBytes[:],
|
2018-06-09 23:36:48 +03:00
|
|
|
aliases["b"].SerializeCompressed()) {
|
|
|
|
t.Fatalf("expected route to pass through b, "+
|
|
|
|
"but got a route through %v",
|
2018-06-04 23:10:05 +03:00
|
|
|
route.Hops[1].Channel.Node.Alias)
|
2018-06-09 23:36:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
type expectedHop struct {
|
|
|
|
alias string
|
|
|
|
fee lnwire.MilliSatoshi
|
|
|
|
fwdAmount lnwire.MilliSatoshi
|
|
|
|
timeLock uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type basicGraphPathFindingTestCase struct {
|
2018-06-04 23:10:05 +03:00
|
|
|
target string
|
|
|
|
paymentAmt btcutil.Amount
|
|
|
|
feeLimit lnwire.MilliSatoshi
|
|
|
|
expectedTotalAmt lnwire.MilliSatoshi
|
|
|
|
expectedTotalTimeLock uint32
|
|
|
|
expectedHops []expectedHop
|
|
|
|
expectFailureNoPath bool
|
2018-06-07 12:00:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var basicGraphPathFindingTests = []basicGraphPathFindingTestCase{
|
2018-06-04 23:10:05 +03:00
|
|
|
// Basic route with one intermediate hop.
|
|
|
|
{target: "sophon", paymentAmt: 100, feeLimit: noFeeLimit,
|
|
|
|
expectedTotalTimeLock: 102, expectedTotalAmt: 100110,
|
2018-06-07 12:00:58 +03:00
|
|
|
expectedHops: []expectedHop{
|
|
|
|
{alias: "songoku", fwdAmount: 100000, fee: 110, timeLock: 101},
|
|
|
|
{alias: "sophon", fwdAmount: 100000, fee: 0, timeLock: 101},
|
|
|
|
}},
|
2018-06-04 23:10:05 +03:00
|
|
|
|
|
|
|
// Basic direct (one hop) route.
|
|
|
|
{target: "luoji", paymentAmt: 100, feeLimit: noFeeLimit,
|
|
|
|
expectedTotalTimeLock: 101, expectedTotalAmt: 100000,
|
2018-06-07 12:00:58 +03:00
|
|
|
expectedHops: []expectedHop{
|
|
|
|
{alias: "luoji", fwdAmount: 100000, fee: 0, timeLock: 101},
|
|
|
|
}},
|
2018-06-04 23:10:05 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// Three hop route where fees need to be added in to the forwarding amount.
|
2018-06-04 23:10:05 +03:00
|
|
|
// The high fee hop phamnewun should be avoided.
|
|
|
|
{target: "elst", paymentAmt: 50000, feeLimit: noFeeLimit,
|
|
|
|
expectedTotalTimeLock: 103, expectedTotalAmt: 50050210,
|
2018-06-07 12:00:58 +03:00
|
|
|
expectedHops: []expectedHop{
|
|
|
|
{alias: "songoku", fwdAmount: 50000200, fee: 50010, timeLock: 102},
|
|
|
|
{alias: "sophon", fwdAmount: 50000000, fee: 200, timeLock: 101},
|
|
|
|
{alias: "elst", fwdAmount: 50000000, fee: 0, timeLock: 101},
|
|
|
|
}},
|
|
|
|
// Three hop route where fees need to be added in to the forwarding amount.
|
|
|
|
// However this time the fwdAmount becomes too large for the roasbeef <->
|
|
|
|
// songoku channel. Then there is no other option than to choose the
|
|
|
|
// expensive phamnuwen channel. This test case was failing before
|
|
|
|
// the route search was executed backwards.
|
2018-06-04 23:10:05 +03:00
|
|
|
{target: "elst", paymentAmt: 100000, feeLimit: noFeeLimit,
|
|
|
|
expectedTotalTimeLock: 103, expectedTotalAmt: 110010220,
|
2018-06-07 12:00:58 +03:00
|
|
|
expectedHops: []expectedHop{
|
|
|
|
{alias: "phamnuwen", fwdAmount: 100000200, fee: 10010020, timeLock: 102},
|
|
|
|
{alias: "sophon", fwdAmount: 100000000, fee: 200, timeLock: 101},
|
|
|
|
{alias: "elst", fwdAmount: 100000000, fee: 0, timeLock: 101},
|
2018-06-04 23:10:05 +03:00
|
|
|
}},
|
|
|
|
|
|
|
|
// Basic route with fee limit.
|
|
|
|
{target: "sophon", paymentAmt: 100, feeLimit: 50,
|
|
|
|
expectFailureNoPath: true,
|
|
|
|
}}
|
2018-06-07 12:00:58 +03:00
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
func TestBasicGraphPathFinding(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// With the test graph loaded, we'll test some basic path finding using
|
|
|
|
// the pre-generated graph. Consult the testdata/basic_graph.json file
|
|
|
|
// to follow along with the assumptions we'll use to test the path
|
|
|
|
// finding.
|
|
|
|
|
|
|
|
for _, testCase := range basicGraphPathFindingTests {
|
|
|
|
t.Run(testCase.target, func(subT *testing.T) {
|
|
|
|
testBasicGraphPathFindingCase(subT, graph, aliases, &testCase)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testBasicGraphPathFindingCase(t *testing.T, graph *channeldb.ChannelGraph,
|
|
|
|
aliases aliasMap, test *basicGraphPathFindingTestCase) {
|
|
|
|
|
|
|
|
expectedHops := test.expectedHops
|
|
|
|
expectedHopCount := len(expectedHops)
|
|
|
|
|
2017-03-20 00:32:52 +03:00
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
2018-01-31 07:26:26 +03:00
|
|
|
sourceVertex := Vertex(sourceNode.PubKeyBytes)
|
2017-03-20 00:32:52 +03:00
|
|
|
|
2017-03-21 04:15:50 +03:00
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
2017-09-08 04:25:43 +03:00
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
2017-03-21 04:15:50 +03:00
|
|
|
|
2017-10-19 08:09:38 +03:00
|
|
|
const (
|
|
|
|
startingHeight = 100
|
|
|
|
finalHopCLTV = 1
|
|
|
|
)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
paymentAmt := lnwire.NewMSatFromSatoshis(test.paymentAmt)
|
|
|
|
target := aliases[test.target]
|
2018-03-27 07:14:10 +03:00
|
|
|
path, err := findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, paymentAmt, test.feeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2018-06-04 23:10:05 +03:00
|
|
|
if test.expectFailureNoPath {
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("expected no path to be found")
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
if err != nil {
|
2017-03-20 01:15:24 +03:00
|
|
|
t.Fatalf("unable to find path: %v", err)
|
|
|
|
}
|
2018-02-01 01:36:10 +03:00
|
|
|
|
2018-04-19 17:32:24 +03:00
|
|
|
route, err := newRoute(
|
2018-06-04 23:10:05 +03:00
|
|
|
paymentAmt, test.feeLimit, sourceVertex, path, startingHeight,
|
2018-04-19 17:32:24 +03:00
|
|
|
finalHopCLTV,
|
|
|
|
)
|
2017-03-20 01:15:24 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create path: %v", err)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
if len(route.Hops) != len(expectedHops) {
|
|
|
|
t.Fatalf("route is of incorrect length, expected %v got %v",
|
|
|
|
expectedHopCount, len(route.Hops))
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// Check hop nodes
|
|
|
|
for i := 0; i < len(expectedHops); i++ {
|
|
|
|
if !bytes.Equal(route.Hops[i].Channel.Node.PubKeyBytes[:],
|
|
|
|
aliases[expectedHops[i].alias].SerializeCompressed()) {
|
2018-01-31 07:26:26 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
t.Fatalf("%v-th hop should be %v, is instead: %v",
|
|
|
|
i, expectedHops[i], route.Hops[i].Channel.Node.Alias)
|
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
2017-06-16 23:45:24 +03:00
|
|
|
// Next, we'll assert that the "next hop" field in each route payload
|
|
|
|
// properly points to the channel ID that the HTLC should be forwarded
|
|
|
|
// along.
|
|
|
|
hopPayloads := route.ToHopPayloads()
|
2018-06-07 12:00:58 +03:00
|
|
|
if len(hopPayloads) != expectedHopCount {
|
2017-06-16 23:45:24 +03:00
|
|
|
t.Fatalf("incorrect number of hop payloads: expected %v, got %v",
|
2018-06-07 12:00:58 +03:00
|
|
|
expectedHopCount, len(hopPayloads))
|
2017-06-16 23:45:24 +03:00
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// Hops should point to the next hop
|
|
|
|
for i := 0; i < len(expectedHops)-1; i++ {
|
|
|
|
var expectedHop [8]byte
|
|
|
|
binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].Channel.ChannelID)
|
|
|
|
if !bytes.Equal(hopPayloads[i].NextAddress[:], expectedHop[:]) {
|
|
|
|
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
|
|
|
|
expectedHop[:], hopPayloads[i].NextAddress)
|
|
|
|
}
|
2017-06-16 23:45:24 +03:00
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// The final hop should have a next hop value of all zeroes in order
|
2017-06-16 23:45:24 +03:00
|
|
|
// to indicate it's the exit hop.
|
|
|
|
var exitHop [8]byte
|
2018-06-07 12:00:58 +03:00
|
|
|
lastHopIndex := len(expectedHops) - 1
|
|
|
|
if !bytes.Equal(hopPayloads[lastHopIndex].NextAddress[:], exitHop[:]) {
|
2017-06-16 23:45:24 +03:00
|
|
|
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
|
2018-06-07 12:00:58 +03:00
|
|
|
exitHop[:], hopPayloads[lastHopIndex].NextAddress)
|
2017-06-16 23:45:24 +03:00
|
|
|
}
|
|
|
|
|
2018-06-04 23:10:05 +03:00
|
|
|
var expectedTotalFee lnwire.MilliSatoshi
|
2018-06-07 12:00:58 +03:00
|
|
|
for i := 0; i < expectedHopCount; i++ {
|
|
|
|
// We'll ensure that the amount to forward, and fees
|
|
|
|
// computed for each hop are correct.
|
2017-10-19 08:09:38 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
if route.Hops[i].Fee != expectedHops[i].fee {
|
|
|
|
t.Fatalf("fee incorrect for hop %v: expected %v, got %v",
|
|
|
|
i, expectedHops[i].fee, route.Hops[i].Fee)
|
|
|
|
}
|
2017-10-19 08:09:38 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
if route.Hops[i].AmtToForward != expectedHops[i].fwdAmount {
|
|
|
|
t.Fatalf("forwarding amount for hop %v incorrect: "+
|
|
|
|
"expected %v, got %v",
|
|
|
|
i, expectedHops[i].fwdAmount,
|
|
|
|
route.Hops[i].AmtToForward)
|
|
|
|
}
|
2017-06-16 23:45:24 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// We'll also assert that the outgoing CLTV value for each
|
|
|
|
// hop was set accordingly.
|
|
|
|
if route.Hops[i].OutgoingTimeLock != expectedHops[i].timeLock {
|
|
|
|
t.Fatalf("outgoing time-lock for hop %v is incorrect: "+
|
|
|
|
"expected %v, got %v", i,
|
|
|
|
expectedHops[i].timeLock,
|
|
|
|
route.Hops[i].OutgoingTimeLock)
|
|
|
|
}
|
2018-01-11 02:15:49 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
expectedTotalFee += expectedHops[i].fee
|
2018-01-11 02:15:49 +03:00
|
|
|
}
|
|
|
|
|
2018-06-04 23:10:05 +03:00
|
|
|
if route.TotalAmount != test.expectedTotalAmt {
|
2018-06-07 12:00:58 +03:00
|
|
|
t.Fatalf("total amount incorrect: "+
|
|
|
|
"expected %v, got %v",
|
2018-06-04 23:10:05 +03:00
|
|
|
test.expectedTotalAmt, route.TotalAmount)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
2018-02-01 01:36:10 +03:00
|
|
|
|
2018-06-04 23:10:05 +03:00
|
|
|
if route.TotalTimeLock != test.expectedTotalTimeLock {
|
2018-06-07 12:00:58 +03:00
|
|
|
t.Fatalf("expected time lock of %v, instead have %v", 2,
|
|
|
|
route.TotalTimeLock)
|
2017-03-20 01:15:24 +03:00
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// The next and prev hop maps should be properly set.
|
|
|
|
for i := 0; i < expectedHopCount; i++ {
|
|
|
|
prevChan, ok := route.prevHopChannel(aliases[expectedHops[i].alias])
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("hop didn't have prev chan but should have")
|
|
|
|
}
|
|
|
|
if prevChan.ChannelID != route.Hops[i].Channel.ChannelID {
|
|
|
|
t.Fatalf("incorrect prev chan: expected %v, got %v",
|
|
|
|
prevChan.ChannelID, route.Hops[i].Channel.ChannelID)
|
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
for i := 0; i < expectedHopCount-1; i++ {
|
|
|
|
nextChan, ok := route.nextHopChannel(aliases[expectedHops[i].alias])
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("hop didn't have prev chan but should have")
|
|
|
|
}
|
|
|
|
if nextChan.ChannelID != route.Hops[i+1].Channel.ChannelID {
|
|
|
|
t.Fatalf("incorrect prev chan: expected %v, got %v",
|
|
|
|
nextChan.ChannelID, route.Hops[i+1].Channel.ChannelID)
|
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// Final hop shouldn't have a next chan
|
|
|
|
if _, ok := route.nextHopChannel(aliases[expectedHops[lastHopIndex].alias]); ok {
|
|
|
|
t.Fatalf("incorrect next hop map, no vertexes should " +
|
|
|
|
"be after sophon")
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-27 07:32:37 +03:00
|
|
|
func TestPathFindingWithAdditionalEdges(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
|
|
|
|
|
|
|
// In this test, we'll test that we're able to find paths through
|
|
|
|
// private channels when providing them as additional edges in our path
|
|
|
|
// finding algorithm. To do so, we'll create a new node, doge, and
|
|
|
|
// create a private channel between it and songoku. We'll then attempt
|
|
|
|
// to find a path from our source node, roasbeef, to doge.
|
|
|
|
dogePubKeyHex := "03dd46ff29a6941b4a2607525b043ec9b020b3f318a1bf281536fd7011ec59c882"
|
|
|
|
dogePubKeyBytes, err := hex.DecodeString(dogePubKeyHex)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to decode public key: %v", err)
|
|
|
|
}
|
|
|
|
dogePubKey, err := btcec.ParsePubKey(dogePubKeyBytes, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to parse public key from bytes: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
doge := &channeldb.LightningNode{}
|
|
|
|
doge.AddPubKey(dogePubKey)
|
|
|
|
doge.Alias = "doge"
|
|
|
|
|
|
|
|
// Create the channel edge going from songoku to doge and include it in
|
|
|
|
// our map of additional edges.
|
|
|
|
songokuToDoge := &channeldb.ChannelEdgePolicy{
|
|
|
|
Node: doge,
|
|
|
|
ChannelID: 1337,
|
|
|
|
FeeBaseMSat: 1,
|
|
|
|
FeeProportionalMillionths: 1000,
|
|
|
|
TimeLockDelta: 9,
|
|
|
|
}
|
|
|
|
|
|
|
|
additionalEdges := map[Vertex][]*channeldb.ChannelEdgePolicy{
|
|
|
|
NewVertex(aliases["songoku"]): {songokuToDoge},
|
|
|
|
}
|
|
|
|
|
|
|
|
// We should now be able to find a path from roasbeef to doge.
|
|
|
|
path, err := findPath(
|
|
|
|
nil, graph, additionalEdges, sourceNode, dogePubKey, nil, nil,
|
2018-06-04 23:10:05 +03:00
|
|
|
paymentAmt, noFeeLimit, nil,
|
2018-03-27 07:32:37 +03:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find private path to doge: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// The path should represent the following hops:
|
|
|
|
// roasbeef -> songoku -> doge
|
|
|
|
assertExpectedPath(t, path, "songoku", "doge")
|
|
|
|
}
|
|
|
|
|
2017-03-21 04:22:04 +03:00
|
|
|
func TestKShortestPathFinding(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2017-03-21 04:22:04 +03:00
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// In this test we'd like to ensure that our algorithm to find the
|
2017-03-21 04:22:04 +03:00
|
|
|
// k-shortest paths from a given source node to any destination node
|
2018-02-07 06:11:11 +03:00
|
|
|
// works as expected.
|
2017-03-21 04:22:04 +03:00
|
|
|
|
|
|
|
// In our basic_graph.json, there exist two paths from roasbeef to luo
|
|
|
|
// ji. Our algorithm should properly find both paths, and also rank
|
|
|
|
// them in order of their total "distance".
|
|
|
|
|
2017-08-22 09:43:20 +03:00
|
|
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
2017-03-21 04:22:04 +03:00
|
|
|
target := aliases["luoji"]
|
2018-02-13 03:27:30 +03:00
|
|
|
paths, err := findPaths(
|
2018-06-04 23:10:05 +03:00
|
|
|
nil, graph, sourceNode, target, paymentAmt, noFeeLimit, 100,
|
2018-05-08 07:04:31 +03:00
|
|
|
nil,
|
2018-02-13 03:27:30 +03:00
|
|
|
)
|
2017-03-21 04:22:04 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find paths between roasbeef and "+
|
|
|
|
"luo ji: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// The algorithm should have found two paths from roasbeef to luo ji.
|
2017-03-21 04:22:04 +03:00
|
|
|
if len(paths) != 2 {
|
|
|
|
t.Fatalf("two path shouldn't been found, instead %v were",
|
|
|
|
len(paths))
|
|
|
|
}
|
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// Additionally, the total hop length of the first path returned should
|
2017-03-21 04:22:04 +03:00
|
|
|
// be _less_ than that of the second path returned.
|
|
|
|
if len(paths[0]) > len(paths[1]) {
|
|
|
|
t.Fatalf("paths found not ordered properly")
|
|
|
|
}
|
|
|
|
|
|
|
|
// The first route should be a direct route to luo ji.
|
2018-03-27 07:32:37 +03:00
|
|
|
assertExpectedPath(t, paths[0], "roasbeef", "luoji")
|
2017-03-21 04:22:04 +03:00
|
|
|
|
|
|
|
// The second route should be a route to luo ji via satoshi.
|
2018-03-27 07:32:37 +03:00
|
|
|
assertExpectedPath(t, paths[1], "roasbeef", "satoshi", "luoji")
|
2017-03-21 04:22:04 +03:00
|
|
|
}
|
|
|
|
|
2018-06-12 14:04:40 +03:00
|
|
|
// TestNewRoute tests whether the construction of hop payloads by newRoute
|
|
|
|
// is executed correctly.
|
|
|
|
func TestNewRoute(t *testing.T) {
|
|
|
|
|
|
|
|
var sourceKey [33]byte
|
|
|
|
sourceVertex := Vertex(sourceKey)
|
|
|
|
|
|
|
|
const (
|
|
|
|
startingHeight = 100
|
|
|
|
finalHopCLTV = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
createHop := func(baseFee lnwire.MilliSatoshi,
|
2018-07-31 10:20:22 +03:00
|
|
|
feeRate lnwire.MilliSatoshi,
|
2018-06-13 10:59:02 +03:00
|
|
|
bandwidth lnwire.MilliSatoshi,
|
2018-07-31 10:20:22 +03:00
|
|
|
timeLockDelta uint16) *ChannelHop {
|
2018-06-12 14:04:40 +03:00
|
|
|
|
2018-07-31 10:20:22 +03:00
|
|
|
return &ChannelHop{
|
|
|
|
ChannelEdgePolicy: &channeldb.ChannelEdgePolicy{
|
2018-06-12 14:04:40 +03:00
|
|
|
Node: &channeldb.LightningNode{},
|
|
|
|
FeeProportionalMillionths: feeRate,
|
2018-07-31 10:20:22 +03:00
|
|
|
FeeBaseMSat: baseFee,
|
|
|
|
TimeLockDelta: timeLockDelta,
|
2018-06-12 14:04:40 +03:00
|
|
|
},
|
2018-06-13 10:59:02 +03:00
|
|
|
Bandwidth: bandwidth,
|
2018-06-12 14:04:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-31 10:20:22 +03:00
|
|
|
testCases := []struct {
|
2018-06-27 12:01:18 +03:00
|
|
|
// name identifies the test case in the test output.
|
2018-07-31 10:20:22 +03:00
|
|
|
name string
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// hops is the list of hops (the route) that gets passed into
|
|
|
|
// the call to newRoute.
|
2018-07-31 10:20:22 +03:00
|
|
|
hops []*ChannelHop
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// paymentAmount is the amount that is send into the route
|
|
|
|
// indicated by hops.
|
2018-07-31 10:20:22 +03:00
|
|
|
paymentAmount lnwire.MilliSatoshi
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// expectedFees is a list of fees that every hop is expected
|
|
|
|
// to charge for forwarding.
|
2018-07-31 10:20:22 +03:00
|
|
|
expectedFees []lnwire.MilliSatoshi
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// expectedTimeLocks is a list of time lock values that every
|
|
|
|
// hop is expected to specify in its outgoing HTLC. The time
|
|
|
|
// lock values in this list are relative to the current block
|
|
|
|
// height.
|
2018-07-31 10:20:22 +03:00
|
|
|
expectedTimeLocks []uint32
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// expectedTotalAmount is the total amount that is expected to
|
|
|
|
// be returned from newRoute. This amount should include all
|
|
|
|
// the fees to be paid to intermediate hops.
|
2018-07-31 10:20:22 +03:00
|
|
|
expectedTotalAmount lnwire.MilliSatoshi
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// expectedTotalTimeLock is the time lock that is expected to
|
|
|
|
// be returned from newRoute. This is the time lock that should
|
|
|
|
// be specified in the HTLC that is sent by the source node.
|
|
|
|
// expectedTotalTimeLock is relative to the current block height.
|
|
|
|
expectedTotalTimeLock uint32
|
|
|
|
|
|
|
|
// expectError indicates whether the newRoute call is expected
|
|
|
|
// to fail or succeed.
|
2018-07-31 10:20:22 +03:00
|
|
|
expectError bool
|
2018-06-27 12:01:18 +03:00
|
|
|
|
|
|
|
// expectedErrorCode indicates the expected error code when
|
|
|
|
// expectError is true.
|
2018-07-31 10:20:22 +03:00
|
|
|
expectedErrorCode errorCode
|
2018-06-13 10:59:02 +03:00
|
|
|
|
|
|
|
feeLimit lnwire.MilliSatoshi
|
2018-07-31 10:20:22 +03:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
// For a single hop payment, no fees are expected to be paid.
|
|
|
|
name: "single hop",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(100, 1000, 1000000, 10),
|
2018-07-31 10:20:22 +03:00
|
|
|
},
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{0},
|
|
|
|
expectedTimeLocks: []uint32{1},
|
|
|
|
expectedTotalAmount: 100000,
|
|
|
|
expectedTotalTimeLock: 1,
|
2018-06-13 10:59:02 +03:00
|
|
|
feeLimit: noFeeLimit,
|
2018-07-31 10:20:22 +03:00
|
|
|
}, {
|
|
|
|
// For a two hop payment, only the fee for the first hop
|
|
|
|
// needs to be paid. The destination hop does not require
|
|
|
|
// a fee to receive the payment.
|
|
|
|
name: "two hop",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(0, 1000, 1000000, 10),
|
|
|
|
createHop(30, 1000, 1000000, 5),
|
2018-07-31 10:20:22 +03:00
|
|
|
},
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{130, 0},
|
|
|
|
expectedTimeLocks: []uint32{1, 1},
|
|
|
|
expectedTotalAmount: 100130,
|
|
|
|
expectedTotalTimeLock: 6,
|
2018-06-13 10:59:02 +03:00
|
|
|
feeLimit: noFeeLimit,
|
2018-07-31 10:20:22 +03:00
|
|
|
}, {
|
|
|
|
// Insufficient capacity in first channel when fees are added.
|
|
|
|
name: "two hop insufficient",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(0, 1000, 100000, 10),
|
|
|
|
createHop(0, 1000, 1000000, 5),
|
2018-07-31 10:20:22 +03:00
|
|
|
},
|
2018-06-13 10:59:02 +03:00
|
|
|
feeLimit: noFeeLimit,
|
2018-07-31 10:20:22 +03:00
|
|
|
expectError: true,
|
|
|
|
expectedErrorCode: ErrInsufficientCapacity,
|
|
|
|
}, {
|
|
|
|
// A three hop payment where the first and second hop
|
|
|
|
// will both charge 1 msat. The fee for the first hop
|
|
|
|
// is actually slightly higher than 1, because the amount
|
|
|
|
// to forward also includes the fee for the second hop. This
|
|
|
|
// gets rounded down to 1.
|
|
|
|
name: "three hop",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(0, 10, 1000000, 10),
|
|
|
|
createHop(0, 10, 1000000, 5),
|
|
|
|
createHop(0, 10, 1000000, 3),
|
2018-07-31 10:20:22 +03:00
|
|
|
},
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{1, 1, 0},
|
|
|
|
expectedTotalAmount: 100002,
|
|
|
|
expectedTimeLocks: []uint32{4, 1, 1},
|
|
|
|
expectedTotalTimeLock: 9,
|
2018-06-13 10:59:02 +03:00
|
|
|
feeLimit: noFeeLimit,
|
2018-07-31 10:20:22 +03:00
|
|
|
}, {
|
|
|
|
// A three hop payment where the fee of the first hop
|
|
|
|
// is slightly higher (11) than the fee at the second hop,
|
|
|
|
// because of the increase amount to forward.
|
|
|
|
name: "three hop with fee carry over",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(0, 10000, 1000000, 10),
|
|
|
|
createHop(0, 10000, 1000000, 5),
|
|
|
|
createHop(0, 10000, 1000000, 3),
|
2018-07-31 10:20:22 +03:00
|
|
|
},
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{1010, 1000, 0},
|
|
|
|
expectedTotalAmount: 102010,
|
|
|
|
expectedTimeLocks: []uint32{4, 1, 1},
|
|
|
|
expectedTotalTimeLock: 9,
|
2018-06-13 10:59:02 +03:00
|
|
|
feeLimit: noFeeLimit,
|
2018-07-31 10:20:22 +03:00
|
|
|
}, {
|
|
|
|
// A three hop payment where the fee policies of the first and
|
|
|
|
// second hop are just high enough to show the fee carry over
|
|
|
|
// effect.
|
|
|
|
name: "three hop with minimal fees for carry over",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(0, 10000, 1000000, 10),
|
2018-07-31 10:20:22 +03:00
|
|
|
|
|
|
|
// First hop charges 0.1% so the second hop fee
|
|
|
|
// should show up in the first hop fee as 1 msat
|
|
|
|
// extra.
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(0, 1000, 1000000, 5),
|
2018-07-31 10:20:22 +03:00
|
|
|
|
|
|
|
// Second hop charges a fixed 1000 msat.
|
2018-06-13 10:59:02 +03:00
|
|
|
createHop(1000, 0, 1000000, 3),
|
2018-07-31 10:20:22 +03:00
|
|
|
},
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{101, 1000, 0},
|
|
|
|
expectedTotalAmount: 101101,
|
|
|
|
expectedTimeLocks: []uint32{4, 1, 1},
|
|
|
|
expectedTotalTimeLock: 9,
|
2018-06-13 10:59:02 +03:00
|
|
|
feeLimit: noFeeLimit,
|
|
|
|
},
|
|
|
|
// Check fee limit behaviour
|
|
|
|
{
|
|
|
|
name: "two hop success with fee limit (greater)",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
},
|
|
|
|
expectedTotalAmount: 100100,
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{100, 0},
|
|
|
|
expectedTimeLocks: []uint32{1, 1},
|
|
|
|
expectedTotalTimeLock: 145,
|
|
|
|
feeLimit: 150,
|
|
|
|
}, {
|
|
|
|
name: "two hop success with fee limit (equal)",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
},
|
|
|
|
expectedTotalAmount: 100100,
|
|
|
|
expectedFees: []lnwire.MilliSatoshi{100, 0},
|
|
|
|
expectedTimeLocks: []uint32{1, 1},
|
|
|
|
expectedTotalTimeLock: 145,
|
|
|
|
feeLimit: 100,
|
|
|
|
}, {
|
|
|
|
name: "two hop failure with fee limit (smaller)",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
},
|
|
|
|
feeLimit: 50,
|
|
|
|
expectError: true,
|
|
|
|
expectedErrorCode: ErrFeeLimitExceeded,
|
|
|
|
}, {
|
|
|
|
name: "two hop failure with fee limit (zero)",
|
|
|
|
paymentAmount: 100000,
|
|
|
|
hops: []*ChannelHop{
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
createHop(0, 1000, 1000000, 144),
|
|
|
|
},
|
|
|
|
feeLimit: 0,
|
|
|
|
expectError: true,
|
|
|
|
expectedErrorCode: ErrFeeLimitExceeded,
|
2018-07-31 10:20:22 +03:00
|
|
|
}}
|
|
|
|
|
2018-06-12 14:04:40 +03:00
|
|
|
for _, testCase := range testCases {
|
|
|
|
assertRoute := func(t *testing.T, route *Route) {
|
|
|
|
if route.TotalAmount != testCase.expectedTotalAmount {
|
2018-07-31 10:20:22 +03:00
|
|
|
t.Errorf("Expected total amount is be %v"+
|
2018-06-12 14:04:40 +03:00
|
|
|
", but got %v instead",
|
|
|
|
testCase.expectedTotalAmount,
|
|
|
|
route.TotalAmount)
|
|
|
|
}
|
2018-06-27 12:01:18 +03:00
|
|
|
|
2018-06-12 14:04:40 +03:00
|
|
|
for i := 0; i < len(testCase.expectedFees); i++ {
|
|
|
|
if testCase.expectedFees[i] !=
|
|
|
|
route.Hops[i].Fee {
|
2018-07-31 10:20:22 +03:00
|
|
|
|
|
|
|
t.Errorf("Expected fee for hop %v to "+
|
|
|
|
"be %v, but got %v instead",
|
|
|
|
i, testCase.expectedFees[i],
|
|
|
|
route.Hops[i].Fee)
|
2018-06-12 14:04:40 +03:00
|
|
|
}
|
|
|
|
}
|
2018-06-27 12:01:18 +03:00
|
|
|
|
2018-07-31 10:20:22 +03:00
|
|
|
expectedTimeLockHeight := startingHeight +
|
2018-06-27 12:01:18 +03:00
|
|
|
testCase.expectedTotalTimeLock
|
|
|
|
|
|
|
|
if route.TotalTimeLock != expectedTimeLockHeight {
|
2018-07-31 10:20:22 +03:00
|
|
|
|
|
|
|
t.Errorf("Expected total time lock to be %v"+
|
2018-06-27 12:01:18 +03:00
|
|
|
", but got %v instead",
|
|
|
|
expectedTimeLockHeight,
|
|
|
|
route.TotalTimeLock)
|
|
|
|
}
|
2018-07-31 10:20:22 +03:00
|
|
|
|
2018-06-27 12:01:18 +03:00
|
|
|
for i := 0; i < len(testCase.expectedTimeLocks); i++ {
|
2018-07-31 10:20:22 +03:00
|
|
|
expectedTimeLockHeight := startingHeight +
|
2018-06-27 12:01:18 +03:00
|
|
|
testCase.expectedTimeLocks[i]
|
|
|
|
|
|
|
|
if expectedTimeLockHeight !=
|
|
|
|
route.Hops[i].OutgoingTimeLock {
|
2018-07-31 10:20:22 +03:00
|
|
|
|
|
|
|
t.Errorf("Expected time lock for hop "+
|
2018-06-27 12:01:18 +03:00
|
|
|
"%v to be %v, but got %v instead",
|
2018-07-31 10:20:22 +03:00
|
|
|
i, expectedTimeLockHeight,
|
|
|
|
route.Hops[i].OutgoingTimeLock)
|
2018-06-27 12:01:18 +03:00
|
|
|
}
|
|
|
|
}
|
2018-06-12 14:04:40 +03:00
|
|
|
}
|
2018-07-31 10:20:22 +03:00
|
|
|
|
2018-06-12 14:04:40 +03:00
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
2018-07-31 10:20:22 +03:00
|
|
|
route, err := newRoute(testCase.paymentAmount,
|
2018-06-13 10:59:02 +03:00
|
|
|
testCase.feeLimit,
|
2018-06-12 14:04:40 +03:00
|
|
|
sourceVertex, testCase.hops, startingHeight,
|
|
|
|
finalHopCLTV)
|
|
|
|
|
|
|
|
if testCase.expectError {
|
|
|
|
expectedCode := testCase.expectedErrorCode
|
|
|
|
if err == nil || !IsError(err, expectedCode) {
|
2018-06-13 10:59:02 +03:00
|
|
|
t.Fatalf("expected newRoute to fail "+
|
|
|
|
"with error code %v but got "+
|
2018-07-31 10:20:22 +03:00
|
|
|
"%v instead",
|
|
|
|
expectedCode, err)
|
2018-06-12 14:04:40 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unable to create path: %v", err)
|
2018-06-13 10:59:02 +03:00
|
|
|
return
|
2018-06-12 14:04:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
assertRoute(t, route)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
func TestNewRoutePathTooLong(t *testing.T) {
|
2017-10-19 08:10:00 +03:00
|
|
|
t.Skip()
|
2017-06-17 01:59:20 +03:00
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// Ensure that potential paths which are over the maximum hop-limit are
|
|
|
|
// rejected.
|
2017-02-01 18:48:30 +03:00
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(excessiveHopsGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
2017-03-20 00:32:52 +03:00
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-03-21 04:15:50 +03:00
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
2017-09-08 04:25:43 +03:00
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
2017-03-21 04:15:50 +03:00
|
|
|
|
2017-08-22 09:43:20 +03:00
|
|
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
2017-02-01 18:48:30 +03:00
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// We start by confirming that routing a payment 20 hops away is possible.
|
2017-02-01 18:48:30 +03:00
|
|
|
// Alice should be able to find a valid route to ursula.
|
|
|
|
target := aliases["ursula"]
|
2018-03-27 07:14:10 +03:00
|
|
|
_, err = findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, paymentAmt, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-03-21 04:15:50 +03:00
|
|
|
if err != nil {
|
2017-02-01 18:48:30 +03:00
|
|
|
t.Fatalf("path should have been found")
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
2017-02-01 18:48:30 +03:00
|
|
|
|
|
|
|
// Vincent is 21 hops away from Alice, and thus no valid route should be
|
|
|
|
// presented to Alice.
|
|
|
|
target = aliases["vincent"]
|
2018-03-27 07:14:10 +03:00
|
|
|
path, err := findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, paymentAmt, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-02-01 18:48:30 +03:00
|
|
|
if err == nil {
|
2017-03-20 00:32:52 +03:00
|
|
|
t.Fatalf("should not have been able to find path, supposed to be "+
|
|
|
|
"greater than 20 hops, found route with %v hops",
|
2017-03-20 01:15:24 +03:00
|
|
|
len(path))
|
2017-02-01 18:48:30 +03:00
|
|
|
}
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPathNotAvailable(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
graph, cleanUp, _, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-03-20 00:32:52 +03:00
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-03-21 04:15:50 +03:00
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
2017-09-08 04:25:43 +03:00
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
2017-03-21 04:15:50 +03:00
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// With the test graph loaded, we'll test that queries for target that
|
|
|
|
// are either unreachable within the graph, or unknown result in an
|
|
|
|
// error.
|
|
|
|
unknownNodeStr := "03dd46ff29a6941b4a2607525b043ec9b020b3f318a1bf281536fd7011ec59c882"
|
|
|
|
unknownNodeBytes, err := hex.DecodeString(unknownNodeStr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to parse bytes: %v", err)
|
|
|
|
}
|
|
|
|
unknownNode, err := btcec.ParsePubKey(unknownNodeBytes, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to parse pubkey: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-03-27 07:14:10 +03:00
|
|
|
_, err = findPath(
|
|
|
|
nil, graph, nil, sourceNode, unknownNode, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, 100, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-03-19 21:40:25 +03:00
|
|
|
if !IsError(err, ErrNoPathFound) {
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
t.Fatalf("path shouldn't have been found: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPathInsufficientCapacity(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-03-20 00:32:52 +03:00
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
2017-03-21 04:15:50 +03:00
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
2017-09-08 04:25:43 +03:00
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
2017-03-20 00:32:52 +03:00
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// Next, test that attempting to find a path in which the current
|
|
|
|
// channel graph cannot support due to insufficient capacity triggers
|
|
|
|
// an error.
|
|
|
|
|
|
|
|
// To test his we'll attempt to make a payment of 1 BTC, or 100 million
|
|
|
|
// satoshis. The largest channel in the basic graph is of size 100k
|
|
|
|
// satoshis, so we shouldn't be able to find a path to sophon even
|
|
|
|
// though we have a 2-hop link.
|
|
|
|
target := aliases["sophon"]
|
|
|
|
|
2018-03-23 03:39:21 +03:00
|
|
|
payAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
2018-03-27 07:14:10 +03:00
|
|
|
_, err = findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, payAmt, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-03-19 21:40:25 +03:00
|
|
|
if !IsError(err, ErrNoPathFound) {
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
|
|
|
}
|
2017-12-01 09:31:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// TestRouteFailMinHTLC tests that if we attempt to route an HTLC which is
|
|
|
|
// smaller than the advertised minHTLC of an edge, then path finding fails.
|
|
|
|
func TestRouteFailMinHTLC(t *testing.T) {
|
2018-04-19 17:32:24 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2017-12-01 09:31:18 +03:00
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
|
|
|
|
|
|
|
// We'll not attempt to route an HTLC of 10 SAT from roasbeef to Son
|
|
|
|
// Goku. However, the min HTLC of Son Goku is 1k SAT, as a result, this
|
|
|
|
// attempt should fail.
|
|
|
|
target := aliases["songoku"]
|
|
|
|
payAmt := lnwire.MilliSatoshi(10)
|
2018-03-27 07:14:10 +03:00
|
|
|
_, err = findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, payAmt, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-12-01 09:31:18 +03:00
|
|
|
if !IsError(err, ErrNoPathFound) {
|
|
|
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestRouteFailDisabledEdge tests that if we attempt to route to an edge
|
|
|
|
// that's disabled, then that edge is disqualified, and the routing attempt
|
|
|
|
// will fail.
|
|
|
|
func TestRouteFailDisabledEdge(t *testing.T) {
|
2018-04-19 17:32:24 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2017-12-01 09:31:18 +03:00
|
|
|
graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create graph: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceNode, err := graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch source node: %v", err)
|
|
|
|
}
|
|
|
|
ignoredEdges := make(map[uint64]struct{})
|
|
|
|
ignoredVertexes := make(map[Vertex]struct{})
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// First, we'll try to route from roasbeef -> sophon. This should
|
|
|
|
// succeed without issue, and return a single path via phamnuwen
|
|
|
|
target := aliases["sophon"]
|
2018-06-04 23:10:05 +03:00
|
|
|
payAmt := lnwire.NewMSatFromSatoshis(105000)
|
2018-03-27 07:14:10 +03:00
|
|
|
_, err = findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, payAmt, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-12-01 09:31:18 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find path: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-06-07 12:00:58 +03:00
|
|
|
// First, we'll modify the edge from roasbeef -> phamnuwen, to read that
|
2017-12-01 09:31:18 +03:00
|
|
|
// it's disabled.
|
2018-06-07 12:00:58 +03:00
|
|
|
_, _, phamnuwenEdge, err := graph.FetchChannelEdgesByID(999991)
|
2017-12-01 09:31:18 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch goku's edge: %v", err)
|
|
|
|
}
|
2018-06-07 12:00:58 +03:00
|
|
|
phamnuwenEdge.Flags = lnwire.ChanUpdateDisabled | lnwire.ChanUpdateDirection
|
|
|
|
if err := graph.UpdateEdgePolicy(phamnuwenEdge); err != nil {
|
2017-12-01 09:31:18 +03:00
|
|
|
t.Fatalf("unable to update edge: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-12-18 05:40:05 +03:00
|
|
|
// Now, if we attempt to route through that edge, we should get a
|
2018-02-07 06:11:11 +03:00
|
|
|
// failure as it is no longer eligible.
|
2018-03-27 07:14:10 +03:00
|
|
|
_, err = findPath(
|
|
|
|
nil, graph, nil, sourceNode, target, ignoredVertexes,
|
2018-06-04 23:10:05 +03:00
|
|
|
ignoredEdges, payAmt, noFeeLimit, nil,
|
2018-03-27 07:14:10 +03:00
|
|
|
)
|
2017-12-01 09:31:18 +03:00
|
|
|
if !IsError(err, ErrNoPathFound) {
|
|
|
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
|
|
|
}
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPathInsufficientCapacityWithFee(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
// TODO(roasbeef): encode live graph to json
|
2017-03-20 00:11:25 +03:00
|
|
|
|
|
|
|
// TODO(roasbeef): need to add a case, or modify the fee ratio for one
|
|
|
|
// to ensure that has going forward, but when fees are applied doesn't
|
|
|
|
// work
|
routing: rewrite package to conform to BOLT07 and factor in fees+timelocks
This commit overhauls the routing package significantly to simplify the
code, conform to the rest of the coding style within the package, and
observe the new authenticated gossiping scheme outlined in BOLT07.
As a major step towards a more realistic path finding algorithm, fees
are properly calculated and observed during path finding. If a path has
sufficient capacity _before_ fees are applied, but afterwards the
finalized route would exceed the capacity of a single link, the route
is marked as invalid.
Currently a naive weighting algorithm is used which only factors in the
time-lock delta at each hop, thereby optimizing for the lowest time
lock. Fee calculation also isn’t finalized since we aren’t yet using
milli-satoshi throughout the daemon. The final TODO item within the PR
is to properly perform a multi-path search and rank the results based
on a summation heuristic rather than just return the first (out of
many) route found.
On the server side, once nodes are initially connected to the daemon,
our routing table will be synced with the peer’s using a naive “just
send everything scheme” to hold us over until I spec out some a
efficient graph reconciliation protocol. Additionally, the routing
table is now pruned by the channel router itself once new blocks arrive
rather than depending on peers to tell us when a channel flaps or is
closed.
Finally, the validation of peer announcements aren’t yet fully
implemented as they’ll be implemented within the pending discovery
package that was blocking on the completion of this package. Most off
the routing message processing will be moved out of this package and
into the discovery package where full validation will be carried out.
2016-12-27 08:20:26 +03:00
|
|
|
}
|
2017-06-16 23:45:24 +03:00
|
|
|
|
2017-10-19 08:10:00 +03:00
|
|
|
func TestPathFindSpecExample(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// All our path finding tests will assume a starting height of 100, so
|
|
|
|
// we'll pass that in to ensure that the router uses 100 as the current
|
|
|
|
// height.
|
|
|
|
const startingHeight = 100
|
|
|
|
ctx, cleanUp, err := createTestCtx(startingHeight, specExampleFilePath)
|
|
|
|
defer cleanUp()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create router: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
aliceFinalCLTV = 10
|
|
|
|
bobFinalCLTV = 20
|
|
|
|
carolFinalCLTV = 30
|
|
|
|
daveFinalCLTV = 40
|
|
|
|
)
|
|
|
|
|
|
|
|
// We'll first exercise the scenario of a direct payment from Bob to
|
|
|
|
// Carol, so we set "B" as the source node so path finding starts from
|
|
|
|
// Bob.
|
|
|
|
bob := ctx.aliases["B"]
|
|
|
|
bobNode, err := ctx.graph.FetchLightningNode(bob)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find bob: %v", err)
|
|
|
|
}
|
|
|
|
if err := ctx.graph.SetSourceNode(bobNode); err != nil {
|
|
|
|
t.Fatalf("unable to set source node: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Query for a route of 4,999,999 mSAT to carol.
|
|
|
|
carol := ctx.aliases["C"]
|
|
|
|
const amt lnwire.MilliSatoshi = 4999999
|
2018-04-19 17:32:24 +03:00
|
|
|
routes, err := ctx.router.FindRoutes(carol, amt, noFeeLimit, 100)
|
2017-10-19 08:10:00 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find route: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We should come back with _exactly_ two routes.
|
|
|
|
if len(routes) != 2 {
|
|
|
|
t.Fatalf("expected %v routes, instead have: %v", 2,
|
|
|
|
len(routes))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we'll examine the first route returned for correctness.
|
|
|
|
//
|
2018-02-07 06:11:11 +03:00
|
|
|
// It should be sending the exact payment amount as there are no
|
2017-10-19 08:10:00 +03:00
|
|
|
// additional hops.
|
|
|
|
firstRoute := routes[0]
|
|
|
|
if firstRoute.TotalAmount != amt {
|
|
|
|
t.Fatalf("wrong total amount: got %v, expected %v",
|
|
|
|
firstRoute.TotalAmount, amt)
|
|
|
|
}
|
|
|
|
if firstRoute.Hops[0].AmtToForward != amt {
|
|
|
|
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
|
|
firstRoute.Hops[0].AmtToForward, amt)
|
|
|
|
}
|
|
|
|
if firstRoute.Hops[0].Fee != 0 {
|
|
|
|
t.Fatalf("wrong hop fee: got %v, expected %v",
|
|
|
|
firstRoute.Hops[0].Fee, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// The CLTV expiry should be the current height plus 9 (the expiry for
|
|
|
|
// the B -> C channel.
|
|
|
|
if firstRoute.TotalTimeLock !=
|
|
|
|
startingHeight+DefaultFinalCLTVDelta {
|
|
|
|
|
|
|
|
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
|
|
firstRoute.TotalTimeLock,
|
|
|
|
startingHeight+DefaultFinalCLTVDelta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next, we'll set A as the source node so we can assert that we create
|
|
|
|
// the proper route for any queries starting with Alice.
|
|
|
|
alice := ctx.aliases["A"]
|
|
|
|
aliceNode, err := ctx.graph.FetchLightningNode(alice)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find alice: %v", err)
|
|
|
|
}
|
|
|
|
if err := ctx.graph.SetSourceNode(aliceNode); err != nil {
|
|
|
|
t.Fatalf("unable to set source node: %v", err)
|
|
|
|
}
|
2017-10-23 03:29:55 +03:00
|
|
|
ctx.router.selfNode = aliceNode
|
2017-10-19 08:10:00 +03:00
|
|
|
source, err := ctx.graph.SourceNode()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to retrieve source node: %v", err)
|
|
|
|
}
|
2018-01-31 07:26:26 +03:00
|
|
|
if !bytes.Equal(source.PubKeyBytes[:], alice.SerializeCompressed()) {
|
2017-10-19 08:10:00 +03:00
|
|
|
t.Fatalf("source node not set")
|
|
|
|
}
|
|
|
|
|
|
|
|
// We'll now request a route from A -> B -> C.
|
|
|
|
ctx.router.routeCache = make(map[routeTuple][]*Route)
|
2018-04-19 17:32:24 +03:00
|
|
|
routes, err = ctx.router.FindRoutes(carol, amt, noFeeLimit, 100)
|
2017-10-19 08:10:00 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find routes: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We should come back with _exactly_ two routes.
|
|
|
|
if len(routes) != 2 {
|
|
|
|
t.Fatalf("expected %v routes, instead have: %v", 2,
|
|
|
|
len(routes))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Both routes should be two hops.
|
|
|
|
if len(routes[0].Hops) != 2 {
|
|
|
|
t.Fatalf("route should be %v hops, is instead %v", 2,
|
|
|
|
len(routes[0].Hops))
|
|
|
|
}
|
|
|
|
if len(routes[1].Hops) != 2 {
|
|
|
|
t.Fatalf("route should be %v hops, is instead %v", 2,
|
|
|
|
len(routes[1].Hops))
|
|
|
|
}
|
|
|
|
|
|
|
|
// The total amount should factor in a fee of 10199 and also use a CLTV
|
|
|
|
// delta total of 29 (20 + 9),
|
|
|
|
expectedAmt := lnwire.MilliSatoshi(5010198)
|
|
|
|
if routes[0].TotalAmount != expectedAmt {
|
|
|
|
t.Fatalf("wrong amount: got %v, expected %v",
|
|
|
|
routes[0].TotalAmount, expectedAmt)
|
|
|
|
}
|
|
|
|
if routes[0].TotalTimeLock != startingHeight+29 {
|
|
|
|
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
|
|
routes[0].TotalTimeLock, startingHeight+29)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that the hops of the first route are properly crafted.
|
|
|
|
//
|
|
|
|
// After taking the fee, Bob should be forwarding the remainder which
|
|
|
|
// is the exact payment to Bob.
|
|
|
|
if routes[0].Hops[0].AmtToForward != amt {
|
|
|
|
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
|
|
routes[0].Hops[0].AmtToForward, amt)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We shouldn't pay any fee for the first, hop, but the fee for the
|
|
|
|
// second hop posted fee should be exactly:
|
2017-10-25 04:29:18 +03:00
|
|
|
|
|
|
|
// The fee that we pay for the second hop will be "applied to the first
|
|
|
|
// hop, so we should get a fee of exactly:
|
2017-10-19 08:10:00 +03:00
|
|
|
//
|
|
|
|
// * 200 + 4999999 * 2000 / 1000000 = 10199
|
2017-10-25 04:29:18 +03:00
|
|
|
if routes[0].Hops[0].Fee != 10199 {
|
2017-10-19 08:10:00 +03:00
|
|
|
t.Fatalf("wrong hop fee: got %v, expected %v",
|
2017-10-25 04:29:18 +03:00
|
|
|
routes[0].Hops[0].Fee, 10199)
|
2017-10-19 08:10:00 +03:00
|
|
|
}
|
2017-10-25 04:29:18 +03:00
|
|
|
|
|
|
|
// While for the final hop, as there's no additional hop afterwards, we
|
|
|
|
// pay no fee.
|
|
|
|
if routes[0].Hops[1].Fee != 0 {
|
2017-10-19 08:10:00 +03:00
|
|
|
t.Fatalf("wrong hop fee: got %v, expected %v",
|
2017-10-25 04:29:18 +03:00
|
|
|
routes[0].Hops[0].Fee, 0)
|
2017-10-19 08:10:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// The outgoing CLTV value itself should be the current height plus 30
|
|
|
|
// to meet Carol's requirements.
|
|
|
|
if routes[0].Hops[0].OutgoingTimeLock !=
|
|
|
|
startingHeight+DefaultFinalCLTVDelta {
|
|
|
|
|
|
|
|
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
|
|
routes[0].Hops[0].OutgoingTimeLock,
|
|
|
|
startingHeight+DefaultFinalCLTVDelta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// For B -> C, we assert that the final hop also has the proper
|
|
|
|
// parameters.
|
|
|
|
lastHop := routes[0].Hops[1]
|
|
|
|
if lastHop.AmtToForward != amt {
|
|
|
|
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
|
|
lastHop.AmtToForward, amt)
|
|
|
|
}
|
|
|
|
if lastHop.OutgoingTimeLock !=
|
|
|
|
startingHeight+DefaultFinalCLTVDelta {
|
|
|
|
|
|
|
|
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
|
|
lastHop.OutgoingTimeLock,
|
|
|
|
startingHeight+DefaultFinalCLTVDelta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We'll also make similar assertions for the second route from A to C
|
|
|
|
// via D.
|
|
|
|
secondRoute := routes[1]
|
|
|
|
expectedAmt = 5020398
|
|
|
|
if secondRoute.TotalAmount != expectedAmt {
|
|
|
|
t.Fatalf("wrong amount: got %v, expected %v",
|
|
|
|
secondRoute.TotalAmount, expectedAmt)
|
|
|
|
}
|
|
|
|
expectedTimeLock := startingHeight + daveFinalCLTV + DefaultFinalCLTVDelta
|
|
|
|
if secondRoute.TotalTimeLock != uint32(expectedTimeLock) {
|
|
|
|
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
|
|
secondRoute.TotalTimeLock, expectedTimeLock)
|
|
|
|
}
|
|
|
|
onionPayload := secondRoute.Hops[0]
|
|
|
|
if onionPayload.AmtToForward != amt {
|
|
|
|
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
|
|
onionPayload.AmtToForward, amt)
|
|
|
|
}
|
|
|
|
expectedTimeLock = startingHeight + DefaultFinalCLTVDelta
|
|
|
|
if onionPayload.OutgoingTimeLock != uint32(expectedTimeLock) {
|
|
|
|
t.Fatalf("wrong outgoing time lock: got %v, expecting %v",
|
|
|
|
onionPayload.OutgoingTimeLock,
|
|
|
|
expectedTimeLock)
|
|
|
|
}
|
|
|
|
|
|
|
|
// The B -> C hop should also be identical as the prior cases.
|
|
|
|
lastHop = secondRoute.Hops[1]
|
|
|
|
if lastHop.AmtToForward != amt {
|
|
|
|
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
|
|
lastHop.AmtToForward, amt)
|
|
|
|
}
|
|
|
|
if lastHop.OutgoingTimeLock !=
|
|
|
|
startingHeight+DefaultFinalCLTVDelta {
|
|
|
|
|
|
|
|
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
|
|
lastHop.OutgoingTimeLock,
|
|
|
|
startingHeight+DefaultFinalCLTVDelta)
|
|
|
|
}
|
|
|
|
}
|
2018-03-27 07:32:37 +03:00
|
|
|
|
|
|
|
func assertExpectedPath(t *testing.T, path []*ChannelHop, nodeAliases ...string) {
|
|
|
|
if len(path) != len(nodeAliases) {
|
|
|
|
t.Fatal("number of hops and number of aliases do not match")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, hop := range path {
|
|
|
|
if hop.Node.Alias != nodeAliases[i] {
|
|
|
|
t.Fatalf("expected %v to be pos #%v in hop, instead "+
|
|
|
|
"%v was", nodeAliases[i], i, hop.Node.Alias)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|