package lnwire import ( "encoding/binary" "encoding/hex" "math" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" ) const ( // MaxFundingTxOutputs is the maximum number of allowed outputs on a // funding transaction within the protocol. This is due to the fact // that we use 2-bytes to encode the index within the funding output // during the funding workflow. Funding transaction with more outputs // than this are considered invalid within the protocol. MaxFundingTxOutputs = math.MaxUint16 ) // ChannelID is a series of 32-bytes that uniquely identifies all channels // within the network. The ChannelID is computed using the outpoint of the // funding transaction (the txid, and output index). Given a funding output the // ChannelID can be calculated by XOR'ing the big-endian serialization of the // txid and the big-endian serialization of the output index, truncated to // 2 bytes. type ChannelID [32]byte // ConnectionWideID is an all-zero ChannelID, which is used to represent a // message intended for all channels to specific peer. var ConnectionWideID = ChannelID{} // String returns the string representation of the ChannelID. This is just the // hex string encoding of the ChannelID itself. func (c ChannelID) String() string { return hex.EncodeToString(c[:]) } // NewChanIDFromOutPoint converts a target OutPoint into a ChannelID that is // usable within the network. In order to convert the OutPoint into a ChannelID, // we XOR the lower 2-bytes of the txid within the OutPoint with the big-endian // serialization of the Index of the OutPoint, truncated to 2-bytes. func NewChanIDFromOutPoint(op *wire.OutPoint) ChannelID { // First we'll copy the txid of the outpoint into our channel ID slice. var cid ChannelID copy(cid[:], op.Hash[:]) // With the txid copied over, we'll now XOR the lower 2-bytes of the // partial channelID with big-endian serialization of output index. xorTxid(&cid, uint16(op.Index)) return cid } // xorTxid performs the transformation needed to transform an OutPoint into a // ChannelID. To do this, we expect the cid parameter to contain the txid // unaltered and the outputIndex to be the output index func xorTxid(cid *ChannelID, outputIndex uint16) { var buf [2]byte binary.BigEndian.PutUint16(buf[:], outputIndex) cid[30] ^= buf[0] cid[31] ^= buf[1] } // GenPossibleOutPoints generates all the possible outputs given a channel ID. // In order to generate these possible outpoints, we perform a brute-force // search through the candidate output index space, performing a reverse // mapping from channelID back to OutPoint. func (c *ChannelID) GenPossibleOutPoints() [MaxFundingTxOutputs]wire.OutPoint { var possiblePoints [MaxFundingTxOutputs]wire.OutPoint for i := uint16(0); i < MaxFundingTxOutputs; i++ { cidCopy := *c xorTxid(&cidCopy, i) possiblePoints[i] = wire.OutPoint{ Hash: chainhash.Hash(cidCopy), Index: uint32(i), } } return possiblePoints } // IsChanPoint returns true if the OutPoint passed corresponds to the target // ChannelID. func (c ChannelID) IsChanPoint(op *wire.OutPoint) bool { candidateCid := NewChanIDFromOutPoint(op) return candidateCid == c }