lnwire: document commitment+HTLC update msgs

This commit adds some cursory documentation along wit minor field
modifications to all messages which deal with adding HTLC’s, or
updating remote commitment transactions.

The messages for dual funding of channel is left purposefully
undocumented as all initial negotiations will be single funder by
default.

A revamp of the testing infrastructure of lnwire will be committed in
the near future.
This commit is contained in:
Olaoluwa Osuntokun 2016-05-23 13:54:34 -07:00
parent b202831868
commit 913ae259de
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
24 changed files with 500 additions and 193 deletions

@ -2,28 +2,41 @@ package lnwire
import (
"fmt"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
"io"
)
// CloseComplete is sent by Bob signalling a fufillment and completion of
// Alice's prior CloseRequest message. After Alice receives Bob's CloseComplete
// message, she is able to broadcast the fully signed transaction executing a
// cooperative closure of the channel.
//
// NOTE: The responder is able to only send a signature without any additional
// message as all transactions are assembled observing BIP 69 which defines a
// cannonical ordering for input/outputs. Therefore, both sides are able to
// arrive at an identical closure transaction as they know the order of the
// inputs/outputs.
type CloseComplete struct {
ReservationID uint64
// ChannelID serves to identify which channel is to be closed.
ChannelID uint64
ResponderCloseSig *btcec.Signature // Requester's Commitment
CloseShaHash *wire.ShaHash // TxID of the Close Tx
// ResponderCloseSig is the signature of the responder for the
// transaction which closes the previously active channel.
ResponderCloseSig *btcec.Signature
}
// Decode deserializes a serialized CloseComplete message stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CloseComplete) Decode(r io.Reader, pver uint32) error {
// ReservationID (8)
// ChannelID (8)
// ResponderCloseSig (73)
// First byte length then sig
// CloseShaHash (32)
err := readElements(r,
&c.ReservationID,
&c.ResponderCloseSig,
&c.CloseShaHash)
&c.ChannelID,
&c.ResponderCloseSig)
if err != nil {
return err
}
@ -31,21 +44,26 @@ func (c *CloseComplete) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new CloseComplete
// NewCloseComplete creates a new empty CloseComplete message.
// TODO(roasbeef): add params to all constructors...
func NewCloseComplete() *CloseComplete {
return &CloseComplete{}
}
// Serializes the item from the CloseComplete struct
// Writes the data to w
// A compile time check to ensure CloseComplete implements the lnwire.Message
// interface.
var _ Message = (*CloseComplete)(nil)
// Encode serializes the target CloseComplete into the passed io.Writer observing
// the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *CloseComplete) Encode(w io.Writer, pver uint32) error {
// ReservationID
// ResponderCloseSig
// CloseShaHash
// ChannelID (8)
// ResponderCloseSig (73)
err := writeElements(w,
c.ReservationID,
c.ResponderCloseSig,
c.CloseShaHash)
c.ChannelID,
c.ResponderCloseSig)
if err != nil {
return err
}
@ -53,34 +71,43 @@ func (c *CloseComplete) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *CloseComplete) Command() uint32 {
return CmdCloseComplete
}
// MaxPayloadLength returns the maximum allowed payload size for a CloseComplete
// complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CloseComplete) MaxPayloadLength(uint32) uint32 {
// 8 + 73 + 32
return 113
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the CloseComplete are valid.
//
// This is part of the lnwire.Message interface.
func (c *CloseComplete) Validate() error {
// We're good!
return nil
}
// String returns the string representation of the target CloseComplete.
//
// This is part of the lnwire.Message interface.
func (c *CloseComplete) String() string {
var serializedSig []byte
var shaString string
if c.ResponderCloseSig != nil && c.ResponderCloseSig.R != nil {
if c.ResponderCloseSig != nil {
serializedSig = c.ResponderCloseSig.Serialize()
}
if c.CloseShaHash != nil {
shaString = (*c).CloseShaHash.String()
}
return fmt.Sprintf("\n--- Begin CloseComplete ---\n") +
fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) +
fmt.Sprintf("ReservationID:\t\t%d\n", c.ChannelID) +
fmt.Sprintf("ResponderCloseSig:\t%x\n", serializedSig) +
fmt.Sprintf("CloseShaHash:\t\t%s\n", shaString) +
fmt.Sprintf("--- End CloseComplete ---\n")
}

@ -1,15 +1,13 @@
package lnwire
import (
// "github.com/roasbeef/btcutil"
"testing"
)
var (
closeComplete = &CloseComplete{
ReservationID: uint64(12345678),
ChannelID: uint64(12345678),
ResponderCloseSig: commitSig,
CloseShaHash: shaHash1,
}
closeCompleteSerializedString = "0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1dfe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
closeCompleteSerializedMessage = "0709110b000001360000006f0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1dfe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

@ -2,26 +2,48 @@ package lnwire
import (
"fmt"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcutil"
"io"
)
// CloseRequest is sent by either side in order to initiate the cooperative
// closure of a channel. This message is rather sparse as both side implicitly
// know to craft a transaction sending the settled funds of both parties to the
// final delivery addresses negotiated during the funding workflow.
//
// NOTE: The requester is able to only send a signature to initiate the
// cooperative channel closure as all transactions are assembled observing
// BIP 69 which defines a cannonical ordering for input/outputs. Therefore,
// both sides are able to arrive at an identical closure transaction as they
// know the order of the inputs/outputs.
type CloseRequest struct {
ReservationID uint64
// ChannelID serves to identify which channel is to be closed.
ChannelID uint64
RequesterCloseSig *btcec.Signature // Requester's Commitment
Fee btcutil.Amount
// RequesterCloseSig is the signature of the requester for the fully
// assembled closing transaction.
RequesterCloseSig *btcec.Signature
// Fee is the required fee-per-KB the closing transaction must have.
// It is recommended that a "sufficient" fee be paid in order to achieve
// timely channel closure.
Fee btcutil.Amount
}
// Decode deserializes a serialized CloseRequest stored in the passed io.Reader
// observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CloseRequest) Decode(r io.Reader, pver uint32) error {
// ReservationID (8)
// ChannelID (8)
// RequesterCloseSig (73)
// First byte length then sig
// Fee (8)
err := readElements(r,
&c.ReservationID,
&c.ChannelID,
&c.RequesterCloseSig,
&c.Fee)
if err != nil {
@ -31,19 +53,25 @@ func (c *CloseRequest) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new CloseRequest
// NewCloseRequest creates a new CloseRequest.
func NewCloseRequest() *CloseRequest {
return &CloseRequest{}
}
// Serializes the item from the CloseRequest struct
// Writes the data to w
// A compile time check to ensure CloseRequest implements the lnwire.Message
// interface.
var _ Message = (*CloseRequest)(nil)
// Encode serializes the target CloseRequest into the passed io.Writer observing
// the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *CloseRequest) Encode(w io.Writer, pver uint32) error {
// ReservationID
// ChannelID
// RequesterCloseSig
// Fee
err := writeElements(w,
c.ReservationID,
c.ChannelID,
c.RequesterCloseSig,
c.Fee)
if err != nil {
@ -53,25 +81,40 @@ func (c *CloseRequest) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *CloseRequest) Command() uint32 {
return CmdCloseRequest
}
func (c *CloseRequest) MaxPayloadLength(uint32) uint32 {
// MaxPayloadLength returns the maximum allowed payload size for this message
// observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CloseRequest) MaxPayloadLength(pver uint32) uint32 {
// 8 + 73 + 8
return 89
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the CloseRequest are valid.
//
// This is part of the lnwire.Message interface.
func (c *CloseRequest) Validate() error {
// Fee must be greater than 0
// Fee must be greater than 0.
if c.Fee < 0 {
return fmt.Errorf("Fee must be greater than zero.")
}
// We're good!
return nil
}
// String returns the string representation of the target CloseRequest.
//
// This is part of the lnwire.Message interface.
func (c *CloseRequest) String() string {
var serializedSig []byte
if c.RequesterCloseSig != nil && c.RequesterCloseSig.R != nil {
@ -79,7 +122,7 @@ func (c *CloseRequest) String() string {
}
return fmt.Sprintf("\n--- Begin CloseRequest ---\n") +
fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) +
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +
fmt.Sprintf("CloseSig\t\t%x\n", serializedSig) +
fmt.Sprintf("Fee:\t\t\t%d\n", c.Fee) +
fmt.Sprintf("--- End CloseRequest ---\n")

@ -1,13 +1,14 @@
package lnwire
import (
"github.com/roasbeef/btcutil"
"testing"
"github.com/roasbeef/btcutil"
)
var (
closeRequest = &CloseRequest{
ReservationID: uint64(12345678),
ChannelID: uint64(12345678),
RequesterCloseSig: commitSig,
Fee: btcutil.Amount(12345),
}

@ -5,17 +5,38 @@ import (
"io"
)
// Multiple Clearing Requests are possible by putting this inside an array of
// clearing requests
// CommitRevocation is sent by either side once a CommitSignature message has
// been received, and validated. This message serves to revoke the prior
// commitment transaction, which was the most up to date version until a
// CommitSignature message referencing the specified ChannelID was received.
// Additionally, this message also piggyback's the next revocation hash that
// Alice should use when constructing the Bob's version of the next commitment
// transaction (which would be done before sending a CommitSignature message).
// This piggybacking allows Alice to send the next CommitSignature message
// modifying Bob's commitment transaction without first asking for a revocation
// hash initially.
type CommitRevocation struct {
//Next revocation to use
// ChannelID uniquely identifies to which currently active channel this
// CommitRevocation applies to.
ChannelID uint64
// Revocation is the pre-image to the revocation hash of the now prior
// commitment transaction.
Revocation [20]byte
// NextRevocationHash is the next revocation hash to use to create the
// next commitment transaction which is to be created upon receipt of a
// CommitSignature message.
NextRevocationHash [20]byte
Revocation [20]byte
}
// Decode deserializes a serialized CommitRevocation message stored in the
// passed io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CommitRevocation) Decode(r io.Reader, pver uint32) error {
// NextRevocationHash(20)
// Revocation(20)
// NextRevocationHash (20)
// Revocation (20)
err := readElements(r,
&c.NextRevocationHash,
&c.Revocation,
@ -27,13 +48,19 @@ func (c *CommitRevocation) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new CommitRevocation
// NewCommitRevocation creates a new CommitRevocation message.
func NewCommitRevocation() *CommitRevocation {
return &CommitRevocation{}
}
// Serializes the item from the CommitRevocation struct
// Writes the data to w
// A compile time check to ensure CommitRevocation implements the lnwire.Message
// interface.
var _ Message = (*CommitRevocation)(nil)
// Encode serializes the target CommitRevocation into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *CommitRevocation) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.NextRevocationHash,
@ -46,22 +73,38 @@ func (c *CommitRevocation) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *CommitRevocation) Command() uint32 {
return CmdCommitRevocation
}
// MaxPayloadLength returns the maximum allowed payload size for a
// CommitRevocation complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CommitRevocation) MaxPayloadLength(uint32) uint32 {
// 8 + 20 + 20
return 48
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the CommitRevocation are valid.
//
// This is part of the lnwire.Message interface.
func (c *CommitRevocation) Validate() error {
// We're good!
return nil
}
// String returns the string representation of the target CommitRevocation.
//
// This is part of the lnwire.Message interface.
func (c *CommitRevocation) String() string {
return fmt.Sprintf("\n--- Begin CommitRevocation ---\n") +
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
fmt.Sprintf("NextRevocationHash:\t%x\n", c.NextRevocationHash) +
fmt.Sprintf("Revocation:\t%x\n", c.Revocation) +
fmt.Sprintf("--- End CommitRevocation ---\n")

@ -11,7 +11,7 @@ var (
commitRevocation = &CommitRevocation{
ChannelID: uint64(12345678),
RevocationProof: revocationHash, // technically it's not a hash... fix later
Revocation: revocationHash, // technically it's not a hash... fix later
NextRevocationHash: nextHop, // technically it's not a hash... fix later
}
commitRevocationSerializedString = "0000000000bc614e4132b6b48371f7b022a16eacb9b2b0ebee134d4194a9ded5a30fc5944cb1e2cbcd980f30616a1440"

@ -2,33 +2,47 @@ package lnwire
import (
"fmt"
"io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcutil"
"io"
)
// Multiple Clearing Requests are possible by putting this inside an array of
// clearing requests
// CommitSignature is sent by either side to stage any pending HTLC's in the
// reciever's pending set which has not explcitly been rejected via an
// HTLCAddReject message. Implictly, the new commitment transaction constructed
// which has been signed by CommitSig includes all HTLC's in the remote node's
// pending set. A CommitSignature message may be sent after a series of HTLCAdd
// messages in order to batch add several HTLC's with a single signature
// covering all implicitly accepted HTLC's.
type CommitSignature struct {
// List of HTLC Keys which are updated from all parties
//UpdatedHTLCKeys []uint64
HighestPosition uint64
// ChannelID uniquely identifies to which currently active channel this
// CommitSignature applies to.
ChannelID uint64
// Total miners' fee that was used
// Fee represents the total miner's fee that was used when constructing
// the new commitment transaction.
// TODO(roasbeef): is the above comment correct?
Fee btcutil.Amount
// Signature for the new Commitment
CommitSig *btcec.Signature // Requester's Commitment
// CommitSig is Alice's signature for Bob's new commitment transaction.
// Alice is able to send this signature without requesting any additional
// data due to the piggybacking of Bob's next revocation hash in his
// prior CommitRevocation message, as well as the cannonical ordering
// used for all inputs/outputs within commitment transactions.
CommitSig *btcec.Signature
}
// Decode deserializes a serialized CommitSignature message stored in the
// passed io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
// ChannelID(8)
// CommitmentHeight(8)
// RevocationHash(20)
// Fee(8)
// RequesterCommitSig(73max+2)
err := readElements(r,
&c.HighestPosition,
&c.ChannelID,
&c.Fee,
&c.CommitSig,
)
@ -39,59 +53,68 @@ func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new CommitSignature
// NewCommitSignature creates a new empty CommitSignature message.
func NewCommitSignature() *CommitSignature {
return &CommitSignature{}
}
// Serializes the item from the CommitSignature struct
// Writes the data to w
func (c *CommitSignature) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.HighestPosition,
c.Fee,
c.CommitSig,
)
if err != nil {
return err
}
// A compile time check to ensure CommitSignature implements the lnwire.Message
// interface.
var _ Message = (*CommitSignature)(nil)
return nil
// Encode serializes the target CommitSignature into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *CommitSignature) Encode(w io.Writer, pver uint32) error {
// TODO(roasbeef): make similar modificaiton to all other encode/decode
// messags
return writeElements(w, c.ChannelID, c.Fee, c.CommitSig)
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *CommitSignature) Command() uint32 {
return CmdCommitSignature
}
// MaxPayloadLength returns the maximum allowed payload size for a
// CommitSignature complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *CommitSignature) MaxPayloadLength(uint32) uint32 {
return 8192
// 8 + 8 + 73
return 89
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the CommitSignature are valid.
//
// This is part of the lnwire.Message interface.
func (c *CommitSignature) Validate() error {
if c.Fee < 0 {
// While fees can be negative, it's too confusing to allow
// negative payments. Maybe for some wallets, but not this one!
return fmt.Errorf("Amount paid cannot be negative.")
}
// We're good!
return nil
}
// String returns the string representation of the target CommitSignature.
//
// This is part of the lnwire.Message interface.
func (c *CommitSignature) String() string {
// c.ChannelID,
// c.CommitmentHeight,
// c.RevocationHash,
// c.UpdatedHTLCKeys,
// c.Fee,
// c.CommitSig,
var serializedSig []byte
if c.CommitSig != nil && c.CommitSig.R != nil {
if c.CommitSig != nil {
serializedSig = c.CommitSig.Serialize()
}
return fmt.Sprintf("\n--- Begin CommitSignature ---\n") +
fmt.Sprintf("HighestPosition:\t%d\n", c.HighestPosition) +
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
fmt.Sprintf("Fee:\t\t\t%s\n", c.Fee.String()) +
fmt.Sprintf("CommitSig:\t\t%x\n", serializedSig) +
fmt.Sprintf("--- End CommitSignature ---\n")

@ -1,8 +1,9 @@
package lnwire
import (
"github.com/roasbeef/btcutil"
"testing"
"github.com/roasbeef/btcutil"
)
var (
@ -10,13 +11,9 @@ var (
_ = copy(revocationHash[:], revocationHashBytes)
commitSignature = &CommitSignature{
ChannelID: uint64(12345678),
CommitmentHeight: uint64(12345),
LastCommittedKeyAlice: HTLCKey(12345),
LastCommittedKeyBob: HTLCKey(54321),
RevocationHash: revocationHash,
Fee: btcutil.Amount(10000),
CommitSig: commitSig,
ChannelID: uint64(12345678),
Fee: btcutil.Amount(10000),
CommitSig: commitSig,
}
commitSignatureSerializedString = "0000000000bc614e00000000000030390000000000003039000000000000d4314132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"
commitSignatureSerializedMessage = "0709110b000007d0000000830000000000bc614e00000000000030390000000000003039000000000000d4314132b6b48371f7b022a16eacb9b2b0ebee134d4100000000000027104630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df"

@ -5,16 +5,30 @@ import (
"io"
)
// Multiple Clearing Requests are possible by putting this inside an array of
// clearing requests
// ErrorGeneric represents a generic error bound to an exact channel. The
// message format is purposefully general in order to allow expressino of a wide
// array of possible errors. Each ErrorGeneric message is directed at a particular
// open channel referenced by ChannelID.
type ErrorGeneric struct {
// We can use a different data type for this if necessary...
// ChannelID references the active channel in which the error occured
// within.
ChannelID uint64
// Some kind of message
// Max length 8192
// TODO(roasbeef): uint16 for problem type?
// ErrorID uint16
// Problem is a human-readable string further elaborating upon the
// nature of the exact error. The maxmium allowed length of this
// message is 8192 bytes.
Problem string
// TODO(roasbeef): add SerializeSize?
}
// Decode deserializes a serialized ErrorGeneric message stored in the
// passed io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error {
// ChannelID(8)
// Problem
@ -29,13 +43,19 @@ func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new ErrorGeneric
// NewErrorGeneric creates a new ErrorGeneric message.
func NewErrorGeneric() *ErrorGeneric {
return &ErrorGeneric{}
}
// Serializes the item from the ErrorGeneric struct
// Writes the data to w
// A compile time check to ensure ErrorGeneric implements the lnwire.Message
// interface.
var _ Message = (*ErrorGeneric)(nil)
// Encode serializes the target ErrorGeneric into the passed io.Writer
// observing the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *ErrorGeneric) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.ChannelID,
@ -48,24 +68,39 @@ func (c *ErrorGeneric) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying an ErrorGeneric message on
// the wire.
//
// This is part of the lnwire.Message interface.
func (c *ErrorGeneric) Command() uint32 {
return CmdErrorGeneric
}
// MaxPayloadLength returns the maximum allowed payload size for a
// ErrorGeneric complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *ErrorGeneric) MaxPayloadLength(uint32) uint32 {
// 8+8192
return 8208
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the ErrorGeneric are valid.
//
// This is part of the lnwire.Message interface.
func (c *ErrorGeneric) Validate() error {
if len(c.Problem) > 8192 {
return fmt.Errorf("Problem string length too long")
return fmt.Errorf("problem string length too long")
}
// We're good!
return nil
}
// String returns the string representation of the target ErrorGeneric.
//
// This is part of the lnwire.Message interface.
func (c *ErrorGeneric) String() string {
return fmt.Sprintf("\n--- Begin ErrorGeneric ---\n") +
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +

@ -2,10 +2,11 @@ package lnwire
import (
"fmt"
"io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
"io"
)
type FundingRequest struct {
@ -150,8 +151,6 @@ func (c *FundingRequest) MaxPayloadLength(uint32) uint32 {
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
func (c *FundingRequest) Validate() error {
var err error
// No negative values
if c.RequesterFundingAmount < 0 {
return fmt.Errorf("RequesterFundingAmount cannot be negative")
@ -187,15 +186,16 @@ func (c *FundingRequest) Validate() error {
}
// DeliveryPkScript is either P2SH or P2PKH
err = ValidatePkScript(c.DeliveryPkScript)
if err != nil {
return err
if !isValidPkScript(c.DeliveryPkScript) {
// TODO(roasbeef): move into actual error
return fmt.Errorf("Valid delivery public key scripts MUST be: " +
"P2PKH, P2WKH, P2SH, or P2WSH.")
}
// ChangePkScript is either P2SH or P2PKH
err = ValidatePkScript(c.ChangePkScript)
if err != nil {
return err
if !isValidPkScript(c.ChangePkScript) {
return fmt.Errorf("Valid change public key script MUST be: " +
"P2PKH, P2WKH, P2SH, or P2WSH.")
}
// We're good!

@ -1,8 +1,9 @@
package lnwire
import (
"github.com/roasbeef/btcutil"
"testing"
"github.com/roasbeef/btcutil"
)
var (

@ -2,10 +2,11 @@ package lnwire
import (
"fmt"
"io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
"io"
)
type FundingResponse struct {
@ -134,8 +135,6 @@ func (c *FundingResponse) MaxPayloadLength(uint32) uint32 {
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
func (c *FundingResponse) Validate() error {
var err error
// No negative values
if c.ResponderFundingAmount < 0 {
return fmt.Errorf("ResponderFundingAmount cannot be negative")
@ -160,15 +159,16 @@ func (c *FundingResponse) Validate() error {
}
// Delivery PkScript is either P2SH or P2PKH
err = ValidatePkScript(c.DeliveryPkScript)
if err != nil {
return err
if !isValidPkScript(c.DeliveryPkScript) {
return fmt.Errorf("Valid delivery public key scripts MUST be: " +
"P2PKH, P2WKH, P2SH, or P2WSH.")
}
// Change PkScript is either P2SH or P2PKH
err = ValidatePkScript(c.ChangePkScript)
if err != nil {
return err
if !isValidPkScript(c.ChangePkScript) {
// TODO(roasbeef): move into actual error
return fmt.Errorf("Valid change public key scripts MUST be: " +
"P2PKH, P2WKH, P2SH, or P2WSH.")
}
// We're good!

@ -1,8 +1,9 @@
package lnwire
import (
"github.com/roasbeef/btcutil"
"testing"
"github.com/roasbeef/btcutil"
)
var (

@ -2,8 +2,9 @@ package lnwire
import (
"fmt"
"github.com/roasbeef/btcd/btcec"
"io"
"github.com/roasbeef/btcd/btcec"
)
type FundingSignAccept struct {

@ -2,9 +2,10 @@ package lnwire
import (
"fmt"
"io"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/wire"
"io"
)
type FundingSignComplete struct {

@ -5,17 +5,28 @@ import (
"io"
)
// HTLCAddReject is sent by Bob when he wishes to reject a particular HTLC that
// Alice attempted to add via an HTLCAddRequest message. The rejected HTLC is
// referenced by its unique HTLCKey ID. An HTLCAddReject message is bound to a
// single active channel, referenced by a unique ChannelID. Additionally, the
// HTLCKey of the rejected HTLC is present
type HTLCAddReject struct {
// ChannelID references the particular active channel to which this
// HTLCAddReject message is binded to.
ChannelID uint64
HTLCKey HTLCKey
// HTLCKey is used to identify which HTLC previously attempted to be
// added via an HTLCAddRequest message is being declined.
HTLCKey HTLCKey
}
// Decode deserializes a serialized HTLCAddReject message stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
// ChannelID(8)
// CommitmentHeight(8)
// NextResponderCommitmentRevocationHash(20)
// ResponderRevocationPreimage(20)
// ResponderCommitSig(2+73max)
// ChannelID (8)
// HTLCKey (8)
err := readElements(r,
&c.ChannelID,
&c.HTLCKey,
@ -27,13 +38,19 @@ func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new HTLCAddReject
// NewHTLCAddReject returns a new empty HTLCAddReject message.
func NewHTLCAddReject() *HTLCAddReject {
return &HTLCAddReject{}
}
// Serializes the item from the HTLCAddReject struct
// Writes the data to w
// A compile time check to ensure HTLCAddReject implements the lnwire.Message
// interface.
var _ Message = (*HTLCAddReject)(nil)
// Encode serializes the target HTLCAddReject into the passed io.Writer observing
// the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.ChannelID,
@ -47,21 +64,35 @@ func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddReject) Command() uint32 {
return CmdHTLCAddReject
}
// MaxPayloadLength returns the maximum allowed payload size for a HTLCAddReject
// complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddReject) MaxPayloadLength(uint32) uint32 {
// 16 base size
// 8 + 8
return 16
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the HTLCAddReject are valid.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddReject) Validate() error {
// We're good!
return nil
}
// String returns the string representation of the target HTLCAddReject.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddReject) String() string {
return fmt.Sprintf("\n--- Begin HTLCAddReject ---\n") +
fmt.Sprintf("ChannelID:\t\t%d\n", c.ChannelID) +

@ -7,7 +7,7 @@ import (
var (
htlcAddReject = &HTLCAddReject{
ChannelID: uint64(12345678),
HTLCKey: HTLCKey(12345),
HTLCKey: HTLCKey(12345),
}
htlcAddRejectSerializedString = "0000000000bc614e0000000000003039"
htlcAddRejectSerializedMessage = "0709110b000003fc000000100000000000bc614e0000000000003039"

@ -5,56 +5,83 @@ import (
"io"
)
// Multiple Clearing Requests are possible by putting this inside an array of
// clearing requests
// HTLCAddRequest is the message sent by Alice to Bob when she wishes to add an
// HTLC to his remote commitment transaction. In addition to information
// detailing the value, and contract type of the HTLC, and onion blob is also
// included which allows Bob to derive the next hop in the route. The HTLC
// added by this message is to be added to the remote node's "pending" HTLC's.
// A subsequent CommitSignature message will move the pending HTLC to the newly
// created commitment transaction, marking them as "staged".
type HTLCAddRequest struct {
// We can use a different data type for this if necessary...
// ChannelID is the particular active channel that this HTLCAddRequest
// is binded to.
ChannelID uint64
// ID of this request
// implicit
// HTLCKey HTLCKey
// When the HTLC expires
// Expiry is the number of blocks after which this HTLC should expire.
// It is the receiver's duty to ensure that the outgoing HTLC has a
// sufficient expiry value to allow her to redeem the incmoing HTLC.
Expiry uint32
// Amount to pay in the hop
// Difference between hop and first item in blob is the fee to complete
// Amount is the number of credits this HTLC is worth.
Amount CreditsAmount
// RefundContext is for payment cancellation
// TODO (j): not currently in use, add later
// TODO(j): not currently in use, add later
RefundContext HTLCKey
// Contract Type
// first 4 bits is n, second for is m, in n-of-m "multisig"
// default is 0.
// ContractType defines the particular output script to be used for
// this HTLC. This value defaults to zero for regular HTLCs. For
// multi-sig HTLCs, then first 4 bit represents N, while the second 4
// bits are M, within the N-of-M multi-sig.
ContractType uint8
// Redemption Hashes
RedemptionHashes []*[20]byte
// RedemptionHashes are the hashes to be used within the HTLC script.
// An HTLC is only fufilled once Bob is provided with the required
// number of pre-images for each of the listed hashes. For regular HTLC's
// this slice only has one hash. However, for "multi-sig" HTLC's, the
// length of this slice should be N.
RedemptionHashes [][20]byte
// Data to parse&pass on to the next node
// Nested HTLCAddRequests with a uint32 in front for the size
Blob []byte
// OnionBlob is the raw serialized mix header used to route an HTLC in
// a privacy-preserving manner. The mix header is defined currently to
// be parsed as a 4-tuple: (groupElement, routingInfo, headerMAC, body).
// First the receiving node should use the groupElement, and its current
// onion key to derive a shared secret with the source. Once the shared
// secret has been derived, the headerMAC should be checked FIRST. Note
// that the MAC only covers the routingInfo field. If the MAC matches,
// and the shared secret is fresh, then the node should stip off a layer
// of encryption, exposing the next hop to be used in the subsequent
// HTLCAddRequest message.
OnionBlob []byte
}
// Decode deserializes a serialized HTLCAddRequest message stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error {
// ChannelID(8)
// HTLCKey(8)
// Expiry(4)
// Amount(4)
// ContractType(1)
// RedemptionHashes (numOfHashes * 20 + numOfHashes)
// Blob(2+blobsize)
// OnionBlog
err := readElements(r,
&c.ChannelID,
&c.HTLCKey,
&c.Expiry,
&c.Amount,
&c.ContractType,
&c.RedemptionHashes,
&c.Blob,
&c.OnionBlob,
)
if err != nil {
return err
@ -63,22 +90,28 @@ func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new HTLCAddRequest
// NewHTLCAddRequest returns a new empty HTLCAddRequest message.
func NewHTLCAddRequest() *HTLCAddRequest {
return &HTLCAddRequest{}
}
// Serializes the item from the HTLCAddRequest struct
// Writes the data to w
// A compile time check to ensure HTLCAddRequest implements the lnwire.Message
// interface.
var _ Message = (*HTLCAddRequest)(nil)
// Encode serializes the target HTLCAddRequest into the passed io.Writer observing
// the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.ChannelID,
c.HTLCKey,
c.Expiry,
c.Amount,
c.ContractType,
c.RedemptionHashes,
c.Blob,
c.OnionBlob,
)
if err != nil {
return err
@ -87,17 +120,28 @@ func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddRequest) Command() uint32 {
return CmdHTLCAddRequest
}
// MaxPayloadLength returns the maximum allowed payload size for a HTLCAddRequest
// complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddRequest) MaxPayloadLength(uint32) uint32 {
// base size ~110, but blob can be variable.
// shouldn't be bigger than 8K though...
return 8192
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the HTLCAddRequest are valid.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddRequest) Validate() error {
if c.Amount < 0 {
// While fees can be negative, it's too confusing to allow
@ -108,21 +152,24 @@ func (c *HTLCAddRequest) Validate() error {
return nil
}
// String returns the string representation of the target HTLCAddRequest.
//
// This is part of the lnwire.Message interface.
func (c *HTLCAddRequest) String() string {
var redemptionHashes string
for i, rh := range c.RedemptionHashes {
redemptionHashes += fmt.Sprintf("\n\tSlice\t%d\n", i)
redemptionHashes += fmt.Sprintf("\t\tRedemption Hash: %x\n", *rh)
redemptionHashes += fmt.Sprintf("\t\tRedemption Hash: %x\n", rh)
}
return fmt.Sprintf("\n--- Begin HTLCAddRequest ---\n") +
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +
fmt.Sprintf("HTLCKey:\t%d\n", c.HTLCKey) +
fmt.Sprintf("Expiry:\t\t%d\n", c.Expiry) +
fmt.Sprintf("Amount\t\t%d\n", c.Amount) +
fmt.Sprintf("ContractType:\t%d (%b)\n", c.ContractType, c.ContractType) +
fmt.Sprintf("RedemptionHashes:") +
redemptionHashes +
fmt.Sprintf("Blob:\t\t\t\t%x\n", c.Blob) +
fmt.Sprintf("OnionBlob:\t\t\t\t%x\n", c.OnionBlob) +
fmt.Sprintf("--- End HTLCAddRequest ---\n")
}

@ -8,18 +8,16 @@ var (
// Need to to do this here
_ = copy(revocationHash[:], revocationHashBytes)
_ = copy(redemptionHash[:], redemptionHashBytes)
emptyRedemptionHashes = []*[20]byte{}
redemptionHashes = append(emptyRedemptionHashes, &redemptionHash)
emptyRedemptionHashes = [][20]byte{}
redemptionHashes = append(emptyRedemptionHashes, redemptionHash)
htlcAddRequest = &HTLCAddRequest{
ChannelID: uint64(12345678),
HTLCKey: HTLCKey(12345),
Expiry: uint32(144),
Amount: CreditsAmount(123456000),
ContractType: uint8(17),
RedemptionHashes: redemptionHashes,
Blob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
Blob: []byte{255, 0, 255, 0, 255, 0, 255, 0},
}
htlcAddRequestSerializedString = "0000000000bc614e00000000000030390000009000000000075bca001100015b315ebabb0d8c0d94281caa2dfee69a1a00436e0008ff00ff00ff00ff00"

@ -5,19 +5,32 @@ import (
"io"
)
// Multiple Clearing Requests are possible by putting this inside an array of
// clearing requests
// HTLCSettleRequest is sent by Alice to Bob when she wishes to settle a
// particular HTLC referenced by its HTLCKey within a specific active channel
// referenced by ChannelID. The message allows multiple hash preimages to be
// presented in order to support N-of-M HTLC contracts. A subsequent
// CommitSignature message will be sent by Alice to "lock-in" the removal of the
// specified HTLC, possible containing a batch signature covering several settled
// HTLC's.
type HTLCSettleRequest struct {
// We can use a different data type for this if necessary...
// ChannelID references an active channel which holds the HTLC to be
// settled.
ChannelID uint64
// ID of this request
// HTLCKey denotes the exact HTLC stage within the receiving node's
// commitment transaction to be removed.
HTLCKey HTLCKey
// Redemption Proofs (R-Values)
RedemptionProofs []*[20]byte
// RedemptionProofs are the R-value preimages required to fully settle
// an HTLC. The number of preimages in the slice will depend on the
// specific ContractType of the referenced HTLC.
RedemptionProofs [][20]byte
}
// Decode deserializes a serialized HTLCSettleRequest message stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
// ChannelID(8)
// HTLCKey(8)
@ -39,11 +52,15 @@ func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new HTLCSettleRequest
// NewHTLCSettleRequest returns a new empty HTLCSettleRequest.
func NewHTLCSettleRequest() *HTLCSettleRequest {
return &HTLCSettleRequest{}
}
// A compile time check to ensure HTLCSettleRequest implements the lnwire.Message
// interface.
var _ Message = (*HTLCSettleRequest)(nil)
// Serializes the item from the HTLCSettleRequest struct
// Writes the data to w
func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error {
@ -59,26 +76,40 @@ func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *HTLCSettleRequest) Command() uint32 {
return CmdHTLCSettleRequest
}
// MaxPayloadLength returns the maximum allowed payload size for a HTLCSettleRequest
// complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCSettleRequest) MaxPayloadLength(uint32) uint32 {
// 21*15+16
// 8 + 8 + (21 * 15)
return 331
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the HTLCSettleRequest are valid.
//
// This is part of the lnwire.Message interface.
func (c *HTLCSettleRequest) Validate() error {
// We're good!
return nil
}
// String returns the string representation of the target HTLCSettleRequest.
//
// This is part of the lnwire.Message interface.
func (c *HTLCSettleRequest) String() string {
var redemptionProofs string
for i, rh := range c.RedemptionProofs {
redemptionProofs += fmt.Sprintf("\n\tSlice\t%d\n", i)
redemptionProofs += fmt.Sprintf("\t\tRedemption Proof: %x\n", *rh)
redemptionProofs += fmt.Sprintf("\t\tRedemption Proof: %x\n", rh)
}
return fmt.Sprintf("\n--- Begin HTLCSettleRequest ---\n") +

@ -7,8 +7,8 @@ import (
var (
// Need to to do this here
_ = copy(redemptionHash[:], redemptionHashBytes)
emptyRedemptionProofs = []*[20]byte{}
redemptionProofs = append(emptyRedemptionProofs, &redemptionHash)
emptyRedemptionProofs = [][20]byte{}
redemptionProofs = append(emptyRedemptionProofs, redemptionHash)
htlcSettleRequest = &HTLCSettleRequest{
ChannelID: uint64(12345678),

@ -5,16 +5,24 @@ import (
"io"
)
// Multiple Clearing Requests are possible by putting this inside an array of
// clearing requests
// HTLCTimeoutRequest is sent by Alice to Bob in order to timeout a previously
// added HTLC. Upon receipt of an HTLCTimeoutRequest the HTLC should be removed
// from the next commitment transaction, with the HTLCTimeoutRequest propgated
// backwards in the route to fully clear the HTLC.
type HTLCTimeoutRequest struct {
// We can use a different data type for this if necessary...
// ChannelID is the particular active channel that this HTLCTimeoutRequest
// is binded to.
ChannelID uint64
// ID of this request
// HTLCKey references which HTLC on the remote node's commitment
// transaction has timed out.
HTLCKey HTLCKey
}
// Decode deserializes a serialized HTLCTimeoutRequest message stored in the passed
// io.Reader observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
// ChannelID(8)
// HTLCKey(8)
@ -29,13 +37,19 @@ func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
return nil
}
// Creates a new HTLCTimeoutRequest
// NewHTLCTimeoutRequest creates a new HTLCTimeoutRequest message.
func NewHTLCTimeoutRequest() *HTLCTimeoutRequest {
return &HTLCTimeoutRequest{}
}
// Serializes the item from the HTLCTimeoutRequest struct
// Writes the data to w
// A compile time check to ensure HTLCTimeoutRequest implements the lnwire.Message
// interface.
var _ Message = (*HTLCTimeoutRequest)(nil)
// Encode serializes the target HTLCTimeoutRequest into the passed io.Writer observing
// the protocol version specified.
//
// This is part of the lnwire.Message interface.
func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error {
err := writeElements(w,
c.ChannelID,
@ -48,21 +62,34 @@ func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the integer uniquely identifying this message type on the
// wire.
//
// This is part of the lnwire.Message interface.
func (c *HTLCTimeoutRequest) Command() uint32 {
return CmdHTLCTimeoutRequest
}
// MaxPayloadLength returns the maximum allowed payload size for a HTLCTimeoutRequest
// complete message observing the specified protocol version.
//
// This is part of the lnwire.Message interface.
func (c *HTLCTimeoutRequest) MaxPayloadLength(uint32) uint32 {
// 16
return 16
}
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
// Validate performs any necessary sanity checks to ensure all fields present
// on the HTLCTimeoutRequest are valid.
//
// This is part of the lnwire.Message interface.
func (c *HTLCTimeoutRequest) Validate() error {
// We're good!
return nil
}
// String returns the string representation of the target HTLCTimeoutRequest. //
// This is part of the lnwire.Message interface.
func (c *HTLCTimeoutRequest) String() string {
return fmt.Sprintf("\n--- Begin HTLCTimeoutRequest ---\n") +
fmt.Sprintf("ChannelID:\t%d\n", c.ChannelID) +

@ -7,7 +7,7 @@ import (
var (
htlcTimeoutRequest = &HTLCTimeoutRequest{
ChannelID: uint64(12345678),
HTLCKey: HTLCKey(12345),
HTLCKey: HTLCKey(12345),
}
htlcTimeoutRequestSerializedString = "0000000000bc614e0000000000003039"
htlcTimeoutRequestSerializedMessage = "0709110b00000514000000100000000000bc614e0000000000003039"

@ -209,6 +209,8 @@ func (s *server) listener(l net.Listener) {
srvrLog.Tracef("New inbound connection from %v", conn.RemoteAddr())
peer := newPeer(conn, s)
peer.Start()
s.newPeers <- peer
}
s.wg.Done()