FundReq/FundResp update / Refactor tests

* Added field
* Renamed FundingAmount and ReserveAmount to specify in FundingRequest
  and FundingResponse that it is for RequesterFundingAmount or
  ResponderFundingAmount
* Added PaymentAmount field to FundingRequest
* Added MinDepth field to FundingRequest and FundingResponse
* Fixed .Serialize() to show inputs/etc. only if there are fields
  available (prevents trying to dereference nil value)
* Add a bunch of Validate() conditions
* MASSIVE REFACTOR of tests (removed tons of redundancy)
This commit is contained in:
Joseph Poon 2015-12-30 22:28:14 -08:00 committed by Olaoluwa Osuntokun
parent cb32ab1fb9
commit 0d4c78e90d
10 changed files with 417 additions and 524 deletions

@ -39,3 +39,24 @@ Funding Transaction. This is provided as a courtesy, it cannot be relied upon
with non-cooperative channel counterparties and the Funding Transaction can be with non-cooperative channel counterparties and the Funding Transaction can be
braodcast without this message being received by the requester. After the braodcast without this message being received by the requester. After the
necessary number of confirmations, Lightning Network transactions can proceed. necessary number of confirmations, Lightning Network transactions can proceed.
Cooperative Channel Close
=========================
This is when either party want to close out a channel with the current balance.
Requires the cooperation of both parites for this type. In the event of
non-cooperation, either party may broadcast the most recent Commitment
Transaction.
Close Channel
-------------
One party unilaterally sends their sig to the other party. No further channel
updates are possible. In the future, we might include HTLCs in the outputs, but
for now, we're assuming *all* HTLCs are cleared out.
Close Channel Complete
----------------------
Returns the Txid as a courtesy. The counterparty may not send this if they're
being non-cooperative.

@ -11,9 +11,19 @@ import (
type FundingRequest struct { type FundingRequest struct {
ChannelType uint8 ChannelType uint8
FundingAmount btcutil.Amount RequesterFundingAmount btcutil.Amount
ReserveAmount btcutil.Amount RequesterReserveAmount btcutil.Amount
MinFeePerKb btcutil.Amount MinFeePerKb btcutil.Amount
//The funding requester can request payment
//This wallet only allows positive values,
//which is a payment to the responder
//(This can be used to fund the Reserve)
//If the responder disagrees, then the funding request fails
PaymentAmount btcutil.Amount
//Minimum number of confirmations to validate transaction
MinDepth uint32
//Should double-check the total funding later //Should double-check the total funding later
MinTotalFundingAmount btcutil.Amount MinTotalFundingAmount btcutil.Amount
@ -36,15 +46,17 @@ type FundingRequest struct {
} }
func (c *FundingRequest) Decode(r io.Reader, pver uint32) error { func (c *FundingRequest) Decode(r io.Reader, pver uint32) error {
//Channel Type (0/1) //Channel Type (1)
//Funding Amount (1/8) //Funding Amount (8)
//Channel Minimum Capacity (9/8) //Channel Minimum Capacity (8)
//Revocation Hash (17/20) //Revocation Hash (20)
//Commitment Pubkey (37/32) //Commitment Pubkey (32)
//Reserve Amount (69/8) //Reserve Amount (8)
//Minimum Transaction Fee Per Kb (77/8) //Minimum Transaction Fee Per Kb (8)
//LockTime (85/4) //PaymentAmount (8)
//FeePayer (89/1) //MinDepth (4)
//LockTime (4)
//FeePayer (1)
//DeliveryPkScript (final delivery) //DeliveryPkScript (final delivery)
// First byte length then pkscript // First byte length then pkscript
//ChangePkScript (change for extra from inputs) //ChangePkScript (change for extra from inputs)
@ -54,12 +66,14 @@ func (c *FundingRequest) Decode(r io.Reader, pver uint32) error {
// For each input, it's 32bytes txin & 4bytes index // For each input, it's 32bytes txin & 4bytes index
err := readElements(r, false, err := readElements(r, false,
&c.ChannelType, &c.ChannelType,
&c.FundingAmount, &c.RequesterFundingAmount,
&c.MinTotalFundingAmount, &c.MinTotalFundingAmount,
&c.RevocationHash, &c.RevocationHash,
&c.Pubkey, &c.Pubkey,
&c.ReserveAmount, &c.RequesterReserveAmount,
&c.MinFeePerKb, &c.MinFeePerKb,
&c.PaymentAmount,
&c.MinDepth,
&c.LockTime, &c.LockTime,
&c.FeePayer, &c.FeePayer,
&c.DeliveryPkScript, &c.DeliveryPkScript,
@ -94,12 +108,14 @@ func (c *FundingRequest) Encode(w io.Writer, pver uint32) error {
//Inputs: Append the actual Txins //Inputs: Append the actual Txins
err := writeElements(w, false, err := writeElements(w, false,
c.ChannelType, c.ChannelType,
c.FundingAmount, c.RequesterFundingAmount,
c.MinTotalFundingAmount, c.MinTotalFundingAmount,
c.RevocationHash, c.RevocationHash,
c.Pubkey, c.Pubkey,
c.ReserveAmount, c.RequesterReserveAmount,
c.MinFeePerKb, c.MinFeePerKb,
c.PaymentAmount,
c.MinDepth,
c.LockTime, c.LockTime,
c.FeePayer, c.FeePayer,
c.DeliveryPkScript, c.DeliveryPkScript,
@ -117,8 +133,8 @@ func (c *FundingRequest) Command() uint32 {
} }
func (c *FundingRequest) MaxPayloadLength(uint32) uint32 { func (c *FundingRequest) MaxPayloadLength(uint32) uint32 {
//90 (base size) + 26 (pkscript) + 26 (pkscript) + 1 (numTxes) + 127*36(127 inputs * sha256+idx) //102 (base size) + 26 (pkscript) + 26 (pkscript) + 1 (numTxes) + 127*36(127 inputs * sha256+idx)
return 4715 return 4727
} }
//Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts) //Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
@ -126,12 +142,12 @@ func (c *FundingRequest) Validate() error {
var err error var err error
//No negative values //No negative values
if c.FundingAmount < 0 { if c.RequesterFundingAmount < 0 {
return fmt.Errorf("FundingAmount cannot be negative") return fmt.Errorf("RequesterFundingAmount cannot be negative")
} }
if c.ReserveAmount < 0 { if c.RequesterReserveAmount < 0 {
return fmt.Errorf("ReserveAmount cannot be negative") return fmt.Errorf("RequesterReserveAmount cannot be negative")
} }
if c.MinFeePerKb < 0 { if c.MinFeePerKb < 0 {
@ -141,6 +157,28 @@ func (c *FundingRequest) Validate() error {
return fmt.Errorf("MinTotalFundingAmount cannot be negative") return fmt.Errorf("MinTotalFundingAmount cannot be negative")
} }
//Validation of what makes sense...
if c.MinTotalFundingAmount < c.RequesterFundingAmount {
return fmt.Errorf("Requester's minimum too low.")
}
if c.RequesterFundingAmount < c.RequesterReserveAmount {
return fmt.Errorf("Reserve must be below Funding Amount")
}
//This wallet only allows payment from the requester to responder
if c.PaymentAmount < 0 {
return fmt.Errorf("This wallet requieres payment to be greater than zero.")
}
//The payment must be below our own contribution (less reserve kept for ourselves
if c.PaymentAmount > c.RequesterFundingAmount-c.RequesterReserveAmount {
return fmt.Errorf("Payment too large")
}
//Make sure there's not more than 127 inputs
if len(c.Inputs) > 127 {
return fmt.Errorf("Too many inputs")
}
//DeliveryPkScript is either P2SH or P2PKH //DeliveryPkScript is either P2SH or P2PKH
err = ValidatePkScript(c.DeliveryPkScript) err = ValidatePkScript(c.DeliveryPkScript)
if err != nil { if err != nil {
@ -161,20 +199,24 @@ func (c *FundingRequest) String() string {
var inputs string var inputs string
for i, in := range c.Inputs { for i, in := range c.Inputs {
inputs += fmt.Sprintf("\n Slice\t%d\n", i) inputs += fmt.Sprintf("\n Slice\t%d\n", i)
inputs += fmt.Sprintf("\tHash\t%s\n", in.PreviousOutPoint.Hash) if &in != nil {
inputs += fmt.Sprintf("\tIndex\t%d\n", in.PreviousOutPoint.Index) inputs += fmt.Sprintf("\tHash\t%s\n", in.PreviousOutPoint.Hash)
inputs += fmt.Sprintf("\tIndex\t%d\n", in.PreviousOutPoint.Index)
}
} }
return fmt.Sprintf("\n--- Begin FundingRequest ---\n") + return fmt.Sprintf("\n--- Begin FundingRequest ---\n") +
fmt.Sprintf("ChannelType:\t\t%x\n", c.ChannelType) + fmt.Sprintf("ChannelType:\t\t\t%x\n", c.ChannelType) +
fmt.Sprintf("FundingAmount:\t\t%s\n", c.FundingAmount.String()) + fmt.Sprintf("RequesterFundingAmount:\t\t%s\n", c.RequesterFundingAmount.String()) +
fmt.Sprintf("ReserveAmount:\t\t%s\n", c.ReserveAmount.String()) + fmt.Sprintf("RequesterReserveAmount:\t\t%s\n", c.RequesterReserveAmount.String()) +
fmt.Sprintf("MinFeePerKb:\t\t%s\n", c.MinFeePerKb.String()) + fmt.Sprintf("MinFeePerKb:\t\t\t%s\n", c.MinFeePerKb.String()) +
fmt.Sprintf("MinTotalFundingAmount\t%s\n", c.MinTotalFundingAmount.String()) + fmt.Sprintf("PaymentAmount:\t\t\t%s\n", c.PaymentAmount.String()) +
fmt.Sprintf("LockTime\t\t%d\n", c.LockTime) + fmt.Sprintf("MinDepth:\t\t\t%d\n", c.MinDepth) +
fmt.Sprintf("FeePayer\t\t%x\n", c.FeePayer) + fmt.Sprintf("MinTotalFundingAmount\t\t%s\n", c.MinTotalFundingAmount.String()) +
fmt.Sprintf("RevocationHash\t\t%x\n", c.RevocationHash) + fmt.Sprintf("LockTime\t\t\t%d\n", c.LockTime) +
fmt.Sprintf("Pubkey\t\t\t%x\n", c.Pubkey.SerializeCompressed()) + fmt.Sprintf("FeePayer\t\t\t%x\n", c.FeePayer) +
fmt.Sprintf("DeliveryPkScript\t%x\n", c.DeliveryPkScript) + fmt.Sprintf("RevocationHash\t\t\t%x\n", c.RevocationHash) +
fmt.Sprintf("Pubkey\t\t\t\t%x\n", c.Pubkey.SerializeCompressed()) +
fmt.Sprintf("DeliveryPkScript\t\t%x\n", c.DeliveryPkScript) +
fmt.Sprintf("Inputs:") + fmt.Sprintf("Inputs:") +
inputs + inputs +
fmt.Sprintf("--- End FundingRequest ---\n") fmt.Sprintf("--- End FundingRequest ---\n")

@ -1,135 +1,49 @@
package lnwire package lnwire
import ( import (
"bytes"
"encoding/hex"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
// "io"
"io/ioutil"
"reflect"
"testing" "testing"
) )
var ( var (
//For debugging, writes to /dev/shm/ //Need to do this here
//Maybe in the future do it if you do "go test -v" _ = copy(revocationHash[:], revocationHashBytes)
WRITE_FILE = false
FILENAME = "/dev/shm/fundingRequest.raw"
//preimage: 9a2cbd088763db88dd8ba79e5726daa6aba4aa7e
//echo -n | openssl sha256 | openssl ripemd160 | openssl sha256 | openssl ripemd160
revocationHashBytes, _ = hex.DecodeString("4132b6b48371f7b022a16eacb9b2b0ebee134d41")
revocationHash [20]byte
_ = copy(revocationHash[:], revocationHashBytes)
//privkey: 9fa1d55217f57019a3c37f49465896b15836f54cb8ef6963870a52926420a2dd
pubKeyBytes, _ = hex.DecodeString("02f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee")
pubKey, _ = btcec.ParsePubKey(pubKeyBytes, btcec.S256())
// Delivery PkScript
//Privkey: f2c00ead9cbcfec63098dc0a5f152c0165aff40a2ab92feb4e24869a284c32a7
//PKhash: n2fkWVphUzw3zSigzPsv9GuDyg9mohzKpz
deliveryPkScript, _ = hex.DecodeString("76a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac")
// Change PkScript
//Privkey: 5b18f5049efd9d3aff1fb9a06506c0b809fb71562b6ecd02f6c5b3ab298f3b0f
//PKhash: miky84cHvLuk6jcT6GsSbgHR8d7eZCu9Qc
changePkScript, _ = hex.DecodeString("76a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac")
//echo -n | openssl sha256
//This stuff gets reversed!!!
shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
shaHash1, _ = wire.NewShaHash(shaHash1Bytes)
outpoint1 = wire.NewOutPoint(shaHash1, 0)
//echo | openssl sha256
//This stuff gets reversed!!!
shaHash2Bytes, _ = hex.DecodeString("01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b")
shaHash2, _ = wire.NewShaHash(shaHash2Bytes)
outpoint2 = wire.NewOutPoint(shaHash2, 1)
//create inputs from outpoint1 and outpoint2
inputs = []*wire.TxIn{wire.NewTxIn(outpoint1, nil), wire.NewTxIn(outpoint2, nil)}
//funding request //funding request
fundingRequest = &FundingRequest{ fundingRequest = &FundingRequest{
ChannelType: uint8(0), ChannelType: uint8(0),
FundingAmount: btcutil.Amount(100000000), RequesterFundingAmount: btcutil.Amount(100000000),
ReserveAmount: btcutil.Amount(131072), RequesterReserveAmount: btcutil.Amount(131072),
MinFeePerKb: btcutil.Amount(20000), MinFeePerKb: btcutil.Amount(20000),
MinTotalFundingAmount: btcutil.Amount(150000000), MinTotalFundingAmount: btcutil.Amount(150000000),
LockTime: uint32(4320), //30 block-days LockTime: uint32(4320), //30 block-days
FeePayer: uint8(0), FeePayer: uint8(0),
RevocationHash: revocationHash, PaymentAmount: btcutil.Amount(1234567),
Pubkey: pubKey, MinDepth: uint32(6),
DeliveryPkScript: deliveryPkScript, RevocationHash: revocationHash,
ChangePkScript: changePkScript, Pubkey: pubKey,
Inputs: inputs, DeliveryPkScript: deliveryPkScript,
ChangePkScript: changePkScript,
Inputs: inputs,
} }
serializedString = "000000000005f5e1000000000008f0d1804132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e20000010e0001976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001" fundingRequestSerializedString = "000000000005f5e1000000000008f0d1804132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e20000000000012d68700000006000010e0001976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001"
serializedMessage = "0709110b000000c8000000d8000000000005f5e1000000000008f0d1804132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e20000010e0001976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001" fundingRequestSerializedMessage = "0709110b000000c8000000e4000000000005f5e1000000000008f0d1804132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e20000000000012d68700000006000010e0001976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001"
) )
func TestFundingRequestEncodeDecode(t *testing.T) { func TestFundingRequestEncodeDecode(t *testing.T) {
//Test serialization //All of these types being passed are of the message interface type
b := new(bytes.Buffer) //Test serialization, runs: message.Encode(b, 0)
err := fundingRequest.Encode(b, 0) //Returns bytes
if err != nil { //Compares the expected serialized string from the original
t.Error("Serialization error") s := SerializeTest(t, fundingRequest, fundingRequestSerializedString, filename)
t.Error(err.Error())
} else {
t.Logf("Encoded Funding Request: %x\n", b.Bytes())
//Check if we serialized correctly
if serializedString != hex.EncodeToString(b.Bytes()) {
t.Error("Serialization does not match expected")
}
//So I can do: hexdump -C /dev/shm/fundingRequest.raw //Test deserialization, runs: message.Decode(s, 0)
if WRITE_FILE { //Makes sure the deserialized struct is the same as the original
err = ioutil.WriteFile(FILENAME, b.Bytes(), 0644) newMessage := NewFundingRequest()
if err != nil { DeserializeTest(t, s, newMessage, fundingRequest)
t.Error("File write error")
t.Error(err.Error())
}
}
}
//Test deserialization
//Make a new buffer just to be clean
c := new(bytes.Buffer)
c.Write(b.Bytes())
newFunding := NewFundingRequest()
err = newFunding.Decode(c, 0)
if err != nil {
t.Error("Decoding Error")
t.Error(err.Error())
} else {
if !reflect.DeepEqual(newFunding, fundingRequest) {
t.Error("Decoding does not match!")
}
//Show the struct
t.Log(newFunding.String())
}
//Test message using Message interface //Test message using Message interface
//Serialize/Encode //Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
b = new(bytes.Buffer) //Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
_, err = WriteMessage(b, fundingRequest, uint32(1), wire.TestNet3) MessageSerializeDeserializeTest(t, fundingRequest, fundingRequestSerializedMessage)
t.Logf("%x\n", b.Bytes())
if hex.EncodeToString(b.Bytes()) != serializedMessage {
t.Error("Message encoding error")
}
//Deserialize/Decode
c = new(bytes.Buffer)
c.Write(b.Bytes())
_, msg, _, err := ReadMessage(c, uint32(1), wire.TestNet3)
if err != nil {
t.Errorf(err.Error())
} else {
if !reflect.DeepEqual(msg, fundingRequest) {
t.Error("Message decoding does not match!")
}
t.Logf(msg.String())
}
} }

@ -13,9 +13,12 @@ type FundingResponse struct {
ReservationID uint64 ReservationID uint64
FundingAmount btcutil.Amount ResponderFundingAmount btcutil.Amount //Responder's funding amount
ReserveAmount btcutil.Amount ResponderReserveAmount btcutil.Amount //Responder's reserve amount
MinFeePerKb btcutil.Amount //Lock-in min fee MinFeePerKb btcutil.Amount //Lock-in min fee
//Minimum depth
MinDepth uint32
//CLTV/CSV lock-time to use //CLTV/CSV lock-time to use
LockTime uint32 LockTime uint32
@ -36,15 +39,16 @@ type FundingResponse struct {
} }
func (c *FundingResponse) Decode(r io.Reader, pver uint32) error { func (c *FundingResponse) Decode(r io.Reader, pver uint32) error {
//ReservationID (0/8) //ReservationID (8)
//Channel Type (8/1) //Channel Type (1)
//Funding Amount (9/8) //Funding Amount (8)
//Revocation Hash (29/20) //Revocation Hash (20)
//Commitment Pubkey (61/32) //Commitment Pubkey (32)
//Reserve Amount (69/8) //Reserve Amount (8)
//Minimum Transaction Fee Per Kb (77/8) //Minimum Transaction Fee Per Kb (8)
//LockTime (81/4) //MinDepth (4)
//FeePayer (82/1) //LockTime (4)
//FeePayer (1)
//DeliveryPkScript (final delivery) //DeliveryPkScript (final delivery)
// First byte length then pkscript // First byte length then pkscript
//ChangePkScript (change for extra from inputs) //ChangePkScript (change for extra from inputs)
@ -57,11 +61,12 @@ func (c *FundingResponse) Decode(r io.Reader, pver uint32) error {
err := readElements(r, false, err := readElements(r, false,
&c.ReservationID, &c.ReservationID,
&c.ChannelType, &c.ChannelType,
&c.FundingAmount, &c.ResponderFundingAmount,
&c.RevocationHash, &c.RevocationHash,
&c.Pubkey, &c.Pubkey,
&c.ReserveAmount, &c.ResponderReserveAmount,
&c.MinFeePerKb, &c.MinFeePerKb,
&c.MinDepth,
&c.LockTime, &c.LockTime,
&c.FeePayer, &c.FeePayer,
&c.DeliveryPkScript, &c.DeliveryPkScript,
@ -99,11 +104,12 @@ func (c *FundingResponse) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, false, err := writeElements(w, false,
c.ReservationID, c.ReservationID,
c.ChannelType, c.ChannelType,
c.FundingAmount, c.ResponderFundingAmount,
c.RevocationHash, c.RevocationHash,
c.Pubkey, c.Pubkey,
c.ReserveAmount, c.ResponderReserveAmount,
c.MinFeePerKb, c.MinFeePerKb,
c.MinDepth,
c.LockTime, c.LockTime,
c.FeePayer, c.FeePayer,
c.DeliveryPkScript, c.DeliveryPkScript,
@ -122,8 +128,8 @@ func (c *FundingResponse) Command() uint32 {
} }
func (c *FundingResponse) MaxPayloadLength(uint32) uint32 { func (c *FundingResponse) MaxPayloadLength(uint32) uint32 {
//82 (base size) + 26 (pkscript) + 26 (pkscript) + 74sig + 1 (numTxes) + 127*36(127 inputs * sha256+idx) //86 (base size) + 26 (pkscript) + 26 (pkscript) + 74sig + 1 (numTxes) + 127*36(127 inputs * sha256+idx)
return 4781 return 4785
} }
//Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts) //Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
@ -131,18 +137,28 @@ func (c *FundingResponse) Validate() error {
var err error var err error
//No negative values //No negative values
if c.FundingAmount < 0 { if c.ResponderFundingAmount < 0 {
return fmt.Errorf("FundingAmount cannot be negative") return fmt.Errorf("ResponderFundingAmount cannot be negative")
} }
if c.ReserveAmount < 0 { if c.ResponderReserveAmount < 0 {
return fmt.Errorf("ReserveAmount cannot be negative") return fmt.Errorf("ResponderReserveAmount cannot be negative")
} }
if c.MinFeePerKb < 0 { if c.MinFeePerKb < 0 {
return fmt.Errorf("MinFeePerKb cannot be negative") return fmt.Errorf("MinFeePerKb cannot be negative")
} }
//Validation of what makes sense...
if c.ResponderFundingAmount < c.ResponderReserveAmount {
return fmt.Errorf("Reserve must be below Funding Amount")
}
//Make sure there's not more than 127 inputs
if len(c.Inputs) > 127 {
return fmt.Errorf("Too many inputs")
}
//Delivery PkScript is either P2SH or P2PKH //Delivery PkScript is either P2SH or P2PKH
err = ValidatePkScript(c.DeliveryPkScript) err = ValidatePkScript(c.DeliveryPkScript)
if err != nil { if err != nil {
@ -163,22 +179,26 @@ func (c *FundingResponse) String() string {
var inputs string var inputs string
for i, in := range c.Inputs { for i, in := range c.Inputs {
inputs += fmt.Sprintf("\n Slice\t%d\n", i) inputs += fmt.Sprintf("\n Slice\t%d\n", i)
inputs += fmt.Sprintf("\tHash\t%s\n", in.PreviousOutPoint.Hash) if &in != nil {
inputs += fmt.Sprintf("\tIndex\t%d\n", in.PreviousOutPoint.Index)
inputs += fmt.Sprintf("\tHash\t%s\n", in.PreviousOutPoint.Hash)
inputs += fmt.Sprintf("\tIndex\t%d\n", in.PreviousOutPoint.Index)
}
} }
return fmt.Sprintf("\n--- Begin FundingResponse ---\n") + return fmt.Sprintf("\n--- Begin FundingResponse ---\n") +
fmt.Sprintf("ChannelType:\t\t%x\n", c.ChannelType) + fmt.Sprintf("ChannelType:\t\t\t%x\n", c.ChannelType) +
fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) + fmt.Sprintf("ReservationID:\t\t\t%d\n", c.ReservationID) +
fmt.Sprintf("FundingAmount:\t\t%s\n", c.FundingAmount.String()) + fmt.Sprintf("ResponderFundingAmount:\t\t%s\n", c.ResponderFundingAmount.String()) +
fmt.Sprintf("ReserveAmount:\t\t%s\n", c.ReserveAmount.String()) + fmt.Sprintf("ResponderReserveAmount:\t\t%s\n", c.ResponderReserveAmount.String()) +
fmt.Sprintf("MinFeePerKb:\t\t%s\n", c.MinFeePerKb.String()) + fmt.Sprintf("MinFeePerKb:\t\t\t%s\n", c.MinFeePerKb.String()) +
fmt.Sprintf("LockTime\t\t%d\n", c.LockTime) + fmt.Sprintf("MinDepth:\t\t\t%d\n", c.MinDepth) +
fmt.Sprintf("FeePayer\t\t%x\n", c.FeePayer) + fmt.Sprintf("LockTime\t\t\t%d\n", c.LockTime) +
fmt.Sprintf("RevocationHash\t\t%x\n", c.RevocationHash) + fmt.Sprintf("FeePayer\t\t\t%x\n", c.FeePayer) +
fmt.Sprintf("Pubkey\t\t\t%x\n", c.Pubkey.SerializeCompressed()) + fmt.Sprintf("RevocationHash\t\t\t%x\n", c.RevocationHash) +
fmt.Sprintf("CommitSig\t\t%x\n", c.CommitSig.Serialize()) + fmt.Sprintf("Pubkey\t\t\t\t%x\n", c.Pubkey.SerializeCompressed()) +
fmt.Sprintf("DeliveryPkScript\t%x\n", c.DeliveryPkScript) + fmt.Sprintf("CommitSig\t\t\t%x\n", c.CommitSig.Serialize()) +
fmt.Sprintf("ChangePkScript\t%x\n", c.ChangePkScript) + fmt.Sprintf("DeliveryPkScript\t\t%x\n", c.DeliveryPkScript) +
fmt.Sprintf("ChangePkScript\t\t%x\n", c.ChangePkScript) +
fmt.Sprintf("Inputs:") + fmt.Sprintf("Inputs:") +
inputs + inputs +
fmt.Sprintf("--- End FundingResponse ---\n") fmt.Sprintf("--- End FundingResponse ---\n")

@ -1,143 +1,49 @@
package lnwire package lnwire
import ( import (
"bytes"
"encoding/hex"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
// "io"
"io/ioutil"
"reflect"
"testing" "testing"
) )
var (
//Need to do this here
_ = copy(revocationHash[:], revocationHashBytes)
//funding response
fundingResponse = &FundingResponse{
ChannelType: uint8(1),
ReservationID: uint64(12345678),
ResponderFundingAmount: btcutil.Amount(100000000),
ResponderReserveAmount: btcutil.Amount(131072),
MinFeePerKb: btcutil.Amount(20000),
MinDepth: uint32(6),
LockTime: uint32(4320), //30 block-days
FeePayer: uint8(1),
RevocationHash: revocationHash,
Pubkey: pubKey,
CommitSig: commitSig,
DeliveryPkScript: deliveryPkScript,
ChangePkScript: changePkScript,
Inputs: inputs,
}
fundingResponseSerializedString = "0000000000bc614e010000000005f5e1004132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e2000000006000010e0011976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001"
fundingResponseSerializedMessage = "0709110b000000d2000001230000000000bc614e010000000005f5e1004132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e2000000006000010e0011976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001"
)
func TestFundingResponseEncodeDecode(t *testing.T) { func TestFundingResponseEncodeDecode(t *testing.T) {
var ( //All of these types being passed are of the message interface type
//For debugging, writes to /dev/shm/ //Test serialization, runs: message.Encode(b, 0)
//Maybe in the future do it if you do "go test -v" //Returns bytes
WRITE_FILE = false //Compares the expected serialized string from the original
FILENAME = "/dev/shm/fundingResponse.raw" s := SerializeTest(t, fundingResponse, fundingResponseSerializedString, filename)
//preimage: 9a2cbd088763db88dd8ba79e5726daa6aba4aa7e //Test deserialization, runs: message.Decode(s, 0)
//echo -n | openssl sha256 | openssl ripemd160 | openssl sha256 | openssl ripemd160 //Makes sure the deserialized struct is the same as the original
revocationHashBytes, _ = hex.DecodeString("4132b6b48371f7b022a16eacb9b2b0ebee134d41") newMessage := NewFundingResponse()
revocationHash [20]byte DeserializeTest(t, s, newMessage, fundingResponse)
_ = copy(revocationHash[:], revocationHashBytes)
privKeyBytes, _ = hex.DecodeString("9fa1d55217f57019a3c37f49465896b15836f54cb8ef6963870a52926420a2dd")
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
//pubKeyBytes, _ = hex.DecodeString("02f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee")
//pubKey, _ = btcec.ParsePubKey(pubKeyBytes, btcec.S256())
// Delivery PkScript
//Privkey: f2c00ead9cbcfec63098dc0a5f152c0165aff40a2ab92feb4e24869a284c32a7
//PKhash: n2fkWVphUzw3zSigzPsv9GuDyg9mohzKpz
deliveryPkScript, _ = hex.DecodeString("76a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac")
// Change PkScript
//Privkey: 5b18f5049efd9d3aff1fb9a06506c0b809fb71562b6ecd02f6c5b3ab298f3b0f
//PKhash: miky84cHvLuk6jcT6GsSbgHR8d7eZCu9Qc
changePkScript, _ = hex.DecodeString("76a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac")
//echo -n | openssl sha256
//This stuff gets reversed!!!
shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
shaHash1, _ = wire.NewShaHash(shaHash1Bytes)
outpoint1 = wire.NewOutPoint(shaHash1, 0)
//echo | openssl sha256
//This stuff gets reversed!!!
shaHash2Bytes, _ = hex.DecodeString("01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b")
shaHash2, _ = wire.NewShaHash(shaHash2Bytes)
outpoint2 = wire.NewOutPoint(shaHash2, 1)
//create inputs from outpoint1 and outpoint2
inputs = []*wire.TxIn{wire.NewTxIn(outpoint1, nil), wire.NewTxIn(outpoint2, nil)}
//Commitment Signature
tx = wire.NewMsgTx()
emptybytes = new([]byte)
sigStr, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, privKey)
commitSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
//funding response
fundingResponse = &FundingResponse{
ChannelType: uint8(1),
ReservationID: uint64(12345678),
FundingAmount: btcutil.Amount(100000000),
ReserveAmount: btcutil.Amount(131072),
MinFeePerKb: btcutil.Amount(20000),
LockTime: uint32(4320), //30 block-days
FeePayer: uint8(1),
RevocationHash: revocationHash,
Pubkey: pubKey,
CommitSig: commitSig,
DeliveryPkScript: deliveryPkScript,
ChangePkScript: changePkScript,
Inputs: inputs,
}
serializedString = "0000000000bc614e010000000005f5e1004132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e20000010e0011976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001"
serializedMessage = "0709110b000000d20000011f0000000000bc614e010000000005f5e1004132b6b48371f7b022a16eacb9b2b0ebee134d4102f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee00000000000200000000000000004e20000010e0011976a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac1976a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8550000000001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b00000001"
)
//Test serialization
b := new(bytes.Buffer)
err := fundingResponse.Encode(b, 0)
if err != nil {
t.Error("Serialization error")
t.Error(err.Error())
} else {
t.Logf("Encoded Funding Response: %x\n", b.Bytes())
//Check if we serialized correctly
if serializedString != hex.EncodeToString(b.Bytes()) {
t.Error("Serialization does not match expected")
}
//So I can do: hexdump -C /dev/shm/fundingResponse.raw
if WRITE_FILE {
err = ioutil.WriteFile(FILENAME, b.Bytes(), 0644)
if err != nil {
t.Error("File write error")
t.Error(err.Error())
}
}
}
//Test deserialization
//Make a new buffer just to be clean
c := new(bytes.Buffer)
c.Write(b.Bytes())
newFunding := NewFundingResponse()
err = newFunding.Decode(c, 0)
if err != nil {
t.Error("Decoding Error")
t.Error(err.Error())
} else {
if !reflect.DeepEqual(newFunding, fundingResponse) {
t.Error("Decoding does not match!")
}
//Show the struct
t.Log(newFunding.String())
}
//Test message using Message interface //Test message using Message interface
//Serialize/Encode //Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
b = new(bytes.Buffer) //Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
_, err = WriteMessage(b, fundingResponse, uint32(1), wire.TestNet3) MessageSerializeDeserializeTest(t, fundingResponse, fundingResponseSerializedMessage)
t.Logf("%x\n", b.Bytes())
if hex.EncodeToString(b.Bytes()) != serializedMessage {
t.Error("Message encoding error")
}
//Deserialize/Decode
c = new(bytes.Buffer)
c.Write(b.Bytes())
_, msg, _, err := ReadMessage(c, uint32(1), wire.TestNet3)
if err != nil {
t.Errorf(err.Error())
} else {
if !reflect.DeepEqual(msg, fundingResponse) {
t.Error("Message decoding does not match!")
}
t.Logf(msg.String())
}
} }

@ -73,7 +73,9 @@ func (c *FundingSignAccept) String() string {
var sigs string var sigs string
for i, in := range *c.FundingTXSigs { for i, in := range *c.FundingTXSigs {
sigs += fmt.Sprintf("\n Slice\t%d\n", i) sigs += fmt.Sprintf("\n Slice\t%d\n", i)
sigs += fmt.Sprintf("\tSig\t%x\n", in.Serialize()) if &in != nil {
sigs += fmt.Sprintf("\tSig\t%x\n", in.Serialize())
}
} }
return fmt.Sprintf("\n--- Begin FundingSignAccept ---\n") + return fmt.Sprintf("\n--- Begin FundingSignAccept ---\n") +
fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) + fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) +

@ -1,115 +1,34 @@
package lnwire package lnwire
import ( import (
"bytes"
"encoding/hex"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
// "io"
"io/ioutil"
"reflect"
"testing" "testing"
) )
var (
//funding sign accept
fundingSignAccept = &FundingSignAccept{
ReservationID: uint64(12345678),
CommitSig: commitSig,
FundingTXSigs: &fundingTXSigs,
}
fundingSignAcceptSerializedString = "0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
fundingSignAcceptSerializedMessage = "0709110b000000dc000000df0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
)
func TestFundingSignAcceptEncodeDecode(t *testing.T) { func TestFundingSignAcceptEncodeDecode(t *testing.T) {
var ( //All of these types being passed are of the message interface type
//For debugging, writes to /dev/shm/ //Test serialization, runs: message.Encode(b, 0)
//Maybe in the future do it if you do "go test -v" //Returns bytes
WRITE_FILE = false //Compares the expected serialized string from the original
FILENAME = "/dev/shm/fundingSignAccept.raw" s := SerializeTest(t, fundingSignAccept, fundingSignAcceptSerializedString, filename)
privKeyBytes, _ = hex.DecodeString("9fa1d55217f57019a3c37f49465896b15836f54cb8ef6963870a52926420a2dd") //Test deserialization, runs: message.Decode(s, 0)
privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) //Makes sure the deserialized struct is the same as the original
//pubKeyBytes, _ = hex.DecodeString("02f977808cb9577897582d7524b562691e180953dd0008eb44e09594c539d6daee") newMessage := NewFundingSignAccept()
//pubKey, _ = btcec.ParsePubKey(pubKeyBytes, btcec.S256()) DeserializeTest(t, s, newMessage, fundingSignAccept)
//Commitment Signature
tx = wire.NewMsgTx()
emptybytes = new([]byte)
sigStr, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, privKey)
commitSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
//Funding TX Sig 1
sig1privKeyBytes, _ = hex.DecodeString("927f5827d75dd2addeb532c0fa5ac9277565f981dd6d0d037b422be5f60bdbef")
sig1privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig1privKeyBytes)
sigStr1, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig1privKey)
commitSig1, _ = btcec.ParseSignature(sigStr1, btcec.S256())
//Funding TX Sig 2
sig2privKeyBytes, _ = hex.DecodeString("8a4ad188f6f4000495b765cfb6ffa591133a73019c45428ddd28f53bab551847")
sig2privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig2privKeyBytes)
sigStr2, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig2privKey)
commitSig2, _ = btcec.ParseSignature(sigStr2, btcec.S256())
fundingTXSigs = append(*new([]btcec.Signature), *commitSig1, *commitSig2)
//funding response
fundingSignAccept = &FundingSignAccept{
ReservationID: uint64(12345678),
CommitSig: commitSig,
FundingTXSigs: &fundingTXSigs,
}
serializedString = "0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
serializedMessage = "0709110b000000dc000000df0000000000bc614e4630440220333835e58e958f5e92b4ff4e6fa2470dac88094c97506b4d6d1f4e23e52cb481022057483ac18d6b9c9c14f0c626694c9ccf8b27b3dbbedfdf6b6c9a9fa9f427a1df02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
)
//Test serialization
b := new(bytes.Buffer)
err := fundingSignAccept.Encode(b, 0)
if err != nil {
t.Error("Serialization error")
t.Error(err.Error())
} else {
t.Logf("Encoded Funding SignAccept: %x\n", b.Bytes())
//Check if we serialized correctly
if serializedString != hex.EncodeToString(b.Bytes()) {
t.Error("Serialization does not match expected")
}
//So I can do: hexdump -C /dev/shm/fundingSignAccept.raw
if WRITE_FILE {
err = ioutil.WriteFile(FILENAME, b.Bytes(), 0644)
if err != nil {
t.Error("File write error")
t.Error(err.Error())
}
}
}
//Test deserialization
//Make a new buffer just to be clean
c := new(bytes.Buffer)
c.Write(b.Bytes())
newFunding := NewFundingSignAccept()
err = newFunding.Decode(c, 0)
if err != nil {
t.Error("Decoding Error")
t.Error(err.Error())
} else {
if !reflect.DeepEqual(newFunding, fundingSignAccept) {
t.Error("Decoding does not match!")
}
//Show the struct
t.Log(newFunding.String())
}
//Test message using Message interface //Test message using Message interface
//Serialize/Encode //Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
b = new(bytes.Buffer) //Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
_, err = WriteMessage(b, fundingSignAccept, uint32(1), wire.TestNet3) MessageSerializeDeserializeTest(t, fundingSignAccept, fundingSignAcceptSerializedMessage)
t.Logf("%x\n", b.Bytes())
if hex.EncodeToString(b.Bytes()) != serializedMessage {
t.Error("Message encoding error")
}
//Deserialize/Decode
c = new(bytes.Buffer)
c.Write(b.Bytes())
_, msg, _, err := ReadMessage(c, uint32(1), wire.TestNet3)
if err != nil {
t.Errorf(err.Error())
} else {
if !reflect.DeepEqual(msg, fundingSignAccept) {
t.Error("Message decoding does not match!")
}
t.Logf(msg.String())
}
} }

@ -73,7 +73,9 @@ func (c *FundingSignComplete) String() string {
var sigs string var sigs string
for i, in := range *c.FundingTXSigs { for i, in := range *c.FundingTXSigs {
sigs += fmt.Sprintf("\n Slice\t%d\n", i) sigs += fmt.Sprintf("\n Slice\t%d\n", i)
sigs += fmt.Sprintf("\tSig\t%x\n", in.Serialize()) if &in != nil {
sigs += fmt.Sprintf("\tSig\t%x\n", in.Serialize())
}
} }
return fmt.Sprintf("\n--- Begin FundingSignComplete ---\n") + return fmt.Sprintf("\n--- Begin FundingSignComplete ---\n") +
fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) + fmt.Sprintf("ReservationID:\t\t%d\n", c.ReservationID) +

@ -1,112 +1,34 @@
package lnwire package lnwire
import ( import (
"bytes"
"encoding/hex"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
// "io"
"io/ioutil"
"reflect"
"testing" "testing"
) )
var (
//funding response
fundingSignComplete = &FundingSignComplete{
ReservationID: uint64(12345678),
TxID: txid,
FundingTXSigs: &fundingTXSigs,
}
fundingSignCompleteSerializedString = "0000000000bc614efd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
fundingSignCompleteSerializedMessage = "0709110b000000e6000000b80000000000bc614efd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
)
func TestFundingSignCompleteEncodeDecode(t *testing.T) { func TestFundingSignCompleteEncodeDecode(t *testing.T) {
var ( //All of these types being passed are of the message interface type
//For debugging, writes to /dev/shm/ //Test serialization, runs: message.Encode(b, 0)
//Maybe in the future do it if you do "go test -v" //Returns bytes
WRITE_FILE = false //Compares the expected serialized string from the original
FILENAME = "/dev/shm/fundingSignComplete.raw" s := SerializeTest(t, fundingSignComplete, fundingSignCompleteSerializedString, filename)
//TxID //Test deserialization, runs: message.Decode(s, 0)
txid = new(wire.ShaHash) //Makes sure the deserialized struct is the same as the original
//Reversed when displayed newMessage := NewFundingSignComplete()
txidBytes, _ = hex.DecodeString("fd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a") DeserializeTest(t, s, newMessage, fundingSignComplete)
_ = copy(txid[:], txidBytes)
//Funding TX Sig 1
tx = wire.NewMsgTx()
emptybytes = new([]byte)
sig1privKeyBytes, _ = hex.DecodeString("927f5827d75dd2addeb532c0fa5ac9277565f981dd6d0d037b422be5f60bdbef")
sig1privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig1privKeyBytes)
sigStr1, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig1privKey)
commitSig1, _ = btcec.ParseSignature(sigStr1, btcec.S256())
//Funding TX Sig 2
sig2privKeyBytes, _ = hex.DecodeString("8a4ad188f6f4000495b765cfb6ffa591133a73019c45428ddd28f53bab551847")
sig2privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig2privKeyBytes)
sigStr2, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig2privKey)
commitSig2, _ = btcec.ParseSignature(sigStr2, btcec.S256())
fundingTXSigs = append(*new([]btcec.Signature), *commitSig1, *commitSig2)
//funding response
fundingSignComplete = &FundingSignComplete{
ReservationID: uint64(12345678),
TxID: txid,
FundingTXSigs: &fundingTXSigs,
}
serializedString = "0000000000bc614efd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
serializedMessage = "0709110b000000e6000000b80000000000bc614efd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a02473045022100e7946d057c0b4cc4d3ea525ba156b429796858ebc543d75a6c6c2cbca732db6902202fea377c1f9fb98cd103cf5a4fba276a074b378d4227d15f5fa6439f1a6685bb4630440220235ee55fed634080089953048c3e3f7dc3a154fd7ad18f31dc08e05b7864608a02203bdd7d4e4d9a8162d4b511faf161f0bb16c45181187125017cd0c620c53876ca"
)
//Test serialization
b := new(bytes.Buffer)
err := fundingSignComplete.Encode(b, 0)
if err != nil {
t.Error("Serialization error")
t.Error(err.Error())
} else {
t.Logf("Encoded FundingSignComplete: %x\n", b.Bytes())
//Check if we serialized correctly
if serializedString != hex.EncodeToString(b.Bytes()) {
t.Error("Serialization does not match expected")
}
//So I can do: hexdump -C /dev/shm/fundingSignComplete.raw
if WRITE_FILE {
err = ioutil.WriteFile(FILENAME, b.Bytes(), 0644)
if err != nil {
t.Error("File write error")
t.Error(err.Error())
}
}
}
//Test deserialization
//Make a new buffer just to be clean
c := new(bytes.Buffer)
c.Write(b.Bytes())
newFunding := NewFundingSignComplete()
err = newFunding.Decode(c, 0)
if err != nil {
t.Error("Decoding Error")
t.Error(err.Error())
} else {
if !reflect.DeepEqual(newFunding, fundingSignComplete) {
t.Error("Decoding does not match!")
}
//Show the struct
t.Log(newFunding.String())
}
//Test message using Message interface //Test message using Message interface
//Serialize/Encode //Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
b = new(bytes.Buffer) //Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
_, err = WriteMessage(b, fundingSignComplete, uint32(1), wire.TestNet3) MessageSerializeDeserializeTest(t, fundingSignComplete, fundingSignCompleteSerializedMessage)
t.Logf("%x\n", b.Bytes())
if hex.EncodeToString(b.Bytes()) != serializedMessage {
t.Error("Message encoding error")
}
//Deserialize/Decode
c = new(bytes.Buffer)
c.Write(b.Bytes())
_, msg, _, err := ReadMessage(c, uint32(1), wire.TestNet3)
if err != nil {
t.Errorf(err.Error())
} else {
if !reflect.DeepEqual(msg, fundingSignComplete) {
t.Error("Message decoding does not match!")
}
t.Logf(msg.String())
}
} }

145
lnwire/lnwire_test.go Normal file

@ -0,0 +1,145 @@
package lnwire
import (
"bytes"
"encoding/hex"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"io/ioutil"
"reflect"
"testing"
)
//Common variables and functions for the message tests
var (
//For debugging, writes to /dev/shm/
//Maybe in the future do it if you do "go test -v"
WRITE_FILE = true
filename = "/dev/shm/serialized.raw"
//preimage: 9a2cbd088763db88dd8ba79e5726daa6aba4aa7e
//echo -n | openssl sha256 | openssl ripemd160 | openssl sha256 | openssl ripemd160
revocationHashBytes, _ = hex.DecodeString("4132b6b48371f7b022a16eacb9b2b0ebee134d41")
revocationHash [20]byte
privKeyBytes, _ = hex.DecodeString("9fa1d55217f57019a3c37f49465896b15836f54cb8ef6963870a52926420a2dd")
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
// Delivery PkScript
//Privkey: f2c00ead9cbcfec63098dc0a5f152c0165aff40a2ab92feb4e24869a284c32a7
//PKhash: n2fkWVphUzw3zSigzPsv9GuDyg9mohzKpz
deliveryPkScript, _ = hex.DecodeString("76a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac")
// Change PkScript
//Privkey: 5b18f5049efd9d3aff1fb9a06506c0b809fb71562b6ecd02f6c5b3ab298f3b0f
//PKhash: miky84cHvLuk6jcT6GsSbgHR8d7eZCu9Qc
changePkScript, _ = hex.DecodeString("76a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac")
//echo -n | openssl sha256
//This stuff gets reversed!!!
shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
shaHash1, _ = wire.NewShaHash(shaHash1Bytes)
outpoint1 = wire.NewOutPoint(shaHash1, 0)
//echo | openssl sha256
//This stuff gets reversed!!!
shaHash2Bytes, _ = hex.DecodeString("01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b")
shaHash2, _ = wire.NewShaHash(shaHash2Bytes)
outpoint2 = wire.NewOutPoint(shaHash2, 1)
//create inputs from outpoint1 and outpoint2
inputs = []*wire.TxIn{wire.NewTxIn(outpoint1, nil), wire.NewTxIn(outpoint2, nil)}
//Commitment Signature
tx = wire.NewMsgTx()
emptybytes = new([]byte)
sigStr, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, privKey)
commitSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
//Funding TX Sig 1
sig1privKeyBytes, _ = hex.DecodeString("927f5827d75dd2addeb532c0fa5ac9277565f981dd6d0d037b422be5f60bdbef")
sig1privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig1privKeyBytes)
sigStr1, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig1privKey)
commitSig1, _ = btcec.ParseSignature(sigStr1, btcec.S256())
//Funding TX Sig 2
sig2privKeyBytes, _ = hex.DecodeString("8a4ad188f6f4000495b765cfb6ffa591133a73019c45428ddd28f53bab551847")
sig2privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig2privKeyBytes)
sigStr2, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig2privKey)
commitSig2, _ = btcec.ParseSignature(sigStr2, btcec.S256())
//Slice of Funding TX Sigs
fundingTXSigs = append(*new([]btcec.Signature), *commitSig1, *commitSig2)
//TxID
txid = new(wire.ShaHash)
//Reversed when displayed
txidBytes, _ = hex.DecodeString("fd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a")
_ = copy(txid[:], txidBytes)
)
func SerializeTest(t *testing.T, message Message, expectedString string, filename string) *bytes.Buffer {
var err error
b := new(bytes.Buffer)
err = message.Encode(b, 0)
if err != nil {
t.Errorf(err.Error())
} else {
t.Logf("Encoded Funding Request: %x\n", b.Bytes())
//Check if we serialized correctly
if expectedString != hex.EncodeToString(b.Bytes()) {
t.Error("Serialization does not match expected")
}
//So I can do: hexdump -C /dev/shm/fundingRequest.raw
if WRITE_FILE {
err = ioutil.WriteFile(filename, b.Bytes(), 0644)
if err != nil {
t.Error(err.Error())
}
}
}
return b
}
func DeserializeTest(t *testing.T, buf *bytes.Buffer, message Message, originalMessage Message) {
var err error
//Make a new buffer just to be clean
c := new(bytes.Buffer)
c.Write(buf.Bytes())
err = message.Decode(c, 0)
if err != nil {
t.Error("Decoding Error")
t.Error(err.Error())
} else {
if !reflect.DeepEqual(message, originalMessage) {
t.Error("Decoding does not match!")
}
//Show the struct
t.Log(message.String())
}
}
func MessageSerializeDeserializeTest(t *testing.T, message Message, expectedString string) {
var err error
b := new(bytes.Buffer)
_, err = WriteMessage(b, message, uint32(1), wire.TestNet3)
t.Logf("%x\n", b.Bytes())
if hex.EncodeToString(b.Bytes()) != expectedString {
t.Error("Message encoding error")
}
//Deserialize/Decode
c := new(bytes.Buffer)
c.Write(b.Bytes())
_, newMsg, _, err := ReadMessage(c, uint32(1), wire.TestNet3)
if err != nil {
t.Errorf(err.Error())
} else {
if !reflect.DeepEqual(newMsg, message) {
t.Error("Message decoding does not match!")
}
t.Logf(newMsg.String())
}
}