From 8cc057bbd44f7a43a62ad5cd879ac536bcf470e6 Mon Sep 17 00:00:00 2001 From: Joseph Poon Date: Thu, 31 Dec 2015 02:42:25 -0800 Subject: [PATCH] Cooperative Close --- lnwire/close_complete.go | 86 +++++++++++++++++++++++++++++++++++ lnwire/close_complete_test.go | 34 ++++++++++++++ lnwire/close_request.go | 86 +++++++++++++++++++++++++++++++++++ lnwire/close_request_test.go | 34 ++++++++++++++ lnwire/lnwire_test.go | 2 +- lnwire/message.go | 4 ++ 6 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 lnwire/close_complete.go create mode 100644 lnwire/close_complete_test.go create mode 100644 lnwire/close_request.go create mode 100644 lnwire/close_request_test.go diff --git a/lnwire/close_complete.go b/lnwire/close_complete.go new file mode 100644 index 00000000..998e3c57 --- /dev/null +++ b/lnwire/close_complete.go @@ -0,0 +1,86 @@ +package lnwire + +import ( + "fmt" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/wire" + + "io" +) + +type CloseComplete struct { + ReservationID uint64 + + ResponderCloseSig *btcec.Signature //Requester's Commitment + CloseShaHash *wire.ShaHash //TxID of the Close Tx +} + +func (c *CloseComplete) Decode(r io.Reader, pver uint32) error { + //ReservationID (8) + //ResponderCloseSig (73) + // First byte length then sig + //CloseShaHash (32) + err := readElements(r, + &c.ReservationID, + &c.ResponderCloseSig, + &c.CloseShaHash) + if err != nil { + return err + } + + return nil +} + +//Creates a new CloseComplete +func NewCloseComplete() *CloseComplete { + return &CloseComplete{} +} + +//Serializes the item from the CloseComplete struct +//Writes the data to w +func (c *CloseComplete) Encode(w io.Writer, pver uint32) error { + //ReservationID + //ResponderCloseSig + //CloseShaHash + err := writeElements(w, + c.ReservationID, + c.ResponderCloseSig, + c.CloseShaHash) + if err != nil { + return err + } + + return nil +} + +func (c *CloseComplete) Command() uint32 { + return CmdCloseComplete +} + +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) +func (c *CloseComplete) Validate() error { + //We're good! + return nil +} + +func (c *CloseComplete) String() string { + var serializedSig []byte + var shaString string + if c.ResponderCloseSig != nil && c.ResponderCloseSig.R != 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("ResponderCloseSig:\t%x\n", serializedSig) + + fmt.Sprintf("CloseShaHash:\t\t%s\n", shaString) + + fmt.Sprintf("--- End CloseComplete ---\n") +} diff --git a/lnwire/close_complete_test.go b/lnwire/close_complete_test.go new file mode 100644 index 00000000..5f92f607 --- /dev/null +++ b/lnwire/close_complete_test.go @@ -0,0 +1,34 @@ +package lnwire + +import ( + //"github.com/btcsuite/btcutil" + "testing" +) + +var ( + closeComplete = &CloseComplete{ + ReservationID: uint64(12345678), + ResponderCloseSig: commitSig, + CloseShaHash: shaHash1, + } + closeCompleteSerializedString = "0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1dfe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + closeCompleteSerializedMessage = "0709110b000001360000006f0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1dfe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" +) + +func TestCloseCompleteEncodeDecode(t *testing.T) { + //All of these types being passed are of the message interface type + //Test serialization, runs: message.Encode(b, 0) + //Returns bytes + //Compares the expected serialized string from the original + s := SerializeTest(t, closeComplete, closeCompleteSerializedString, filename) + + //Test deserialization, runs: message.Decode(s, 0) + //Makes sure the deserialized struct is the same as the original + newMessage := NewCloseComplete() + DeserializeTest(t, s, newMessage, closeComplete) + + //Test message using Message interface + //Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) + //Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) + MessageSerializeDeserializeTest(t, closeComplete, closeCompleteSerializedMessage) +} diff --git a/lnwire/close_request.go b/lnwire/close_request.go new file mode 100644 index 00000000..84dd5ad3 --- /dev/null +++ b/lnwire/close_request.go @@ -0,0 +1,86 @@ +package lnwire + +import ( + "fmt" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcutil" + + "io" +) + +type CloseRequest struct { + ReservationID uint64 + + RequesterCloseSig *btcec.Signature //Requester's Commitment + Fee btcutil.Amount +} + +func (c *CloseRequest) Decode(r io.Reader, pver uint32) error { + //ReservationID (8) + //RequesterCloseSig (73) + // First byte length then sig + //Fee (8) + err := readElements(r, + &c.ReservationID, + &c.RequesterCloseSig, + &c.Fee) + if err != nil { + return err + } + + return nil +} + +//Creates a new CloseRequest +func NewCloseRequest() *CloseRequest { + return &CloseRequest{} +} + +//Serializes the item from the CloseRequest struct +//Writes the data to w +func (c *CloseRequest) Encode(w io.Writer, pver uint32) error { + //ReservationID + //RequesterCloseSig + //Fee + err := writeElements(w, + c.ReservationID, + c.RequesterCloseSig, + c.Fee) + if err != nil { + return err + } + + return nil +} + +func (c *CloseRequest) Command() uint32 { + return CmdCloseRequest +} + +func (c *CloseRequest) MaxPayloadLength(uint32) uint32 { + //8 + 73 + 8 + return 89 +} + +//Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts) +func (c *CloseRequest) Validate() error { + //Fee must be greater than 0 + if c.Fee < 0 { + return fmt.Errorf("Fee must be greater than zero.") + } + //We're good! + return nil +} + +func (c *CloseRequest) String() string { + var serializedSig []byte + if c.RequesterCloseSig != nil && c.RequesterCloseSig.R != nil { + serializedSig = c.RequesterCloseSig.Serialize() + } + + return fmt.Sprintf("\n--- Begin CloseRequest ---\n") + + fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) + + fmt.Sprintf("CloseSig\t\t%x\n", serializedSig) + + fmt.Sprintf("Fee:\t\t\t%d\n", c.Fee) + + fmt.Sprintf("--- End CloseRequest ---\n") +} diff --git a/lnwire/close_request_test.go b/lnwire/close_request_test.go new file mode 100644 index 00000000..42356143 --- /dev/null +++ b/lnwire/close_request_test.go @@ -0,0 +1,34 @@ +package lnwire + +import ( + "github.com/btcsuite/btcutil" + "testing" +) + +var ( + closeRequest = &CloseRequest{ + ReservationID: uint64(12345678), + RequesterCloseSig: commitSig, + Fee: btcutil.Amount(12345), + } + closeRequestSerializedString = "0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df0000000000003039" + closeRequestSerializedMessage = "0709110b0000012c000000570000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df0000000000003039" +) + +func TestCloseRequestEncodeDecode(t *testing.T) { + //All of these types being passed are of the message interface type + //Test serialization, runs: message.Encode(b, 0) + //Returns bytes + //Compares the expected serialized string from the original + s := SerializeTest(t, closeRequest, closeRequestSerializedString, filename) + + //Test deserialization, runs: message.Decode(s, 0) + //Makes sure the deserialized struct is the same as the original + newMessage := NewCloseRequest() + DeserializeTest(t, s, newMessage, closeRequest) + + //Test message using Message interface + //Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) + //Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) + MessageSerializeDeserializeTest(t, closeRequest, closeRequestSerializedMessage) +} diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index 19ec4e0f..13221161 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -85,7 +85,7 @@ func SerializeTest(t *testing.T, message Message, expectedString string, filenam if err != nil { t.Errorf(err.Error()) } else { - t.Logf("Encoded Funding Request: %x\n", b.Bytes()) + t.Logf("Encoded Bytes: %x\n", b.Bytes()) //Check if we serialized correctly if expectedString != hex.EncodeToString(b.Bytes()) { t.Error("Serialization does not match expected") diff --git a/lnwire/message.go b/lnwire/message.go index e12b1522..1dd6dd1e 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -49,6 +49,10 @@ func makeEmptyMessage(command uint32) (Message, error) { msg = &FundingSignAccept{} case CmdFundingSignComplete: msg = &FundingSignComplete{} + case CmdCloseRequest: + msg = &CloseRequest{} + case CmdCloseComplete: + msg = &CloseComplete{} default: return nil, fmt.Errorf("unhandled command [%d]", command) }