diff --git a/fundingmanager.go b/fundingmanager.go index 3f8aaceb8..38b34446d 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -967,7 +967,7 @@ func (f *fundingManager) handleFundingLocked(fmsg *fundingLockedMsg) { // Register the new link with the L3 routing manager so this // new channel can be utilized during path // finding. - f.announceChannel(f.cfg.IDKey, fmsg.peerAddress.IdentityKey, channel, + go f.announceChannel(f.cfg.IDKey, fmsg.peerAddress.IdentityKey, channel, fmsg.msg.ChannelID, f.fakeProof, f.fakeProof) } diff --git a/lnwire/funding_locked.go b/lnwire/funding_locked.go new file mode 100644 index 000000000..32f06d18d --- /dev/null +++ b/lnwire/funding_locked.go @@ -0,0 +1,119 @@ +package lnwire + +import ( + "fmt" + "io" + + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/wire" +) + +// FundingLocked is the message that both parties to a new channel creation +// send once they have observed the funding transaction being confirmed on +// the blockchain. FundingLocked contains the signatures necessary for the +// channel participants to advertise the existence of the channel to the +// rest of the network. +type FundingLocked struct { + // ChannelOutpoint is the outpoint of the channel's funding + // transaction. This can be used to query for the channel in the + // database. + ChannelOutpoint wire.OutPoint + + // ChannelId serves to uniquely identify the channel created by the + // current channel funding workflow. + ChannelID ChannelID + + // NextPerCommitmentPoint is the secret that can be used to revoke + // the next commitment transaction for the channel. + NextPerCommitmentPoint *btcec.PublicKey +} + +// NewFundingLocked creates a new FundingLocked message, populating it with +// the necessary IDs and revocation secret.. +func NewFundingLocked(op wire.OutPoint, cid ChannelID, + npcp *btcec.PublicKey) *FundingLocked { + return &FundingLocked{ + ChannelOutpoint: op, + ChannelID: cid, + NextPerCommitmentPoint: npcp, + } +} + +// A compile time check to ensure FundingLocked implements the +// lnwire.Message interface. +var _ Message = (*FundingLocked)(nil) + +// Decode deserializes the serialized FundingLocked message stored in the passed +// io.Reader into the target FundingLocked using the deserialization +// rules defined by the passed protocol version. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) Decode(r io.Reader, pver uint32) error { + err := readElements(r, + &c.ChannelOutpoint, + &c.ChannelID, + &c.NextPerCommitmentPoint) + if err != nil { + return err + } + + return nil +} + +// Encode serializes the target FundingLocked message into the passed io.Writer +// implementation. Serialization will observe the rules defined by the passed +// protocol version. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) Encode(w io.Writer, pver uint32) error { + err := writeElements(w, + c.ChannelOutpoint, + c.ChannelID, + c.NextPerCommitmentPoint) + if err != nil { + return err + } + + return nil +} + +// Command returns the uint32 code which uniquely identifies this message as a +// FundingLocked message on the wire. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) Command() uint32 { + return CmdFundingLocked +} + +// MaxPayloadLength returns the maximum allowed payload length for a +// FundingLocked message. This is calculated by summing the max length of all +// the fields within a FundingLocked message. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) MaxPayloadLength(uint32) uint32 { + var length uint32 + + // ChannelOutpoint - 36 bytes + length += 36 + + // ChannelID - 8 bytes + length += 8 + + // NextPerCommitmentPoint - 33 bytes + length += 33 + + return length +} + +// Validate examines each populated field within the FundingLocked message for +// field sanity. For example, signature fields MUST NOT be nil. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) Validate() error { + if c.NextPerCommitmentPoint == nil { + return fmt.Errorf("The next per commitment point must be non-nil.") + } + + // We're good! + return nil +} diff --git a/lnwire/funding_locked_test.go b/lnwire/funding_locked_test.go new file mode 100644 index 000000000..5ea08b264 --- /dev/null +++ b/lnwire/funding_locked_test.go @@ -0,0 +1,35 @@ +package lnwire + +import ( + "bytes" + "reflect" + "testing" +) + +func TestFundingLockedWire(t *testing.T) { + // First create a new FundingLocked message. + fl := NewFundingLocked(*outpoint1, someChannelID, pubKey) + + // Next encode the FundingLocked message into an empty bytes buffer. + var b bytes.Buffer + if err := fl.Encode(&b, 0); err != nil { + t.Fatalf("unable to encode FundingLocked: %v", err) + } + + // Check to ensure that the FundingLocked message is the correct size. + if uint32(b.Len()) > fl.MaxPayloadLength(0) { + t.Fatalf("length of FundingLocked message is too long: %v should be less than %v", + b.Len(), fl.MaxPayloadLength(0)) + } + + // Deserialize the encoded FundingLocked message into an empty struct. + fl2 := &FundingLocked{} + if err := fl2.Decode(&b, 0); err != nil { + t.Fatalf("unable to decode FundingLocked: %v", err) + } + + // Assert equality of the two instances + if !reflect.DeepEqual(fl, fl2) { + t.Fatalf("encode/decode error messages don't match %#v vs %#v", fl, fl2) + } +} diff --git a/lnwire/message.go b/lnwire/message.go index dbadf2f8b..5e05722b7 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -30,7 +30,9 @@ const ( CmdSingleFundingResponse = uint32(110) CmdSingleFundingComplete = uint32(120) CmdSingleFundingSignComplete = uint32(130) - CmdSingleFundingOpenProof = uint32(140) + + // Command for locking a funded channel + CmdFundingLocked = uint32(200) // Commands for the workflow of cooperatively closing an active channel. CmdCloseRequest = uint32(300) @@ -99,8 +101,8 @@ func makeEmptyMessage(command uint32) (Message, error) { msg = &SingleFundingComplete{} case CmdSingleFundingSignComplete: msg = &SingleFundingSignComplete{} - case CmdSingleFundingOpenProof: - msg = &SingleFundingOpenProof{} + case CmdFundingLocked: + msg = &FundingLocked{} case CmdCloseRequest: msg = &CloseRequest{} case CmdCloseComplete: diff --git a/lnwire/single_funding_open_proof.go b/lnwire/single_funding_open_proof.go deleted file mode 100644 index 1700e9f90..000000000 --- a/lnwire/single_funding_open_proof.go +++ /dev/null @@ -1,92 +0,0 @@ -package lnwire - -import "io" - -// SingleFundingOpenProof is the message sent by the channel initiator to the -// responder after the previously constructed funding transaction has achieved -// a sufficient number of confirmations. It is the initiator's duty to present -// a proof of an open channel to the responder. Otherwise, responding node may -// be vulnerable to a resource exhaustion attack wherein the requesting node -// repeatedly negotiates funding transactions which are never broadcast. If the -// responding node commits resources to watch the chain for each funding -// transaction, then this attack is very cheap for the initiator. -type SingleFundingOpenProof struct { - // ChannelID serves to uniquely identify the future channel created by - // the initiated single funder workflow. - ChannelID uint64 - - // ChanChainID is the channel ID of the completed channel which - // compactly encodes the location of the channel within the current - // main chain. - ChanChainID ChannelID -} - -// NewSingleFundingSignComplete creates a new empty SingleFundingOpenProof -// message. -func NewSingleFundingOpenProof(chanID uint64, chainID ChannelID) *SingleFundingOpenProof { - return &SingleFundingOpenProof{ - ChannelID: chanID, - ChanChainID: chainID, - } -} - -// Decode deserializes the serialized SingleFundingOpenProof stored in the -// passed io.Reader into the target SingleFundingOpenProof using the -// deserialization rules defined by the passed protocol version. -// -// This is part of the lnwire.Message interface. -func (s *SingleFundingOpenProof) Decode(r io.Reader, pver uint32) error { - // ChannelID (8) - // ChanChainID (8) - err := readElements(r, - &s.ChannelID, - &s.ChanChainID) - if err != nil { - return err - } - - return nil -} - -// Encode serializes the target SingleFundingOpenProof into the passed -// io.Writer implementation. Serialization will observe the rules defined by -// the passed protocol version. -// -// This is part of the lnwire.Message interface. -func (s *SingleFundingOpenProof) Encode(w io.Writer, pver uint32) error { - err := writeElements(w, - s.ChannelID, - s.ChanChainID) - if err != nil { - return err - } - - return nil -} - -// Command returns the uint32 code which uniquely identifies this message as a -// SingleFundingSignComplete on the wire. -// -// This is part of the lnwire.Message interface. -func (s *SingleFundingOpenProof) Command() uint32 { - return CmdSingleFundingOpenProof -} - -// MaxPayloadLength returns the maximum allowed payload length for a -// SingleFundingComplete. This is calculated by summing the max length of all -// the fields within a SingleFundingOpenProof. -// -// This is part of the lnwire.Message interface. -func (s *SingleFundingOpenProof) MaxPayloadLength(uint32) uint32 { - // 8 + - return 81 -} - -// Validate examines each populated field within the SingleFundingOpenProof for -// field sanity. -// -// This is part of the lnwire.Message interface. -func (s *SingleFundingOpenProof) Validate() error { - // We're good! - return nil -} diff --git a/lnwire/single_funding_open_proof_test.go b/lnwire/single_funding_open_proof_test.go deleted file mode 100644 index 399d16cf0..000000000 --- a/lnwire/single_funding_open_proof_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package lnwire - -import ( - "bytes" - "reflect" - "testing" -) - -func TestSingleFundingOpenProofWire(t *testing.T) { - // First create a new SFOP message. - sfop := NewSingleFundingOpenProof(22, someChannelID) - - // Next encode the SFOP message into an empty bytes buffer. - var b bytes.Buffer - if err := sfop.Encode(&b, 0); err != nil { - t.Fatalf("unable to encode SingleFundingSignComplete: %v", err) - } - - // Deserialize the encoded SFOP message into a new empty struct. - sfop2 := &SingleFundingOpenProof{} - if err := sfop2.Decode(&b, 0); err != nil { - t.Fatalf("unable to decode SingleFundingOpenProof: %v", err) - } - - // Assert equality of the two instances. - if !reflect.DeepEqual(sfop, sfop2) { - t.Fatalf("encode/decode error messages don't match %#v vs %#v", - sfop, sfop2) - } -} diff --git a/peer.go b/peer.go index 108480c98..d40ef3db9 100644 --- a/peer.go +++ b/peer.go @@ -446,6 +446,8 @@ out: p.server.fundingMgr.processFundingComplete(msg, p.addr) case *lnwire.SingleFundingSignComplete: p.server.fundingMgr.processFundingSignComplete(msg, p.addr) + case *lnwire.FundingLocked: + p.server.fundingMgr.processFundingLocked(msg, p.addr) case *lnwire.CloseRequest: p.remoteCloseChanReqs <- msg @@ -524,6 +526,8 @@ func (p *peer) logWireMessage(msg lnwire.Message, read bool) { m.ChannelDerivationPoint.Curve = nil m.CommitmentKey.Curve = nil m.RevocationKey.Curve = nil + case *lnwire.FundingLocked: + m.NextPerCommitmentPoint.Curve = nil } prefix := "readMessage from" diff --git a/server.go b/server.go index 259ef42c2..c4c3ca7a7 100644 --- a/server.go +++ b/server.go @@ -198,11 +198,14 @@ func newServer(listenAddrs []string, notifier chainntnfs.ChainNotifier, s.breachArbiter = newBreachArbiter(wallet, chanDB, notifier, s.htlcSwitch) s.fundingMgr, err = newFundingManager(fundingConfig{ - Wallet: wallet, - Notifier: s.chainNotifier, - ArbiterChan: s.breachArbiter.newContracts, - SendToPeer: s.sendToPeer, - FindPeer: s.findPeer, + IDKey: s.identityPriv.PubKey(), + Wallet: wallet, + Notifier: s.chainNotifier, + ProcessRoutingMessage: s.chanRouter.ProcessRoutingMessage, + ArbiterChan: s.breachArbiter.newContracts, + SendToPeer: s.sendToPeer, + FindPeer: s.findPeer, + FindChannel: s.rpcServer.fetchActiveChannel, }) if err != nil { return nil, err