lnwire: update single funder workflow to use revocation keys
This commit updates the messages sent during a single funder workflow to utilize revocation keys rather than revocation hashes. This now matches the latest updates to the commitment transaction. The changes to the workflow are as follows: * the response message now carries the responder’s revocation key * the complete message now carries the initiator’s revocation key Once the initiator receives the response message, it can construct both versions of the commitment transaction as it now knows the responder’s commitment key. The initiator then sends their initial revocation key over to the responder allowing it to construct the commitment transactions and give the initiator a sig for their version.
This commit is contained in:
parent
582b83ada3
commit
fd02c1c1aa
@ -28,17 +28,25 @@ type SingleFundingComplete struct {
|
||||
// CommitSignature is Alice's signature for Bob's version of the
|
||||
// commitment transaction.
|
||||
CommitSignature *btcec.Signature
|
||||
|
||||
// RevocationKey is the initial key to be used for the revocation
|
||||
// clause within the self-output of the initiators's commitment
|
||||
// transaction. Once an initial new state is created, the initiator
|
||||
// will send a pre-image which will allow the initiator to sweep the
|
||||
// initiator's funds if the violate the contract.
|
||||
RevocationKey *btcec.PublicKey
|
||||
}
|
||||
|
||||
// NewSingleFundingComplete creates, and returns a new empty
|
||||
// SingleFundingResponse.
|
||||
func NewSingleFundingComplete(chanID uint64, fundingPoint *wire.OutPoint,
|
||||
commitSig *btcec.Signature) *SingleFundingComplete {
|
||||
commitSig *btcec.Signature, revokeKey *btcec.PublicKey) *SingleFundingComplete {
|
||||
|
||||
return &SingleFundingComplete{
|
||||
ChannelID: chanID,
|
||||
FundingOutPoint: fundingPoint,
|
||||
CommitSignature: commitSig,
|
||||
RevocationKey: revokeKey,
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,11 +58,13 @@ func NewSingleFundingComplete(chanID uint64, fundingPoint *wire.OutPoint,
|
||||
func (s *SingleFundingComplete) Decode(r io.Reader, pver uint32) error {
|
||||
// ChannelID (8)
|
||||
// FundingOutPoint (36)
|
||||
// Commitment Signature (73)
|
||||
// CommitmentSignature (73)
|
||||
// RevocationKey (33)
|
||||
err := readElements(r,
|
||||
&s.ChannelID,
|
||||
&s.FundingOutPoint,
|
||||
&s.CommitSignature)
|
||||
&s.CommitSignature,
|
||||
&s.RevocationKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -71,10 +81,12 @@ func (s *SingleFundingComplete) Encode(w io.Writer, pver uint32) error {
|
||||
// ChannelID (8)
|
||||
// FundingOutPoint (36)
|
||||
// Commitment Signature (73)
|
||||
// RevocationKey (33)
|
||||
err := writeElements(w,
|
||||
s.ChannelID,
|
||||
s.FundingOutPoint,
|
||||
s.CommitSignature)
|
||||
s.CommitSignature,
|
||||
s.RevocationKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -92,13 +104,12 @@ func (s *SingleFundingComplete) Command() uint32 {
|
||||
|
||||
// MaxPayloadLength returns the maximum allowed payload length for a
|
||||
// SingleFundingComplete. This is calculated by summing the max length of all
|
||||
// the fields within a SingleFundingResponse. To enforce a maximum
|
||||
// DeliveryPkScript size, the size of a P2PKH public key script is used.
|
||||
// Therefore, the final breakdown is: 8 + 36 + 73 = 117
|
||||
// the fields within a SingleFundingResponse. Therefore, the final breakdown
|
||||
// is: 8 + 36 + 73 = 150
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (s *SingleFundingComplete) MaxPayloadLength(uint32) uint32 {
|
||||
return 117
|
||||
return 150
|
||||
}
|
||||
|
||||
// Validate examines each populated field within the SingleFundingComplete for
|
||||
@ -115,6 +126,8 @@ func (s *SingleFundingComplete) Validate() error {
|
||||
return fmt.Errorf("commitment signature must be non-nil")
|
||||
}
|
||||
|
||||
// TODO(roasbeef): fin validation
|
||||
|
||||
// We're good!
|
||||
return nil
|
||||
}
|
||||
@ -123,9 +136,15 @@ func (s *SingleFundingComplete) Validate() error {
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (s *SingleFundingComplete) String() string {
|
||||
var rk []byte
|
||||
if s.RevocationKey != nil {
|
||||
rk = s.RevocationKey.SerializeCompressed()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\n--- Begin SingleFundingComplete ---\n") +
|
||||
fmt.Sprintf("ChannelID:\t\t\t%d\n", s.ChannelID) +
|
||||
fmt.Sprintf("FundingOutPoint:\t\t\t%x\n", s.FundingOutPoint) +
|
||||
fmt.Sprintf("CommitSignature\t\t\t\t%x\n", s.CommitSignature) +
|
||||
fmt.Sprintf("RevocationKey\t\t\t\t%x\n", rk) +
|
||||
fmt.Sprintf("--- End SingleFundingComplete ---\n")
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestSingleFundingCompleteWire(t *testing.T) {
|
||||
// First create a new SFC message.
|
||||
sfc := NewSingleFundingComplete(22, outpoint1, commitSig1)
|
||||
sfc := NewSingleFundingComplete(22, outpoint1, commitSig1, pubKey)
|
||||
|
||||
// Next encode the SFC message into an empty bytes buffer.
|
||||
var b bytes.Buffer
|
||||
|
@ -1,7 +1,6 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@ -63,12 +62,6 @@ type SingleFundingRequest struct {
|
||||
// an odd y-coordinate.
|
||||
ChannelDerivationPoint *btcec.PublicKey
|
||||
|
||||
// RevocationHash is the initial revocation hash to be used for the
|
||||
// initiator's commitment transaction to derive their revocation public
|
||||
// key as: P + G*revocationHash, where P is the initiator's channel
|
||||
// public key.
|
||||
RevocationHash [20]byte
|
||||
|
||||
// DeliveryPkScript defines the public key script that the initiator
|
||||
// would like to use to receive their balance in the case of a
|
||||
// cooperative close. Only the following script templates are
|
||||
@ -81,7 +74,7 @@ type SingleFundingRequest struct {
|
||||
// NewSingleFundingRequest creates, and returns a new empty SingleFundingRequest.
|
||||
func NewSingleFundingRequest(chanID uint64, chanType uint8, coinType uint64,
|
||||
fee btcutil.Amount, amt btcutil.Amount, delay uint32, ck,
|
||||
cdp *btcec.PublicKey, revocation [20]byte, deliveryScript PkScript) *SingleFundingRequest {
|
||||
cdp *btcec.PublicKey, deliveryScript PkScript) *SingleFundingRequest {
|
||||
|
||||
return &SingleFundingRequest{
|
||||
ChannelID: chanID,
|
||||
@ -92,7 +85,6 @@ func NewSingleFundingRequest(chanID uint64, chanType uint8, coinType uint64,
|
||||
CsvDelay: delay,
|
||||
CommitmentKey: ck,
|
||||
ChannelDerivationPoint: cdp,
|
||||
RevocationHash: revocation,
|
||||
DeliveryPkScript: deliveryScript,
|
||||
}
|
||||
}
|
||||
@ -107,10 +99,10 @@ func (c *SingleFundingRequest) Decode(r io.Reader, pver uint32) error {
|
||||
// ChannelType (1)
|
||||
// CoinType (8)
|
||||
// FeePerKb (8)
|
||||
// FundingAmount (8)
|
||||
// CsvDelay (4)
|
||||
// Channel Derivation Point (32)
|
||||
// Revocation Hash (20)
|
||||
// PaymentAmount (8)
|
||||
// Delay (4)
|
||||
// Pubkey (33)
|
||||
// Pubkey (33)
|
||||
// DeliveryPkScript (final delivery)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
@ -121,7 +113,6 @@ func (c *SingleFundingRequest) Decode(r io.Reader, pver uint32) error {
|
||||
&c.CsvDelay,
|
||||
&c.CommitmentKey,
|
||||
&c.ChannelDerivationPoint,
|
||||
&c.RevocationHash,
|
||||
&c.DeliveryPkScript)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -141,9 +132,9 @@ func (c *SingleFundingRequest) Encode(w io.Writer, pver uint32) error {
|
||||
// CoinType (8)
|
||||
// FeePerKb (8)
|
||||
// PaymentAmount (8)
|
||||
// LockTime (4)
|
||||
// Revocation Hash (20)
|
||||
// Pubkey (32)
|
||||
// Delay (4)
|
||||
// Pubkey (33)
|
||||
// Pubkey (33)
|
||||
// DeliveryPkScript (final delivery)
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
@ -154,7 +145,6 @@ func (c *SingleFundingRequest) Encode(w io.Writer, pver uint32) error {
|
||||
c.CsvDelay,
|
||||
c.CommitmentKey,
|
||||
c.ChannelDerivationPoint,
|
||||
c.RevocationHash,
|
||||
c.DeliveryPkScript)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -175,11 +165,11 @@ func (c *SingleFundingRequest) Command() uint32 {
|
||||
// SingleFundingRequest. This is calculated by summing the max length of all
|
||||
// the fields within a SingleFundingRequest. To enforce a maximum
|
||||
// DeliveryPkScript size, the size of a P2PKH public key script is used.
|
||||
// Therefore, the final breakdown is: 8 + 1 + 8 + 8 + 8 + 4 + 33 + 33 + 20 + 25 = 114.
|
||||
// Therefore, the final breakdown is: 8 + 1 + 8 + 8 + 8 + 4 + 33 + 33 + 25 = 158.
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *SingleFundingRequest) MaxPayloadLength(uint32) uint32 {
|
||||
return 148
|
||||
return 158
|
||||
}
|
||||
|
||||
// Validate examines each populated field within the SingleFundingRequest for
|
||||
@ -212,12 +202,6 @@ func (c *SingleFundingRequest) Validate() error {
|
||||
//"y-coordinate")
|
||||
//}
|
||||
|
||||
// The revocation hash MUST be non-zero.
|
||||
var zeroHash [20]byte
|
||||
if bytes.Equal(c.RevocationHash[:], zeroHash[:]) {
|
||||
return fmt.Errorf("Initial revocation hash must be non-zero")
|
||||
}
|
||||
|
||||
// The delivery pkScript must be amongst the supported script
|
||||
// templates.
|
||||
if !isValidPkScript(c.DeliveryPkScript) {
|
||||
@ -249,7 +233,6 @@ func (c *SingleFundingRequest) String() string {
|
||||
fmt.Sprintf("FundingAmount:\t\t\t%s\n", c.FundingAmount.String()) +
|
||||
fmt.Sprintf("CsvDelay\t\t\t%d\n", c.CsvDelay) +
|
||||
fmt.Sprintf("ChannelDerivationPoint\t\t\t\t%x\n", serializedPubkey) +
|
||||
fmt.Sprintf("RevocationHash\t\t\t%x\n", c.RevocationHash) +
|
||||
fmt.Sprintf("DeliveryPkScript\t\t%x\n", c.DeliveryPkScript) +
|
||||
fmt.Sprintf("--- End SingleFundingRequest ---\n")
|
||||
}
|
||||
|
@ -8,10 +8,9 @@ import (
|
||||
|
||||
func TestSingleFundingRequestWire(t *testing.T) {
|
||||
// First create a new SFR message.
|
||||
var rev [20]byte
|
||||
cdp := pubKey
|
||||
delivery := PkScript(bytes.Repeat([]byte{0x02}, 25))
|
||||
sfr := NewSingleFundingRequest(20, 21, 22, 23, 5, 5, cdp, cdp, rev, delivery)
|
||||
sfr := NewSingleFundingRequest(20, 21, 22, 23, 5, 5, cdp, cdp, delivery)
|
||||
|
||||
// Next encode the SFR message into an empty bytes buffer.
|
||||
var b bytes.Buffer
|
||||
|
@ -1,7 +1,6 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@ -17,29 +16,30 @@ type SingleFundingResponse struct {
|
||||
// the initiated single funder workflow.
|
||||
ChannelID uint64
|
||||
|
||||
// RevocationHash is the initial revocation hash to be used for the
|
||||
// responders's commitment transaction to derive their revocation public
|
||||
// key as: P + G*revocationHash, where P is the initiator's channel
|
||||
// public key.
|
||||
RevocationHash [20]byte
|
||||
// ChannelDerivationPoint is an secp256k1 point which will be used to
|
||||
// derive the public key the responder will use for the half of the
|
||||
// 2-of-2 multi-sig. Using the channel derivation point (CDP), and the
|
||||
// responder's identity public key (A), the channel public key is
|
||||
// computed as: C = A + CDP. In order to be valid all CDP's MUST have
|
||||
// an odd y-coordinate.
|
||||
ChannelDerivationPoint *btcec.PublicKey
|
||||
|
||||
// CommitmentKey is key the responder to the funding workflow wishes to
|
||||
// use within their versino of the commitment transaction for any
|
||||
// delayed (CSV) or immediate outputs to them.
|
||||
CommitmentKey *btcec.PublicKey
|
||||
|
||||
// RevocationKey is the initial key to be used for the revocation
|
||||
// clause within the self-output of the responder's commitment
|
||||
// transaction. Once an initial new state is created, the responder
|
||||
// will send a pre-image which will allow the initiator to sweep the
|
||||
// responder's funds if the violate the contract.
|
||||
RevocationKey *btcec.PublicKey
|
||||
|
||||
// CsvDelay is the number of blocks to use for the relative time lock
|
||||
// in the pay-to-self output of both commitment transactions.
|
||||
CsvDelay uint32
|
||||
|
||||
// ChannelDerivationPoint is an secp256k1 point which will be used to
|
||||
// derive the public key the responder will use for the half of the
|
||||
// 2-of-2 multi-sig. Using the channel derivation point (CDP), and the
|
||||
// initiators identity public key (A), the channel public key is
|
||||
// computed as: C = A + CDP. In order to be valid all CDP's MUST have
|
||||
// an odd y-coordinate.
|
||||
ChannelDerivationPoint *btcec.PublicKey
|
||||
|
||||
// DeliveryPkScript defines the public key script that the initiator
|
||||
// would like to use to receive their balance in the case of a
|
||||
// cooperative close. Only the following script templates are
|
||||
@ -49,20 +49,23 @@ type SingleFundingResponse struct {
|
||||
|
||||
// NewSingleFundingResponse creates, and returns a new empty
|
||||
// SingleFundingResponse.
|
||||
func NewSingleFundingResponse(chanID uint64, revocation [20]byte,
|
||||
ck, cdp *btcec.PublicKey, delay uint32,
|
||||
deliveryScript PkScript) *SingleFundingResponse {
|
||||
func NewSingleFundingResponse(chanID uint64, rk, ck, cdp *btcec.PublicKey,
|
||||
delay uint32, deliveryScript PkScript) *SingleFundingResponse {
|
||||
|
||||
return &SingleFundingResponse{
|
||||
ChannelID: chanID,
|
||||
RevocationHash: revocation,
|
||||
CommitmentKey: ck,
|
||||
CsvDelay: delay,
|
||||
ChannelDerivationPoint: cdp,
|
||||
CommitmentKey: ck,
|
||||
RevocationKey: rk,
|
||||
CsvDelay: delay,
|
||||
DeliveryPkScript: deliveryScript,
|
||||
}
|
||||
}
|
||||
|
||||
// A compile time check to ensure SingleFundingResponse implements the
|
||||
// lnwire.Message interface.
|
||||
var _ Message = (*SingleFundingResponse)(nil)
|
||||
|
||||
// Decode deserializes the serialized SingleFundingResponse stored in the passed
|
||||
// io.Reader into the target SingleFundingResponse using the deserialization
|
||||
// rules defined by the passed protocol version.
|
||||
@ -70,14 +73,16 @@ func NewSingleFundingResponse(chanID uint64, revocation [20]byte,
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *SingleFundingResponse) Decode(r io.Reader, pver uint32) error {
|
||||
// ChannelID (8)
|
||||
// Revocation Hash (20)
|
||||
// Pubkey (32)
|
||||
// ChannelDerivationPoint (33)
|
||||
// CommitmentKey (33)
|
||||
// RevocationKey (33)
|
||||
// CsvDelay (4)
|
||||
// DeliveryPkScript (final delivery)
|
||||
err := readElements(r,
|
||||
&c.ChannelID,
|
||||
&c.RevocationHash,
|
||||
&c.CommitmentKey,
|
||||
&c.ChannelDerivationPoint,
|
||||
&c.CommitmentKey,
|
||||
&c.RevocationKey,
|
||||
&c.CsvDelay,
|
||||
&c.DeliveryPkScript)
|
||||
if err != nil {
|
||||
@ -94,14 +99,16 @@ func (c *SingleFundingResponse) Decode(r io.Reader, pver uint32) error {
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *SingleFundingResponse) Encode(w io.Writer, pver uint32) error {
|
||||
// ChannelID (8)
|
||||
// Revocation Hash (20)
|
||||
// Channel Derivation Point (32)
|
||||
// ChannelDerivationPoint (33)
|
||||
// CommitmentKey (33)
|
||||
// RevocationKey (33)
|
||||
// CsvDelay (4)
|
||||
// DeliveryPkScript (final delivery)
|
||||
err := writeElements(w,
|
||||
c.ChannelID,
|
||||
c.RevocationHash,
|
||||
c.CommitmentKey,
|
||||
c.ChannelDerivationPoint,
|
||||
c.CommitmentKey,
|
||||
c.RevocationKey,
|
||||
c.CsvDelay,
|
||||
c.DeliveryPkScript)
|
||||
if err != nil {
|
||||
@ -123,11 +130,11 @@ func (c *SingleFundingResponse) Command() uint32 {
|
||||
// SingleFundingResponse. This is calculated by summing the max length of all
|
||||
// the fields within a SingleFundingResponse. To enforce a maximum
|
||||
// DeliveryPkScript size, the size of a P2PKH public key script is used.
|
||||
// Therefore, the final breakdown is: 8 + 20 + 33 + 33 + 4 + 25 = 123
|
||||
// Therefore, the final breakdown is: 8 + (33 * 3) + 8 + 25
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *SingleFundingResponse) MaxPayloadLength(uint32) uint32 {
|
||||
return 123
|
||||
return 140
|
||||
}
|
||||
|
||||
// Validate examines each populated field within the SingleFundingResponse for
|
||||
@ -136,11 +143,6 @@ func (c *SingleFundingResponse) MaxPayloadLength(uint32) uint32 {
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *SingleFundingResponse) Validate() error {
|
||||
var zeroHash [20]byte
|
||||
if bytes.Equal(zeroHash[:], c.RevocationHash[:]) {
|
||||
return fmt.Errorf("revocation has must be non-zero")
|
||||
}
|
||||
|
||||
// The channel derivation point must be non-nil, and have an odd
|
||||
// y-coordinate.
|
||||
if c.ChannelDerivationPoint == nil {
|
||||
@ -166,15 +168,25 @@ func (c *SingleFundingResponse) Validate() error {
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (c *SingleFundingResponse) String() string {
|
||||
var serializedPubkey []byte
|
||||
if &c.ChannelDerivationPoint != nil && c.ChannelDerivationPoint.X != nil {
|
||||
serializedPubkey = c.ChannelDerivationPoint.SerializeCompressed()
|
||||
var cdp []byte
|
||||
var ck []byte
|
||||
var rk []byte
|
||||
if &c.ChannelDerivationPoint != nil {
|
||||
cdp = c.ChannelDerivationPoint.SerializeCompressed()
|
||||
}
|
||||
if &c.CommitmentKey != nil {
|
||||
ck = c.CommitmentKey.SerializeCompressed()
|
||||
}
|
||||
if &c.RevocationKey != nil {
|
||||
rk = c.RevocationKey.SerializeCompressed()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\n--- Begin SingleFundingResponse ---\n") +
|
||||
fmt.Sprintf("ChannelID:\t\t\t%d\n", c.ChannelID) +
|
||||
fmt.Sprintf("RevocationHash\t\t\t%x\n", c.RevocationHash) +
|
||||
fmt.Sprintf("ChannelDerivationPoint\t\t\t\t%x\n", serializedPubkey) +
|
||||
fmt.Sprintf("ChannelDerivationPoint\t\t\t\t%x\n", cdp) +
|
||||
fmt.Sprintf("CommitmentKey\t\t\t\t%x\n", ck) +
|
||||
fmt.Sprintf("RevocationKey\t\t\t\t%x\n", rk) +
|
||||
fmt.Sprintf("CsvDelay\t\t%d\n", c.CsvDelay) +
|
||||
fmt.Sprintf("DeliveryPkScript\t\t%x\n", c.DeliveryPkScript) +
|
||||
fmt.Sprintf("--- End SingleFundingResponse ---\n")
|
||||
}
|
||||
|
@ -8,10 +8,8 @@ import (
|
||||
|
||||
func TestSingleFundingResponseWire(t *testing.T) {
|
||||
// First create a new SFR message.
|
||||
var rev [20]byte
|
||||
cdp := pubKey
|
||||
delivery := PkScript(bytes.Repeat([]byte{0x02}, 25))
|
||||
sfr := NewSingleFundingResponse(22, rev, cdp, cdp, 5, delivery)
|
||||
sfr := NewSingleFundingResponse(22, pubKey, pubKey, pubKey, 5, delivery)
|
||||
|
||||
// Next encode the SFR message into an empty bytes buffer.
|
||||
var b bytes.Buffer
|
||||
|
Loading…
Reference in New Issue
Block a user