github.com/decred/dcrlnd@v0.7.6/netann/channel_update.go (about)

     1  package netann
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     9  	"github.com/decred/dcrlnd/channeldb"
    10  	"github.com/decred/dcrlnd/keychain"
    11  	"github.com/decred/dcrlnd/lnwallet"
    12  	"github.com/decred/dcrlnd/lnwire"
    13  )
    14  
    15  // ErrUnableToExtractChanUpdate is returned when a channel update cannot be
    16  // found for one of our active channels.
    17  var ErrUnableToExtractChanUpdate = fmt.Errorf("unable to extract ChannelUpdate")
    18  
    19  // ChannelUpdateModifier is a closure that makes in-place modifications to an
    20  // lnwire.ChannelUpdate.
    21  type ChannelUpdateModifier func(*lnwire.ChannelUpdate)
    22  
    23  // ChanUpdSetDisable is a functional option that sets the disabled channel flag
    24  // if disabled is true, and clears the bit otherwise.
    25  func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier {
    26  	return func(update *lnwire.ChannelUpdate) {
    27  		if disabled {
    28  			// Set the bit responsible for marking a channel as
    29  			// disabled.
    30  			update.ChannelFlags |= lnwire.ChanUpdateDisabled
    31  		} else {
    32  			// Clear the bit responsible for marking a channel as
    33  			// disabled.
    34  			update.ChannelFlags &= ^lnwire.ChanUpdateDisabled
    35  		}
    36  	}
    37  }
    38  
    39  // ChanUpdSetTimestamp is a functional option that sets the timestamp of the
    40  // update to the current time, or increments it if the timestamp is already in
    41  // the future.
    42  func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) {
    43  	newTimestamp := uint32(time.Now().Unix())
    44  	if newTimestamp <= update.Timestamp {
    45  		// Increment the prior value to ensure the timestamp
    46  		// monotonically increases, otherwise the update won't
    47  		// propagate.
    48  		newTimestamp = update.Timestamp + 1
    49  	}
    50  	update.Timestamp = newTimestamp
    51  }
    52  
    53  // SignChannelUpdate applies the given modifiers to the passed
    54  // lnwire.ChannelUpdate, then signs the resulting update. The provided update
    55  // should be the most recent, valid update, otherwise the timestamp may not
    56  // monotonically increase from the prior.
    57  //
    58  // NOTE: This method modifies the given update.
    59  func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
    60  	update *lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error {
    61  
    62  	// Apply the requested changes to the channel update.
    63  	for _, modifier := range mods {
    64  		modifier(update)
    65  	}
    66  
    67  	// Create the DER-encoded ECDSA signature over the message digest.
    68  	sig, err := SignAnnouncement(signer, keyLoc, update)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	// Parse the DER-encoded signature into a fixed-size 64-byte array.
    74  	update.Signature, err = lnwire.NewSigFromSignature(sig)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	return nil
    80  }
    81  
    82  // ExtractChannelUpdate attempts to retrieve a lnwire.ChannelUpdate message from
    83  // an edge's info and a set of routing policies.
    84  //
    85  // NOTE: The passed policies can be nil.
    86  func ExtractChannelUpdate(ownerPubKey []byte,
    87  	info *channeldb.ChannelEdgeInfo,
    88  	policies ...*channeldb.ChannelEdgePolicy) (
    89  	*lnwire.ChannelUpdate, error) {
    90  
    91  	// Helper function to extract the owner of the given policy.
    92  	owner := func(edge *channeldb.ChannelEdgePolicy) []byte {
    93  		var pubKey *secp256k1.PublicKey
    94  		if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
    95  			pubKey, _ = info.NodeKey1()
    96  		} else {
    97  			pubKey, _ = info.NodeKey2()
    98  		}
    99  
   100  		// If pubKey was not found, just return nil.
   101  		if pubKey == nil {
   102  			return nil
   103  		}
   104  
   105  		return pubKey.SerializeCompressed()
   106  	}
   107  
   108  	// Extract the channel update from the policy we own, if any.
   109  	for _, edge := range policies {
   110  		if edge != nil && bytes.Equal(ownerPubKey, owner(edge)) {
   111  			return ChannelUpdateFromEdge(info, edge)
   112  		}
   113  	}
   114  
   115  	return nil, ErrUnableToExtractChanUpdate
   116  }
   117  
   118  // UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the
   119  // given edge info and policy.
   120  func UnsignedChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo,
   121  	policy *channeldb.ChannelEdgePolicy) *lnwire.ChannelUpdate {
   122  
   123  	return &lnwire.ChannelUpdate{
   124  		ChainHash:         info.ChainHash,
   125  		ShortChannelID:    lnwire.NewShortChanIDFromInt(policy.ChannelID),
   126  		Timestamp:         uint32(policy.LastUpdate.Unix()),
   127  		ChannelFlags:      policy.ChannelFlags,
   128  		MessageFlags:      policy.MessageFlags,
   129  		TimeLockDelta:     policy.TimeLockDelta,
   130  		HtlcMinimumMAtoms: policy.MinHTLC,
   131  		HtlcMaximumMAtoms: policy.MaxHTLC,
   132  		BaseFee:           uint32(policy.FeeBaseMAtoms),
   133  		FeeRate:           uint32(policy.FeeProportionalMillionths),
   134  		ExtraOpaqueData:   policy.ExtraOpaqueData,
   135  	}
   136  }
   137  
   138  // ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge
   139  // info and policy.
   140  func ChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo,
   141  	policy *channeldb.ChannelEdgePolicy) (*lnwire.ChannelUpdate, error) {
   142  
   143  	update := UnsignedChannelUpdateFromEdge(info, policy)
   144  
   145  	var err error
   146  	update.Signature, err = lnwire.NewSigFromRawSignature(policy.SigBytes)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	return update, nil
   152  }