From 4d92d237629c02e28a05cf1e2521c1f54941b98c Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Mon, 21 Aug 2017 23:50:12 -0700 Subject: [PATCH] htlcswitch: add new UpdateForwardingPolicies method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a new method to the HtlcSwitch: UpdateForwardingPolicies. With this method callers are now able to modify the forwarding policies of all, or some currently active links. We also make a slight modification to the way that forwarding policy updates are handled within the links themselves to ensure that we don’t override with a zero value for any of the fields. --- htlcswitch/link.go | 24 ++++++++++++-- htlcswitch/switch.go | 75 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 4ada5bc1..b5af7c15 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -423,7 +423,23 @@ out: case *getBandwidthCmd: req.resp <- l.getBandwidth() case *policyUpdate: - l.cfg.FwrdingPolicy = req.policy + // In order to avoid overriding a valid policy + // with a "null" field in the new policy, we'll + // only update to the set sub policy if the new + // value isn't uninitialized. + if req.policy.MinHTLC != 0 { + l.cfg.FwrdingPolicy.MinHTLC = req.policy.MinHTLC + } + if req.policy.BaseFee != 0 { + l.cfg.FwrdingPolicy.BaseFee = req.policy.BaseFee + } + if req.policy.FeeRate != 0 { + l.cfg.FwrdingPolicy.FeeRate = req.policy.FeeRate + } + if req.policy.TimeLockDelta != 0 { + l.cfg.FwrdingPolicy.TimeLockDelta = req.policy.TimeLockDelta + } + if req.done != nil { close(req.done) } @@ -862,7 +878,10 @@ type policyUpdate struct { // UpdateForwardingPolicy updates the forwarding policy for the target // ChannelLink. Once updated, the link will use the new forwarding policy to -// govern if it an incoming HTLC should be forwarded or not. +// govern if it an incoming HTLC should be forwarded or not. Note that this +// processing of the new policy will ensure that uninitialized fields in the +// passed policy won't override already initialized fields in the current +// policy. // // NOTE: Part of the ChannelLink interface. func (l *channelLink) UpdateForwardingPolicy(newPolicy ForwardingPolicy) { @@ -887,6 +906,7 @@ func (l *channelLink) UpdateForwardingPolicy(newPolicy ForwardingPolicy) { // NOTE: Part of the ChannelLink interface. func (l *channelLink) Stats() (uint64, lnwire.MilliSatoshi, lnwire.MilliSatoshi) { snapshot := l.channel.StateSnapshot() + return snapshot.NumUpdates, snapshot.TotalMilliSatoshisSent, snapshot.TotalMilliSatoshisReceived diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index bdc1328d..6cccfb22 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -224,6 +224,79 @@ func (s *Switch) SendHTLC(nextNode [33]byte, htlc *lnwire.UpdateAddHTLC, return preimage, err } +// UpdateForwardingPolicies sends a message to the switch to update the +// forwarding policies for the set of target channels. If the set of targeted +// channels is nil, then the forwarding policies for all active channels with +// be updated. +// +// NOTE: This function is synchronous and will block until either the +// forwarding policies for all links have been updated, or the switch shuts +// down. +func (s *Switch) UpdateForwardingPolicies(newPolicy ForwardingPolicy, + targetChans ...wire.OutPoint) error { + + errChan := make(chan error, 1) + select { + case s.linkControl <- &updatePoliciesCmd{ + newPolicy: newPolicy, + targetChans: targetChans, + err: errChan, + }: + case <-s.quit: + return fmt.Errorf("switch is shutting down") + } + + select { + case err := <-errChan: + return err + case <-s.quit: + return fmt.Errorf("switch is shutting down") + } +} + +// updatePoliciesCmd is a message sent to the switch to update the forwarding +// policies of a set of target links. +type updatePoliciesCmd struct { + newPolicy ForwardingPolicy + targetChans []wire.OutPoint + + err chan error +} + +// updateLinkPolicies attempts to update the forwarding policies for the set of +// passed links identified by their channel points. If a nil set of channel +// points is passed, then the forwarding policies for all active links will be +// updated.k +func (s *Switch) updateLinkPolicies(c *updatePoliciesCmd) error { + log.Debugf("Updating link policies: %v", spew.Sdump(c)) + + // If no channels have been targeted, then we'll update the link policies + // for all active channels + if len(c.targetChans) == 0 { + for _, link := range s.linkIndex { + link.UpdateForwardingPolicy(c.newPolicy) + } + } + + // Otherwise, we'll only attempt to update the forwarding policies for the + // set of targeted links. + for _, targetLink := range c.targetChans { + cid := lnwire.NewChanIDFromOutPoint(&targetLink) + + // If we can't locate a link by its converted channel ID, then we'll + // return an error back to the caller. + link, ok := s.linkIndex[cid] + if !ok { + return fmt.Errorf("unable to find ChannelPoint(%v) to "+ + "update link policy", targetLink) + } + + link.UpdateForwardingPolicy(c.newPolicy) + } + + return nil +} + // forward is used in order to find next channel link and apply htlc // update. Also this function is used by channel links itself in order to // forward the update after it has been included in the channel. @@ -723,6 +796,8 @@ func (s *Switch) htlcForwarder() { case req := <-s.linkControl: switch cmd := req.(type) { + case *updatePoliciesCmd: + cmd.err <- s.updateLinkPolicies(cmd) case *addLinkCmd: cmd.err <- s.addLink(cmd.link) case *removeLinkCmd: