lnwire: add FundingLocked message

When the funding transaction has been confirmed, the FundingLocked
message is sent by the peers to each other so that the existence of the
newly funded channel can be announced to the network.

This commit also removes the SingleFundingOpenProof message.
This commit is contained in:
bryanvu 2017-01-30 18:45:28 -08:00 committed by Olaoluwa Osuntokun
parent e549a3f0ed
commit eb490b8833
8 changed files with 172 additions and 131 deletions

View File

@ -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)
}

119
lnwire/funding_locked.go Normal file
View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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:

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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"

View File

@ -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