From 07076cce219bb5aa22a18417e5e456e84b6146ac Mon Sep 17 00:00:00 2001 From: Andrey Samokhvalov Date: Mon, 27 Mar 2017 20:00:38 +0300 Subject: [PATCH] routing+channeldb: add AddProof method Originally we adding the edge without proof in order to able to use it for payments path constrcution. This method will allow us to populate the announcement proof after the exchange of the half proofs and constrcutrion of full proof finished. --- channeldb/graph.go | 28 +++++++++++++++++++++++ discovery/service_test.go | 5 ++++ routing/router.go | 19 ++++++++++++++++ routing/router_test.go | 48 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) diff --git a/channeldb/graph.go b/channeldb/graph.go index b53933e1..a1b7c7a8 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -507,6 +507,34 @@ func (c *ChannelGraph) HasChannelEdge(chanID uint64) (time.Time, time.Time, bool return node1UpdateTime, node2UpdateTime, exists, nil } +// UpdateChannelEdge retrieves and update edge of the graph database. Method +// only reserved for updating an edge info after it's already been created. +// In order to maintain this constraints, we return an error in the scenario +// that an edge info hasn't yet been created yet, but someone attempts to update +// it. +func (c *ChannelGraph) UpdateChannelEdge(edge *ChannelEdgeInfo) error { + // Construct the channel's primary key which is the 8-byte channel ID. + var chanKey [8]byte + binary.BigEndian.PutUint64(chanKey[:], edge.ChannelID) + + return c.db.Update(func(tx *bolt.Tx) error { + edges, err := tx.CreateBucketIfNotExists(edgeBucket) + if err != nil { + return err + } + edgeIndex, err := edges.CreateBucketIfNotExists(edgeIndexBucket) + if err != nil { + return err + } + + if edgeInfo := edgeIndex.Get(chanKey[:]); edgeInfo == nil { + return ErrEdgeNotFound + } + + return putChanEdgeInfo(edgeIndex, edge, chanKey) + }) +} + const ( // pruneTipBytes is the total size of the value which stores the // current prune tip of the graph. The prune tip indicates if the diff --git a/discovery/service_test.go b/discovery/service_test.go index 85ce3e79..a0b0885d 100644 --- a/discovery/service_test.go +++ b/discovery/service_test.go @@ -73,6 +73,11 @@ func (r *mockGraphSource) CurrentBlockHeight() (uint32, error) { return r.bestHeight, nil } +func (r *mockGraphSource) AddProof(chanID lnwire.ShortChannelID, + proof *channeldb.ChannelAuthProof) error { + return nil +} + func (r *mockGraphSource) ForEachNode(func(node *channeldb.LightningNode) error) error { return nil } diff --git a/routing/router.go b/routing/router.go index 3dbdd74b..2012cad4 100644 --- a/routing/router.go +++ b/routing/router.go @@ -34,6 +34,10 @@ type ChannelGraphSource interface { // edge/channel might be used in construction of payment path. AddEdge(edge *channeldb.ChannelEdgeInfo) error + // AddProof updates the channel edge info with proof which is needed + // to properly announce the edge to the rest of the network. + AddProof(chanID lnwire.ShortChannelID, proof *channeldb.ChannelAuthProof) error + // UpdateEdge is used to update edge information, without this // message edge considered as not fully constructed. UpdateEdge(policy *channeldb.ChannelEdgePolicy) error @@ -1063,3 +1067,18 @@ func (r *ChannelRouter) ForEachChannel(cb func(chanInfo *channeldb.ChannelEdgeIn e1, e2 *channeldb.ChannelEdgePolicy) error) error { return r.cfg.Graph.ForEachChannel(cb) } + +// AddProof updates the channel edge info with proof which is needed +// to properly announce the edge to the rest of the network. +// NOTE: Part of the Router interface. +func (r *ChannelRouter) AddProof(chanID lnwire.ShortChannelID, + proof *channeldb.ChannelAuthProof) error { + + info, _, _, err := r.cfg.Graph.FetchChannelEdgesByID(chanID.ToUint64()) + if err != nil { + return err + } + + info.AuthProof = proof + return r.cfg.Graph.UpdateChannelEdge(info) +} diff --git a/routing/router_test.go b/routing/router_test.go index a8bd7d56..b965916e 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -206,3 +206,51 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) { route.Hops[0].Channel.Node.Alias) } } + +// TestAddProof checks that we can update the channel proof after channel +// info was added to the database. +func TestAddProof(t *testing.T) { + ctx, cleanup, err := createTestCtx(0) + if err != nil { + t.Fatal(err) + } + defer cleanup() + + // In order to be able to add the edge we should have the valud + // funding UTXO within the blockchain. + fundingTx, _, chanID, err := createChannelEdge(ctx, + bitcoinKey1.SerializeCompressed(), bitcoinKey2.SerializeCompressed(), + 100, 0) + if err != nil { + t.Fatalf("unable create channel edge: %v", err) + } + + fundingBlock := &wire.MsgBlock{ + Transactions: []*wire.MsgTx{fundingTx}, + } + ctx.chain.addBlock(fundingBlock, chanID.BlockHeight) + + // After utxo was recreated adding the edge without the proof. + edge := &channeldb.ChannelEdgeInfo{ + ChannelID: chanID.ToUint64(), + NodeKey1: priv1.PubKey(), + NodeKey2: priv1.PubKey(), + BitcoinKey1: bitcoinKey1, + BitcoinKey2: bitcoinKey2, + AuthProof: nil, + } + + if err := ctx.router.AddEdge(edge); err != nil { + t.Fatalf("unable to add edge: %v", err) + } + + // No trying to update the proof and checking that it have been updated. + if err := ctx.router.AddProof(*chanID, &testAuthProof); err != nil { + t.Fatalf("unable to add proof: %v", err) + } + + info, _, _, err := ctx.router.GetChannelByID(*chanID) + if info.AuthProof == nil { + t.Fatal("proof have been updated") + } +}