Cleanup comments & removed notes on escrow

This commit is contained in:
Joseph Poon 2016-01-16 17:14:35 -08:00
parent 84c0f56330
commit f2a1c0368a
36 changed files with 648 additions and 769 deletions

@ -1,121 +0,0 @@
NOTE: Not implemented in code, only included as part of the wire protocol for
future implementation!
There are multiple R-value hashes supported in HTLCs in the wire protocol. This
is to support conditional multiparty payments, e.g. 2-of-3 "escrow", which is
one of the biggest use cases of bitcoin scripting today. An example use case is
a 3rd party escrow verifies whether a seller should be paid. This design is
such that the escrow is not a traditional custodial escrow, but instead
determines who should get the money in the event of non-cooperation.
In this implementation, we are including *wire protocol support* but not
writing code yet for 2-of-3, it is to be implemented later. Arbitrary N-of-M
can be supported with M values higher than 3 and lower than max script size,
but let's keep this simple for now!
How it works: Require 2-of-3 R-value preimages (from 3 hashes) in order for the
HTLC to be fulfilled. For each hop in the payment, it requires this 2-of-3
condition. The timeout minimum for each hop in the path is at least the minimum
agreed contractual escrow timeout. This means each hop consumes a higher amount
of time-value (due to much longer timeouts along all channels in the path),
which does have greater pressure towards lower hop-distances compared to
straight payments.
This is a slightly different way of thinking about things. It's not signatures
that the escrow produces (or for that matters any of the 3-parties in the
2-of-3). It's some secret which is revealed to authorize payment. So if the
Escrow wants the payment to go through, they disclose the secret (R-value) to
the recipient. If the recipient is unable to produce 2-of-3, after the agreed
timeout, the sender will be refunded. Sender and receiver can agree to
authorize payment in most cases where there is cooperation, escrow is only
contacted if there is non-cooperation.
Supported in the wire protocol for the uint8 (two 4-bit N-of-M):
17 (00010001): 1-of-1
34 (00100010): 2-of-2
35 (00100011): 2-of-3 [with Recipient being 1 of the two N parties]
51 (00110011): 3-of-3
I think the only ones that really matter are 1-of-1, 2-of-3, and 2-of-2. 1-of-2
and 1-of-3 doesn't make sense if the recipient must consent to receiving funds
anyway (pushing funds w/o consent is tricky due to pay-to-contract-hash) so
that's basically a 1-of-1.
Assume the order in the stack is Sender, Escrow, Recipient.
For PAID 2-of-3 Escrow+Recipient, the HTLC stack is:
<BobSig> <0> <EscrowPreimageR> <RecipientPreimageR> <0>
If it's REFUND because 2-of-3 has not been redeemed in time:
<AliceSig> <1>
Script (we use OP_1/OP_0 to distinctly show computed true/false. 0/1 is for
supplied data as part of the sigScript/redeemScript stack):
-------------------------------------------------------------------------------
//Paid
OP_IF
<CSVDelay> OP_DROP OP_CSV
//Stack: <BobSig> <0> <EscrowPreimageR> <RecipientPreimageR>
//Recipient must agree to receive funds.
OP_HASH160 <RecipientHash> OP_EQUALVERIFY
//Stack: <BobSig> <0> <EscrowPreimageR>
//Either the Sender or Escrow must consent for payment
OP_HASH160 <EscrowHash> OP_EQUAL
//Stack: <BobSig> <0> <OP_1>
OP_SWAP
//Stack: <BobSig> <OP_1> <0>
OP_HASH160 <SenderHash> OP_EQUAL
//Stack: <BobSig> <OP_1> <OP_0>
OP_BOOLOR
//Stack: <BobSig> <OP_1>
OP_VERIFY
<BobPubKey>
//Stack: <BobSig> <BobPubKey>
//Refund
OP_ELSE
<CSVDelay> OP_DROP OP_CSV
<HTLCTimeout> OP_DROP OP_CLTV
<AlicePubKey>
//Stack: <AliceSig> <AlicePubKey>
OP_ENDIF
OP_CHECKSIG
-------------------------------------------------------------------------------
Note: It is possible that Alice and Bob may not be Sender, Recipient, nor
Escrow!
The result? We can do 2-of-3 escrow payments which refund to the sender after a
timeout! The Sender and Recipient can agree to redeem and they only need to go
to the Escrow if there's a dispute. All nodes along the path gets paid or
refunded atomically, the same as a single-HTLC payment on Lightning.
Possible Resolution States:
* Recipient paid: Recipient and Sender provide R-values
* Recipient paid: Recipient and Escrow provide R-values
* Sender refunded via timeout: Sender is refunded if Recipient cannot convince
Escrow or Sender to disclose their R-value before HTLC timeout
* Payment immediately cancelled and Sender gets refunded: Payment sent in the
opposite direction enforced by same R-values (if there is sender & receiver
consent & cooperation to cancel payment)
Sender+Escrow isn't going to want to push funds w/o cooperation of Recipient.
However, it's possible to construct a script that way.
Ta-da! "Smart Contract(TM)" maymay.
Escrow-enforced immediately refundable payments (2-of-3 can immediately cancel
a payment) are also possible but requires another payment in the opposite
direction with the R-value hashed twice (the H becomes the R-value) and funds
encumbered in the opposite direction, but that's kind of annoying to write...
it's easier if immediate refund can only occur when both Recipient+Sender agree
to cancel the payment immediately (otherwise it will wait until the timeout).
Escrow is only contacted if the recipient needs to redeem and the sender is
uncooperative so this is still true to the "lazy escrow service" in Bitcoin
multisig.
(2-of-2 is also needed for payment cancellation.)

@ -11,15 +11,15 @@ import (
type CloseComplete struct { type CloseComplete struct {
ReservationID uint64 ReservationID uint64
ResponderCloseSig *btcec.Signature //Requester's Commitment ResponderCloseSig *btcec.Signature // Requester's Commitment
CloseShaHash *wire.ShaHash //TxID of the Close Tx CloseShaHash *wire.ShaHash // TxID of the Close Tx
} }
func (c *CloseComplete) Decode(r io.Reader, pver uint32) error { func (c *CloseComplete) Decode(r io.Reader, pver uint32) error {
//ReservationID (8) // ReservationID (8)
//ResponderCloseSig (73) // ResponderCloseSig (73)
// First byte length then sig // First byte length then sig
//CloseShaHash (32) // CloseShaHash (32)
err := readElements(r, err := readElements(r,
&c.ReservationID, &c.ReservationID,
&c.ResponderCloseSig, &c.ResponderCloseSig,
@ -31,17 +31,17 @@ func (c *CloseComplete) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new CloseComplete // Creates a new CloseComplete
func NewCloseComplete() *CloseComplete { func NewCloseComplete() *CloseComplete {
return &CloseComplete{} return &CloseComplete{}
} }
//Serializes the item from the CloseComplete struct // Serializes the item from the CloseComplete struct
//Writes the data to w // Writes the data to w
func (c *CloseComplete) Encode(w io.Writer, pver uint32) error { func (c *CloseComplete) Encode(w io.Writer, pver uint32) error {
//ReservationID // ReservationID
//ResponderCloseSig // ResponderCloseSig
//CloseShaHash // CloseShaHash
err := writeElements(w, err := writeElements(w,
c.ReservationID, c.ReservationID,
c.ResponderCloseSig, c.ResponderCloseSig,
@ -58,13 +58,13 @@ func (c *CloseComplete) Command() uint32 {
} }
func (c *CloseComplete) MaxPayloadLength(uint32) uint32 { func (c *CloseComplete) MaxPayloadLength(uint32) uint32 {
//8 + 73 + 32 // 8 + 73 + 32
return 113 return 113
} }
//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)
func (c *CloseComplete) Validate() error { func (c *CloseComplete) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -1,7 +1,7 @@
package lnwire package lnwire
import ( import (
//"github.com/btcsuite/btcutil" // "github.com/btcsuite/btcutil"
"testing" "testing"
) )
@ -16,19 +16,19 @@ var (
) )
func TestCloseCompleteEncodeDecode(t *testing.T) { func TestCloseCompleteEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, closeComplete, closeCompleteSerializedString, filename) s := SerializeTest(t, closeComplete, closeCompleteSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewCloseComplete() newMessage := NewCloseComplete()
DeserializeTest(t, s, newMessage, closeComplete) DeserializeTest(t, s, newMessage, closeComplete)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, closeComplete, closeCompleteSerializedMessage) MessageSerializeDeserializeTest(t, closeComplete, closeCompleteSerializedMessage)
} }

@ -11,15 +11,15 @@ import (
type CloseRequest struct { type CloseRequest struct {
ReservationID uint64 ReservationID uint64
RequesterCloseSig *btcec.Signature //Requester's Commitment RequesterCloseSig *btcec.Signature // Requester's Commitment
Fee btcutil.Amount Fee btcutil.Amount
} }
func (c *CloseRequest) Decode(r io.Reader, pver uint32) error { func (c *CloseRequest) Decode(r io.Reader, pver uint32) error {
//ReservationID (8) // ReservationID (8)
//RequesterCloseSig (73) // RequesterCloseSig (73)
// First byte length then sig // First byte length then sig
//Fee (8) // Fee (8)
err := readElements(r, err := readElements(r,
&c.ReservationID, &c.ReservationID,
&c.RequesterCloseSig, &c.RequesterCloseSig,
@ -31,17 +31,17 @@ func (c *CloseRequest) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new CloseRequest // Creates a new CloseRequest
func NewCloseRequest() *CloseRequest { func NewCloseRequest() *CloseRequest {
return &CloseRequest{} return &CloseRequest{}
} }
//Serializes the item from the CloseRequest struct // Serializes the item from the CloseRequest struct
//Writes the data to w // Writes the data to w
func (c *CloseRequest) Encode(w io.Writer, pver uint32) error { func (c *CloseRequest) Encode(w io.Writer, pver uint32) error {
//ReservationID // ReservationID
//RequesterCloseSig // RequesterCloseSig
//Fee // Fee
err := writeElements(w, err := writeElements(w,
c.ReservationID, c.ReservationID,
c.RequesterCloseSig, c.RequesterCloseSig,
@ -58,17 +58,17 @@ func (c *CloseRequest) Command() uint32 {
} }
func (c *CloseRequest) MaxPayloadLength(uint32) uint32 { func (c *CloseRequest) MaxPayloadLength(uint32) uint32 {
//8 + 73 + 8 // 8 + 73 + 8
return 89 return 89
} }
//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)
func (c *CloseRequest) Validate() error { func (c *CloseRequest) Validate() error {
//Fee must be greater than 0 // Fee must be greater than 0
if c.Fee < 0 { if c.Fee < 0 {
return fmt.Errorf("Fee must be greater than zero.") return fmt.Errorf("Fee must be greater than zero.")
} }
//We're good! // We're good!
return nil return nil
} }

@ -16,19 +16,19 @@ var (
) )
func TestCloseRequestEncodeDecode(t *testing.T) { func TestCloseRequestEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, closeRequest, closeRequestSerializedString, filename) s := SerializeTest(t, closeRequest, closeRequestSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewCloseRequest() newMessage := NewCloseRequest()
DeserializeTest(t, s, newMessage, closeRequest) DeserializeTest(t, s, newMessage, closeRequest)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, closeRequest, closeRequestSerializedMessage) MessageSerializeDeserializeTest(t, closeRequest, closeRequestSerializedMessage)
} }

@ -5,28 +5,28 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type CommitRevocation struct { type CommitRevocation struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//Height of the commitment // Height of the commitment
//You should have the most recent commitment height stored locally // You should have the most recent commitment height stored locally
//This should be validated! // This should be validated!
//This is used for shachain. // This is used for shachain.
//Each party increments their own CommitmentHeight, they can differ for // Each party increments their own CommitmentHeight, they can differ for
//each part of the Commitment. // each part of the Commitment.
CommitmentHeight uint64 CommitmentHeight uint64
//Revocation to use // Revocation to use
RevocationProof [20]byte RevocationProof [20]byte
} }
func (c *CommitRevocation) Decode(r io.Reader, pver uint32) error { func (c *CommitRevocation) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//CommitmentHeight(8) // CommitmentHeight(8)
//RevocationProof(20) // RevocationProof(20)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.CommitmentHeight, &c.CommitmentHeight,
@ -39,13 +39,13 @@ func (c *CommitRevocation) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new CommitRevocation // Creates a new CommitRevocation
func NewCommitRevocation() *CommitRevocation { func NewCommitRevocation() *CommitRevocation {
return &CommitRevocation{} return &CommitRevocation{}
} }
//Serializes the item from the CommitRevocation struct // Serializes the item from the CommitRevocation struct
//Writes the data to w // Writes the data to w
func (c *CommitRevocation) Encode(w io.Writer, pver uint32) error { func (c *CommitRevocation) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -67,9 +67,9 @@ func (c *CommitRevocation) MaxPayloadLength(uint32) uint32 {
return 36 return 36
} }
//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)
func (c *CommitRevocation) Validate() error { func (c *CommitRevocation) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -5,32 +5,32 @@ import (
) )
var ( var (
//Need to to do this here // Need to to do this here
_ = copy(revocationHash[:], revocationHashBytes) _ = copy(revocationHash[:], revocationHashBytes)
commitRevocation = &CommitRevocation{ commitRevocation = &CommitRevocation{
ChannelID: uint64(12345678), ChannelID: uint64(12345678),
CommitmentHeight: uint64(12345), CommitmentHeight: uint64(12345),
RevocationProof: revocationHash, //technically it's not a hash... fix later RevocationProof: revocationHash, // technically it's not a hash... fix later
} }
commitRevocationSerializedString = "0000000000bc614e00000000000030394132b6b48371f7b022a16eacb9b2b0ebee134d41" commitRevocationSerializedString = "0000000000bc614e00000000000030394132b6b48371f7b022a16eacb9b2b0ebee134d41"
commitRevocationSerializedMessage = "0709110b000007da000000240000000000bc614e00000000000030394132b6b48371f7b022a16eacb9b2b0ebee134d41" commitRevocationSerializedMessage = "0709110b000007da000000240000000000bc614e00000000000030394132b6b48371f7b022a16eacb9b2b0ebee134d41"
) )
func TestCommitRevocationEncodeDecode(t *testing.T) { func TestCommitRevocationEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, commitRevocation, commitRevocationSerializedString, filename) s := SerializeTest(t, commitRevocation, commitRevocationSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewCommitRevocation() newMessage := NewCommitRevocation()
DeserializeTest(t, s, newMessage, commitRevocation) DeserializeTest(t, s, newMessage, commitRevocation)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, commitRevocation, commitRevocationSerializedMessage) MessageSerializeDeserializeTest(t, commitRevocation, commitRevocationSerializedMessage)
} }

@ -7,40 +7,40 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type CommitSignature struct { type CommitSignature struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//Height of the commitment // Height of the commitment
//You should have the most recent commitment height stored locally // You should have the most recent commitment height stored locally
//This should be validated! // This should be validated!
//This is used for shachain. // This is used for shachain.
//Each party increments their own CommitmentHeight, they can differ for // Each party increments their own CommitmentHeight, they can differ for
//each part of the Commitment. // each part of the Commitment.
CommitmentHeight uint64 CommitmentHeight uint64
//List of HTLC Keys which are updated from all parties // List of HTLC Keys which are updated from all parties
UpdatedHTLCKeys []uint64 UpdatedHTLCKeys []uint64
//Hash of the revocation to use // Hash of the revocation to use
RevocationHash [20]byte RevocationHash [20]byte
//Total miners' fee that was used // Total miners' fee that was used
Fee btcutil.Amount Fee btcutil.Amount
//Signature for the new Commitment // Signature for the new Commitment
CommitSig *btcec.Signature //Requester's Commitment CommitSig *btcec.Signature // Requester's Commitment
} }
func (c *CommitSignature) Decode(r io.Reader, pver uint32) error { func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//CommitmentHeight(8) // CommitmentHeight(8)
//c.UpdatedHTLCKeys(8*1000max) // c.UpdatedHTLCKeys(8*1000max)
//RevocationHash(20) // RevocationHash(20)
//Fee(8) // Fee(8)
//RequesterCommitSig(73max+2) // RequesterCommitSig(73max+2)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.CommitmentHeight, &c.CommitmentHeight,
@ -56,13 +56,13 @@ func (c *CommitSignature) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new CommitSignature // Creates a new CommitSignature
func NewCommitSignature() *CommitSignature { func NewCommitSignature() *CommitSignature {
return &CommitSignature{} return &CommitSignature{}
} }
//Serializes the item from the CommitSignature struct // Serializes the item from the CommitSignature struct
//Writes the data to w // Writes the data to w
func (c *CommitSignature) Encode(w io.Writer, pver uint32) error { func (c *CommitSignature) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -87,24 +87,24 @@ func (c *CommitSignature) MaxPayloadLength(uint32) uint32 {
return 8192 return 8192
} }
//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)
func (c *CommitSignature) Validate() error { func (c *CommitSignature) Validate() error {
if c.Fee < 0 { if c.Fee < 0 {
//While fees can be negative, it's too confusing to allow // While fees can be negative, it's too confusing to allow
//negative payments. Maybe for some wallets, but not this one! // negative payments. Maybe for some wallets, but not this one!
return fmt.Errorf("Amount paid cannot be negative.") return fmt.Errorf("Amount paid cannot be negative.")
} }
//We're good! // We're good!
return nil return nil
} }
func (c *CommitSignature) String() string { func (c *CommitSignature) String() string {
//c.ChannelID, // c.ChannelID,
//c.CommitmentHeight, // c.CommitmentHeight,
//c.RevocationHash, // c.RevocationHash,
//c.UpdatedHTLCKeys, // c.UpdatedHTLCKeys,
//c.Fee, // c.Fee,
//c.CommitSig, // c.CommitSig,
var serializedSig []byte var serializedSig []byte
if &c.CommitSig != nil && c.CommitSig.R != nil { if &c.CommitSig != nil && c.CommitSig.R != nil {
serializedSig = c.CommitSig.Serialize() serializedSig = c.CommitSig.Serialize()

@ -6,13 +6,13 @@ import (
) )
var ( var (
//Need to to do this here // Need to to do this here
_ = copy(revocationHash[:], revocationHashBytes) _ = copy(revocationHash[:], revocationHashBytes)
commitSignature = &CommitSignature{ commitSignature = &CommitSignature{
ChannelID: uint64(12345678), ChannelID: uint64(12345678),
CommitmentHeight: uint64(12345), CommitmentHeight: uint64(12345),
//CommitterLastStaging: uint64(12345678), // CommitterLastStaging: uint64(12345678),
UpdatedHTLCKeys: []uint64{1, 2, 3, 4, 5}, UpdatedHTLCKeys: []uint64{1, 2, 3, 4, 5},
RevocationHash: revocationHash, RevocationHash: revocationHash,
Fee: btcutil.Amount(10000), Fee: btcutil.Amount(10000),
@ -23,19 +23,19 @@ var (
) )
func TestCommitSignatureEncodeDecode(t *testing.T) { func TestCommitSignatureEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, commitSignature, commitSignatureSerializedString, filename) s := SerializeTest(t, commitSignature, commitSignatureSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewCommitSignature() newMessage := NewCommitSignature()
DeserializeTest(t, s, newMessage, commitSignature) DeserializeTest(t, s, newMessage, commitSignature)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, commitSignature, commitSignatureSerializedMessage) MessageSerializeDeserializeTest(t, commitSignature, commitSignatureSerializedMessage)
} }

@ -5,19 +5,19 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type ErrorGeneric struct { type ErrorGeneric struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//Some kind of message // Some kind of message
//Max length 8192 // Max length 8192
Problem string Problem string
} }
func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error { func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//Problem // Problem
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.Problem, &c.Problem,
@ -29,13 +29,13 @@ func (c *ErrorGeneric) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new ErrorGeneric // Creates a new ErrorGeneric
func NewErrorGeneric() *ErrorGeneric { func NewErrorGeneric() *ErrorGeneric {
return &ErrorGeneric{} return &ErrorGeneric{}
} }
//Serializes the item from the ErrorGeneric struct // Serializes the item from the ErrorGeneric struct
//Writes the data to w // Writes the data to w
func (c *ErrorGeneric) Encode(w io.Writer, pver uint32) error { func (c *ErrorGeneric) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -53,16 +53,16 @@ func (c *ErrorGeneric) Command() uint32 {
} }
func (c *ErrorGeneric) MaxPayloadLength(uint32) uint32 { func (c *ErrorGeneric) MaxPayloadLength(uint32) uint32 {
//8+8192 // 8+8192
return 8208 return 8208
} }
//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)
func (c *ErrorGeneric) Validate() error { func (c *ErrorGeneric) Validate() error {
if len(c.Problem) > 8192 { if len(c.Problem) > 8192 {
return fmt.Errorf("Problem string length too long") return fmt.Errorf("Problem string length too long")
} }
//We're good! // We're good!
return nil return nil
} }

@ -14,19 +14,19 @@ var (
) )
func TestErrorGenericEncodeDecode(t *testing.T) { func TestErrorGenericEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, errorGeneric, errorGenericSerializedString, filename) s := SerializeTest(t, errorGeneric, errorGenericSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewErrorGeneric() newMessage := NewErrorGeneric()
DeserializeTest(t, s, newMessage, errorGeneric) DeserializeTest(t, s, newMessage, errorGeneric)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, errorGeneric, errorGenericSerializedMessage) MessageSerializeDeserializeTest(t, errorGeneric, errorGenericSerializedMessage)
} }

@ -17,62 +17,62 @@ type FundingRequest struct {
RequesterReserveAmount btcutil.Amount RequesterReserveAmount btcutil.Amount
MinFeePerKb btcutil.Amount MinFeePerKb btcutil.Amount
//The funding requester can request payment // The funding requester can request payment
//This wallet only allows positive values, // This wallet only allows positive values,
//which is a payment to the responder // which is a payment to the responder
//(This can be used to fund the Reserve) // (This can be used to fund the Reserve)
//If the responder disagrees, then the funding request fails // If the responder disagrees, then the funding request fails
//THIS VALUE GOES INTO THE RESPONDER'S FUNDING AMOUNT // THIS VALUE GOES INTO THE RESPONDER'S FUNDING AMOUNT
//total requester input value = RequesterFundingAmount + PaymentAmount + "Total Change" + Fees(?) // total requester input value = RequesterFundingAmount + PaymentAmount + "Total Change" + Fees(?)
//RequesterFundingAmount = "Available Balance" + RequesterReserveAmount // RequesterFundingAmount = "Available Balance" + RequesterReserveAmount
//Payment SHOULD NOT be acknowledged until the minimum confirmation has elapsed // Payment SHOULD NOT be acknowledged until the minimum confirmation has elapsed
//(Due to double-spend risks the recipient will not want to acknolwedge confirmation until later) // (Due to double-spend risks the recipient will not want to acknolwedge confirmation until later)
//This is to make a payment as part of opening the channel // This is to make a payment as part of opening the channel
PaymentAmount btcutil.Amount PaymentAmount btcutil.Amount
//Minimum number of confirmations to validate transaction // Minimum number of confirmations to validate transaction
MinDepth uint32 MinDepth uint32
//Should double-check the total funding later // Should double-check the total funding later
MinTotalFundingAmount btcutil.Amount MinTotalFundingAmount btcutil.Amount
//CLTV/CSV lock-time to use // CLTV/CSV lock-time to use
LockTime uint32 LockTime uint32
//Who pays the fees // Who pays the fees
//0: (default) channel initiator // 0: (default) channel initiator
//1: split // 1: split
//2: channel responder // 2: channel responder
FeePayer uint8 FeePayer uint8
RevocationHash [20]byte RevocationHash [20]byte
Pubkey *btcec.PublicKey Pubkey *btcec.PublicKey
DeliveryPkScript PkScript //*MUST* be either P2PKH or P2SH DeliveryPkScript PkScript // *MUST* be either P2PKH or P2SH
ChangePkScript PkScript //*MUST* be either P2PKH or P2SH ChangePkScript PkScript // *MUST* be either P2PKH or P2SH
Inputs []*wire.TxIn Inputs []*wire.TxIn
} }
func (c *FundingRequest) Decode(r io.Reader, pver uint32) error { func (c *FundingRequest) Decode(r io.Reader, pver uint32) error {
//Reservation ID (8) // Reservation ID (8)
//Channel Type (1) // Channel Type (1)
//Funding Amount (8) // Funding Amount (8)
//Channel Minimum Capacity (8) // Channel Minimum Capacity (8)
//Revocation Hash (20) // Revocation Hash (20)
//Commitment Pubkey (32) // Commitment Pubkey (32)
//Reserve Amount (8) // Reserve Amount (8)
//Minimum Transaction Fee Per Kb (8) // Minimum Transaction Fee Per Kb (8)
//PaymentAmount (8) // PaymentAmount (8)
//MinDepth (4) // MinDepth (4)
//LockTime (4) // LockTime (4)
//FeePayer (1) // 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)
// First byte length then pkscript // First byte length then pkscript
//Inputs: Create the TxIns // Inputs: Create the TxIns
// First byte is number of inputs // First byte is number of inputs
// For each input, it's 32bytes txin & 4bytes index // For each input, it's 32bytes txin & 4bytes index
err := readElements(r, err := readElements(r,
&c.ReservationID, &c.ReservationID,
&c.ChannelType, &c.ChannelType,
@ -96,26 +96,26 @@ func (c *FundingRequest) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new FundingRequest // Creates a new FundingRequest
func NewFundingRequest() *FundingRequest { func NewFundingRequest() *FundingRequest {
return &FundingRequest{} return &FundingRequest{}
} }
//Serializes the item from the FundingRequest struct // Serializes the item from the FundingRequest struct
//Writes the data to w // Writes the data to w
func (c *FundingRequest) Encode(w io.Writer, pver uint32) error { func (c *FundingRequest) Encode(w io.Writer, pver uint32) error {
//Channel Type // Channel Type
//Funding Amont // Funding Amont
//Channel Minimum Capacity // Channel Minimum Capacity
//Revocation Hash // Revocation Hash
//Commitment Pubkey // Commitment Pubkey
//Reserve Amount // Reserve Amount
//Minimum Transaction Fee Per KB // Minimum Transaction Fee Per KB
//LockTime // LockTime
//FeePayer // FeePayer
//DeliveryPkScript // DeliveryPkScript
//ChangePkScript // ChangePkScript
//Inputs: Append the actual Txins // Inputs: Append the actual Txins
err := writeElements(w, err := writeElements(w,
c.ReservationID, c.ReservationID,
c.ChannelType, c.ChannelType,
@ -144,15 +144,15 @@ func (c *FundingRequest) Command() uint32 {
} }
func (c *FundingRequest) MaxPayloadLength(uint32) uint32 { func (c *FundingRequest) MaxPayloadLength(uint32) uint32 {
//110 (base size) + 26 (pkscript) + 26 (pkscript) + 1 (numTxes) + 127*36(127 inputs * sha256+idx) // 110 (base size) + 26 (pkscript) + 26 (pkscript) + 1 (numTxes) + 127*36(127 inputs * sha256+idx)
return 4735 return 4735
} }
//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)
func (c *FundingRequest) Validate() error { func (c *FundingRequest) Validate() error {
var err error var err error
//No negative values // No negative values
if c.RequesterFundingAmount < 0 { if c.RequesterFundingAmount < 0 {
return fmt.Errorf("RequesterFundingAmount cannot be negative") return fmt.Errorf("RequesterFundingAmount cannot be negative")
} }
@ -168,7 +168,7 @@ func (c *FundingRequest) Validate() error {
return fmt.Errorf("MinTotalFundingAmount cannot be negative") return fmt.Errorf("MinTotalFundingAmount cannot be negative")
} }
//Validation of what makes sense... // Validation of what makes sense...
if c.MinTotalFundingAmount < c.RequesterFundingAmount { if c.MinTotalFundingAmount < c.RequesterFundingAmount {
return fmt.Errorf("Requester's minimum too low.") return fmt.Errorf("Requester's minimum too low.")
} }
@ -176,29 +176,29 @@ func (c *FundingRequest) Validate() error {
return fmt.Errorf("Reserve must be below Funding Amount") return fmt.Errorf("Reserve must be below Funding Amount")
} }
//This wallet only allows payment from the requester to responder // This wallet only allows payment from the requester to responder
if c.PaymentAmount < 0 { if c.PaymentAmount < 0 {
return fmt.Errorf("This wallet requieres payment to be greater than zero.") return fmt.Errorf("This wallet requieres payment to be greater than zero.")
} }
//Make sure there's not more than 127 inputs // Make sure there's not more than 127 inputs
if len(c.Inputs) > 127 { if len(c.Inputs) > 127 {
return fmt.Errorf("Too many inputs") 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 {
return err return err
} }
//ChangePkScript is either P2SH or P2PKH // ChangePkScript is either P2SH or P2PKH
err = ValidatePkScript(c.ChangePkScript) err = ValidatePkScript(c.ChangePkScript)
if err != nil { if err != nil {
return err return err
} }
//We're good! // We're good!
return nil return nil
} }

@ -6,10 +6,10 @@ import (
) )
var ( var (
//Need to do this here // Need to do this here
_ = copy(revocationHash[:], revocationHashBytes) _ = copy(revocationHash[:], revocationHashBytes)
//funding request // funding request
fundingRequest = &FundingRequest{ fundingRequest = &FundingRequest{
ReservationID: uint64(12345678), ReservationID: uint64(12345678),
ChannelType: uint8(0), ChannelType: uint8(0),
@ -17,7 +17,7 @@ var (
RequesterReserveAmount: 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),
PaymentAmount: btcutil.Amount(1234567), PaymentAmount: btcutil.Amount(1234567),
MinDepth: uint32(6), MinDepth: uint32(6),
@ -32,19 +32,19 @@ var (
) )
func TestFundingRequestEncodeDecode(t *testing.T) { func TestFundingRequestEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, fundingRequest, fundingRequestSerializedString, filename) s := SerializeTest(t, fundingRequest, fundingRequestSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewFundingRequest() newMessage := NewFundingRequest()
DeserializeTest(t, s, newMessage, fundingRequest) DeserializeTest(t, s, newMessage, fundingRequest)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, fundingRequest, fundingRequestSerializedMessage) MessageSerializeDeserializeTest(t, fundingRequest, fundingRequestSerializedMessage)
} }

@ -13,51 +13,51 @@ type FundingResponse struct {
ReservationID uint64 ReservationID uint64
ResponderFundingAmount btcutil.Amount //Responder's funding amount ResponderFundingAmount btcutil.Amount // Responder's funding amount
ResponderReserveAmount btcutil.Amount //Responder's reserve amount ResponderReserveAmount btcutil.Amount // Responder's reserve amount
MinFeePerKb btcutil.Amount //Lock-in min fee MinFeePerKb btcutil.Amount // Lock-in min fee
//Minimum depth // Minimum depth
MinDepth uint32 MinDepth uint32
//CLTV/CSV lock-time to use // CLTV/CSV lock-time to use
LockTime uint32 LockTime uint32
//Who pays the fees // Who pays the fees
//0: (default) channel initiator // 0: (default) channel initiator
//1: split // 1: split
//2: channel responder // 2: channel responder
FeePayer uint8 FeePayer uint8
RevocationHash [20]byte RevocationHash [20]byte
Pubkey *btcec.PublicKey Pubkey *btcec.PublicKey
CommitSig *btcec.Signature //Requester's Commitment CommitSig *btcec.Signature // Requester's Commitment
DeliveryPkScript PkScript //*MUST* be either P2PKH or P2SH DeliveryPkScript PkScript // *MUST* be either P2PKH or P2SH
ChangePkScript PkScript //*MUST* be either P2PKH or P2SH ChangePkScript PkScript // *MUST* be either P2PKH or P2SH
Inputs []*wire.TxIn Inputs []*wire.TxIn
} }
func (c *FundingResponse) Decode(r io.Reader, pver uint32) error { func (c *FundingResponse) Decode(r io.Reader, pver uint32) error {
//ReservationID (8) // ReservationID (8)
//Channel Type (1) // Channel Type (1)
//Funding Amount (8) // Funding Amount (8)
//Revocation Hash (20) // Revocation Hash (20)
//Commitment Pubkey (32) // Commitment Pubkey (32)
//Reserve Amount (8) // Reserve Amount (8)
//Minimum Transaction Fee Per Kb (8) // Minimum Transaction Fee Per Kb (8)
//MinDepth (4) // MinDepth (4)
//LockTime (4) // LockTime (4)
//FeePayer (1) // 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)
// First byte length then pkscript // First byte length then pkscript
//CommitSig // CommitSig
// First byte length then sig // First byte length then sig
//Inputs: Create the TxIns // Inputs: Create the TxIns
// First byte is number of inputs // First byte is number of inputs
// For each input, it's 32bytes txin & 4bytes index // For each input, it's 32bytes txin & 4bytes index
err := readElements(r, err := readElements(r,
&c.ReservationID, &c.ReservationID,
&c.ChannelType, &c.ChannelType,
@ -80,27 +80,27 @@ func (c *FundingResponse) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new FundingResponse // Creates a new FundingResponse
func NewFundingResponse() *FundingResponse { func NewFundingResponse() *FundingResponse {
return &FundingResponse{} return &FundingResponse{}
} }
//Serializes the item from the FundingResponse struct // Serializes the item from the FundingResponse struct
//Writes the data to w // Writes the data to w
func (c *FundingResponse) Encode(w io.Writer, pver uint32) error { func (c *FundingResponse) Encode(w io.Writer, pver uint32) error {
//ReservationID (8) // ReservationID (8)
//Channel Type (1) // Channel Type (1)
//Funding Amount (8) // Funding Amount (8)
//Revocation Hash (20) // Revocation Hash (20)
//Commitment Pubkey (32) // Commitment Pubkey (32)
//Reserve Amount (8) // Reserve Amount (8)
//Minimum Transaction Fee Per Kb (8) // Minimum Transaction Fee Per Kb (8)
//LockTime (4) // LockTime (4)
//FeePayer (1) // FeePayer (1)
//DeliveryPkScript (final delivery) // DeliveryPkScript (final delivery)
//ChangePkScript (change for extra from inputs) // ChangePkScript (change for extra from inputs)
//CommitSig // CommitSig
//Inputs // Inputs
err := writeElements(w, err := writeElements(w,
c.ReservationID, c.ReservationID,
c.ChannelType, c.ChannelType,
@ -128,15 +128,15 @@ func (c *FundingResponse) Command() uint32 {
} }
func (c *FundingResponse) MaxPayloadLength(uint32) uint32 { func (c *FundingResponse) MaxPayloadLength(uint32) uint32 {
//86 (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 4785 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)
func (c *FundingResponse) Validate() error { func (c *FundingResponse) Validate() error {
var err error var err error
//No negative values // No negative values
if c.ResponderFundingAmount < 0 { if c.ResponderFundingAmount < 0 {
return fmt.Errorf("ResponderFundingAmount cannot be negative") return fmt.Errorf("ResponderFundingAmount cannot be negative")
} }
@ -149,29 +149,29 @@ func (c *FundingResponse) Validate() error {
return fmt.Errorf("MinFeePerKb cannot be negative") return fmt.Errorf("MinFeePerKb cannot be negative")
} }
//Validation of what makes sense... // Validation of what makes sense...
if c.ResponderFundingAmount < c.ResponderReserveAmount { if c.ResponderFundingAmount < c.ResponderReserveAmount {
return fmt.Errorf("Reserve must be below Funding Amount") return fmt.Errorf("Reserve must be below Funding Amount")
} }
//Make sure there's not more than 127 inputs // Make sure there's not more than 127 inputs
if len(c.Inputs) > 127 { if len(c.Inputs) > 127 {
return fmt.Errorf("Too many inputs") 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 {
return err return err
} }
//Change PkScript is either P2SH or P2PKH // Change PkScript is either P2SH or P2PKH
err = ValidatePkScript(c.ChangePkScript) err = ValidatePkScript(c.ChangePkScript)
if err != nil { if err != nil {
return err return err
} }
//We're good! // We're good!
return nil return nil
} }

@ -6,10 +6,10 @@ import (
) )
var ( var (
//Need to do this here // Need to do this here
_ = copy(revocationHash[:], revocationHashBytes) _ = copy(revocationHash[:], revocationHashBytes)
//funding response // funding response
fundingResponse = &FundingResponse{ fundingResponse = &FundingResponse{
ChannelType: uint8(1), ChannelType: uint8(1),
ReservationID: uint64(12345678), ReservationID: uint64(12345678),
@ -17,7 +17,7 @@ var (
ResponderReserveAmount: btcutil.Amount(131072), ResponderReserveAmount: btcutil.Amount(131072),
MinFeePerKb: btcutil.Amount(20000), MinFeePerKb: btcutil.Amount(20000),
MinDepth: uint32(6), MinDepth: uint32(6),
LockTime: uint32(4320), //30 block-days LockTime: uint32(4320), // 30 block-days
FeePayer: uint8(1), FeePayer: uint8(1),
RevocationHash: revocationHash, RevocationHash: revocationHash,
Pubkey: pubKey, Pubkey: pubKey,
@ -31,19 +31,19 @@ var (
) )
func TestFundingResponseEncodeDecode(t *testing.T) { func TestFundingResponseEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, fundingResponse, fundingResponseSerializedString, filename) s := SerializeTest(t, fundingResponse, fundingResponseSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewFundingResponse() newMessage := NewFundingResponse()
DeserializeTest(t, s, newMessage, fundingResponse) DeserializeTest(t, s, newMessage, fundingResponse)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, fundingResponse, fundingResponseSerializedMessage) MessageSerializeDeserializeTest(t, fundingResponse, fundingResponseSerializedMessage)
} }

@ -9,18 +9,18 @@ import (
type FundingSignAccept struct { type FundingSignAccept struct {
ReservationID uint64 ReservationID uint64
CommitSig *btcec.Signature //Requester's Commitment CommitSig *btcec.Signature // Requester's Commitment
FundingTXSigs []*btcec.Signature FundingTXSigs []*btcec.Signature
} }
func (c *FundingSignAccept) Decode(r io.Reader, pver uint32) error { func (c *FundingSignAccept) Decode(r io.Reader, pver uint32) error {
//ReservationID (8) // ReservationID (8)
//CommitSig (73) // CommitSig (73)
// First byte length then sig // First byte length then sig
//FundingTXSigs // FundingTXSigs
// First byte is number of FundingTxSigs // First byte is number of FundingTxSigs
// Sorted list of the requester's input signatures // Sorted list of the requester's input signatures
// (originally provided in the Funding Request) // (originally provided in the Funding Request)
err := readElements(r, err := readElements(r,
&c.ReservationID, &c.ReservationID,
&c.CommitSig, &c.CommitSig,
@ -32,17 +32,17 @@ func (c *FundingSignAccept) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new FundingSignAccept // Creates a new FundingSignAccept
func NewFundingSignAccept() *FundingSignAccept { func NewFundingSignAccept() *FundingSignAccept {
return &FundingSignAccept{} return &FundingSignAccept{}
} }
//Serializes the item from the FundingSignAccept struct // Serializes the item from the FundingSignAccept struct
//Writes the data to w // Writes the data to w
func (c *FundingSignAccept) Encode(w io.Writer, pver uint32) error { func (c *FundingSignAccept) Encode(w io.Writer, pver uint32) error {
//ReservationID // ReservationID
//CommitSig // CommitSig
//FundingTxSigs // FundingTxSigs
err := writeElements(w, err := writeElements(w,
c.ReservationID, c.ReservationID,
c.CommitSig, c.CommitSig,
@ -59,13 +59,13 @@ func (c *FundingSignAccept) Command() uint32 {
} }
func (c *FundingSignAccept) MaxPayloadLength(uint32) uint32 { func (c *FundingSignAccept) MaxPayloadLength(uint32) uint32 {
//8 (base size) + 73 + (73maxSigSize*127maxInputs) // 8 (base size) + 73 + (73maxSigSize*127maxInputs)
return 9352 return 9352
} }
//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)
func (c *FundingSignAccept) Validate() error { func (c *FundingSignAccept) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -5,7 +5,7 @@ import (
) )
var ( var (
//funding sign accept // funding sign accept
fundingSignAccept = &FundingSignAccept{ fundingSignAccept = &FundingSignAccept{
ReservationID: uint64(12345678), ReservationID: uint64(12345678),
CommitSig: commitSig, CommitSig: commitSig,
@ -16,19 +16,19 @@ var (
) )
func TestFundingSignAcceptEncodeDecode(t *testing.T) { func TestFundingSignAcceptEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, fundingSignAccept, fundingSignAcceptSerializedString, filename) s := SerializeTest(t, fundingSignAccept, fundingSignAcceptSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewFundingSignAccept() newMessage := NewFundingSignAccept()
DeserializeTest(t, s, newMessage, fundingSignAccept) DeserializeTest(t, s, newMessage, fundingSignAccept)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, fundingSignAccept, fundingSignAcceptSerializedMessage) MessageSerializeDeserializeTest(t, fundingSignAccept, fundingSignAcceptSerializedMessage)
} }

@ -15,12 +15,12 @@ type FundingSignComplete struct {
} }
func (c *FundingSignComplete) Decode(r io.Reader, pver uint32) error { func (c *FundingSignComplete) Decode(r io.Reader, pver uint32) error {
//ReservationID (8) // ReservationID (8)
//TxID (32) // TxID (32)
//FundingTXSigs // FundingTXSigs
// First byte is number of FundingTxSigs // First byte is number of FundingTxSigs
// Sorted list of the requester's input signatures // Sorted list of the requester's input signatures
// (originally provided in the Funding Request) // (originally provided in the Funding Request)
err := readElements(r, err := readElements(r,
&c.ReservationID, &c.ReservationID,
&c.TxID, &c.TxID,
@ -32,13 +32,13 @@ func (c *FundingSignComplete) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new FundingSignComplete // Creates a new FundingSignComplete
func NewFundingSignComplete() *FundingSignComplete { func NewFundingSignComplete() *FundingSignComplete {
return &FundingSignComplete{} return &FundingSignComplete{}
} }
//Serializes the item from the FundingSignComplete struct // Serializes the item from the FundingSignComplete struct
//Writes the data to w // Writes the data to w
func (c *FundingSignComplete) Encode(w io.Writer, pver uint32) error { func (c *FundingSignComplete) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ReservationID, c.ReservationID,
@ -56,13 +56,13 @@ func (c *FundingSignComplete) Command() uint32 {
} }
func (c *FundingSignComplete) MaxPayloadLength(uint32) uint32 { func (c *FundingSignComplete) MaxPayloadLength(uint32) uint32 {
//8 (base size) + 32 + (73maxSigSize*127maxInputs) // 8 (base size) + 32 + (73maxSigSize*127maxInputs)
return 9311 return 9311
} }
//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)
func (c *FundingSignComplete) Validate() error { func (c *FundingSignComplete) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -5,7 +5,7 @@ import (
) )
var ( var (
//funding response // funding response
fundingSignComplete = &FundingSignComplete{ fundingSignComplete = &FundingSignComplete{
ReservationID: uint64(12345678), ReservationID: uint64(12345678),
TxID: txid, TxID: txid,
@ -16,19 +16,19 @@ var (
) )
func TestFundingSignCompleteEncodeDecode(t *testing.T) { func TestFundingSignCompleteEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, fundingSignComplete, fundingSignCompleteSerializedString, filename) s := SerializeTest(t, fundingSignComplete, fundingSignCompleteSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewFundingSignComplete() newMessage := NewFundingSignComplete()
DeserializeTest(t, s, newMessage, fundingSignComplete) DeserializeTest(t, s, newMessage, fundingSignComplete)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, fundingSignComplete, fundingSignCompleteSerializedMessage) MessageSerializeDeserializeTest(t, fundingSignComplete, fundingSignCompleteSerializedMessage)
} }

@ -11,8 +11,8 @@ type HTLCAddAccept struct {
} }
func (c *HTLCAddAccept) Decode(r io.Reader, pver uint32) error { func (c *HTLCAddAccept) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//HTLCKey(8) // HTLCKey(8)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -24,13 +24,13 @@ func (c *HTLCAddAccept) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCAddAccept // Creates a new HTLCAddAccept
func NewHTLCAddAccept() *HTLCAddAccept { func NewHTLCAddAccept() *HTLCAddAccept {
return &HTLCAddAccept{} return &HTLCAddAccept{}
} }
//Serializes the item from the HTLCAddAccept struct // Serializes the item from the HTLCAddAccept struct
//Writes the data to w // Writes the data to w
func (c *HTLCAddAccept) Encode(w io.Writer, pver uint32) error { func (c *HTLCAddAccept) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -49,13 +49,13 @@ func (c *HTLCAddAccept) Command() uint32 {
} }
func (c *HTLCAddAccept) MaxPayloadLength(uint32) uint32 { func (c *HTLCAddAccept) MaxPayloadLength(uint32) uint32 {
//16 base size // 16 base size
return 16 return 16
} }
//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)
func (c *HTLCAddAccept) Validate() error { func (c *HTLCAddAccept) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -14,19 +14,19 @@ var (
) )
func TestHTLCAddAcceptEncodeDecode(t *testing.T) { func TestHTLCAddAcceptEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcAddAccept, htlcAddAcceptSerializedString, filename) s := SerializeTest(t, htlcAddAccept, htlcAddAcceptSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCAddAccept() newMessage := NewHTLCAddAccept()
DeserializeTest(t, s, newMessage, htlcAddAccept) DeserializeTest(t, s, newMessage, htlcAddAccept)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcAddAccept, htlcAddAcceptSerializedMessage) MessageSerializeDeserializeTest(t, htlcAddAccept, htlcAddAcceptSerializedMessage)
} }

@ -11,11 +11,11 @@ type HTLCAddReject struct {
} }
func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error { func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//CommitmentHeight(8) // CommitmentHeight(8)
//NextResponderCommitmentRevocationHash(20) // NextResponderCommitmentRevocationHash(20)
//ResponderRevocationPreimage(20) // ResponderRevocationPreimage(20)
//ResponderCommitSig(2+73max) // ResponderCommitSig(2+73max)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -27,13 +27,13 @@ func (c *HTLCAddReject) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCAddReject // Creates a new HTLCAddReject
func NewHTLCAddReject() *HTLCAddReject { func NewHTLCAddReject() *HTLCAddReject {
return &HTLCAddReject{} return &HTLCAddReject{}
} }
//Serializes the item from the HTLCAddReject struct // Serializes the item from the HTLCAddReject struct
//Writes the data to w // Writes the data to w
func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error { func (c *HTLCAddReject) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -52,13 +52,13 @@ func (c *HTLCAddReject) Command() uint32 {
} }
func (c *HTLCAddReject) MaxPayloadLength(uint32) uint32 { func (c *HTLCAddReject) MaxPayloadLength(uint32) uint32 {
//16 base size // 16 base size
return 16 return 16
} }
//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)
func (c *HTLCAddReject) Validate() error { func (c *HTLCAddReject) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -14,19 +14,19 @@ var (
) )
func TestHTLCAddRejectEncodeDecode(t *testing.T) { func TestHTLCAddRejectEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcAddReject, htlcAddRejectSerializedString, filename) s := SerializeTest(t, htlcAddReject, htlcAddRejectSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCAddReject() newMessage := NewHTLCAddReject()
DeserializeTest(t, s, newMessage, htlcAddReject) DeserializeTest(t, s, newMessage, htlcAddReject)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcAddReject, htlcAddRejectSerializedMessage) MessageSerializeDeserializeTest(t, htlcAddReject, htlcAddRejectSerializedMessage)
} }

@ -5,46 +5,46 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type HTLCAddRequest struct { type HTLCAddRequest struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//ID of this request // ID of this request
HTLCKey HTLCKey HTLCKey HTLCKey
//When the HTLC expires // When the HTLC expires
Expiry uint32 Expiry uint32
//Amount to pay in the hop // Amount to pay in the hop
//Difference between hop and first item in blob is the fee to complete // Difference between hop and first item in blob is the fee to complete
Amount CreditsAmount Amount CreditsAmount
//RefundContext is for payment cancellation // RefundContext is for payment cancellation
//TODO (j): not currently in use, add later // TODO (j): not currently in use, add later
RefundContext HTLCKey RefundContext HTLCKey
//Contract Type // Contract Type
//first 4 bits is n, second for is m, in n-of-m "multisig" // first 4 bits is n, second for is m, in n-of-m "multisig"
ContractType uint8 ContractType uint8
//Redemption Hashes // Redemption Hashes
RedemptionHashes []*[20]byte RedemptionHashes []*[20]byte
//Data to parse&pass on to the next node // Data to parse&pass on to the next node
//Eventually, we need to make this into a group of 2 nested structs? // Eventually, we need to make this into a group of 2 nested structs?
Blob []byte Blob []byte
} }
func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error { func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//HTLCKey(8) // HTLCKey(8)
//Expiry(4) // Expiry(4)
//Amount(4) // Amount(4)
//ContractType(1) // ContractType(1)
//RedemptionHashes (numOfHashes * 20 + numOfHashes) // RedemptionHashes (numOfHashes * 20 + numOfHashes)
//Blob(2+blobsize) // Blob(2+blobsize)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -61,13 +61,13 @@ func (c *HTLCAddRequest) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCAddRequest // Creates a new HTLCAddRequest
func NewHTLCAddRequest() *HTLCAddRequest { func NewHTLCAddRequest() *HTLCAddRequest {
return &HTLCAddRequest{} return &HTLCAddRequest{}
} }
//Serializes the item from the HTLCAddRequest struct // Serializes the item from the HTLCAddRequest struct
//Writes the data to w // Writes the data to w
func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error { func (c *HTLCAddRequest) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -90,19 +90,19 @@ func (c *HTLCAddRequest) Command() uint32 {
} }
func (c *HTLCAddRequest) MaxPayloadLength(uint32) uint32 { func (c *HTLCAddRequest) MaxPayloadLength(uint32) uint32 {
//base size ~110, but blob can be variable. // base size ~110, but blob can be variable.
//shouldn't be bigger than 8K though... // shouldn't be bigger than 8K though...
return 8192 return 8192
} }
//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)
func (c *HTLCAddRequest) Validate() error { func (c *HTLCAddRequest) Validate() error {
if c.Amount < 0 { if c.Amount < 0 {
//While fees can be negative, it's too confusing to allow // While fees can be negative, it's too confusing to allow
//negative payments. Maybe for some wallets, but not this one! // negative payments. Maybe for some wallets, but not this one!
return fmt.Errorf("Amount paid cannot be negative.") return fmt.Errorf("Amount paid cannot be negative.")
} }
//We're good! // We're good!
return nil return nil
} }

@ -5,7 +5,7 @@ import (
) )
var ( var (
//Need to to do this here // Need to to do this here
_ = copy(revocationHash[:], revocationHashBytes) _ = copy(revocationHash[:], revocationHashBytes)
_ = copy(redemptionHash[:], redemptionHashBytes) _ = copy(redemptionHash[:], redemptionHashBytes)
emptyRedemptionHashes = []*[20]byte{} emptyRedemptionHashes = []*[20]byte{}
@ -26,19 +26,19 @@ var (
) )
func TestHTLCAddRequestEncodeDecode(t *testing.T) { func TestHTLCAddRequestEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcAddRequest, htlcAddRequestSerializedString, filename) s := SerializeTest(t, htlcAddRequest, htlcAddRequestSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCAddRequest() newMessage := NewHTLCAddRequest()
DeserializeTest(t, s, newMessage, htlcAddRequest) DeserializeTest(t, s, newMessage, htlcAddRequest)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcAddRequest, htlcAddRequestSerializedMessage) MessageSerializeDeserializeTest(t, htlcAddRequest, htlcAddRequestSerializedMessage)
} }

@ -5,19 +5,19 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type HTLCSettleAccept struct { type HTLCSettleAccept struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//ID of this request // ID of this request
HTLCKey HTLCKey HTLCKey HTLCKey
} }
func (c *HTLCSettleAccept) Decode(r io.Reader, pver uint32) error { func (c *HTLCSettleAccept) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//HTLCKey(8) // HTLCKey(8)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -29,13 +29,13 @@ func (c *HTLCSettleAccept) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCSettleAccept // Creates a new HTLCSettleAccept
func NewHTLCSettleAccept() *HTLCSettleAccept { func NewHTLCSettleAccept() *HTLCSettleAccept {
return &HTLCSettleAccept{} return &HTLCSettleAccept{}
} }
//Serializes the item from the HTLCSettleAccept struct // Serializes the item from the HTLCSettleAccept struct
//Writes the data to w // Writes the data to w
func (c *HTLCSettleAccept) Encode(w io.Writer, pver uint32) error { func (c *HTLCSettleAccept) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -53,13 +53,13 @@ func (c *HTLCSettleAccept) Command() uint32 {
} }
func (c *HTLCSettleAccept) MaxPayloadLength(uint32) uint32 { func (c *HTLCSettleAccept) MaxPayloadLength(uint32) uint32 {
//16 // 16
return 16 return 16
} }
//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)
func (c *HTLCSettleAccept) Validate() error { func (c *HTLCSettleAccept) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -14,19 +14,19 @@ var (
) )
func TestHTLCSettleAcceptEncodeDecode(t *testing.T) { func TestHTLCSettleAcceptEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcSettleAccept, htlcSettleAcceptSerializedString, filename) s := SerializeTest(t, htlcSettleAccept, htlcSettleAcceptSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCSettleAccept() newMessage := NewHTLCSettleAccept()
DeserializeTest(t, s, newMessage, htlcSettleAccept) DeserializeTest(t, s, newMessage, htlcSettleAccept)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcSettleAccept, htlcSettleAcceptSerializedMessage) MessageSerializeDeserializeTest(t, htlcSettleAccept, htlcSettleAcceptSerializedMessage)
} }

@ -5,28 +5,28 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type HTLCSettleRequest struct { type HTLCSettleRequest struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//ID of this request // ID of this request
HTLCKey HTLCKey HTLCKey HTLCKey
//Redemption Proofs (R-Values) // Redemption Proofs (R-Values)
RedemptionProofs []*[20]byte RedemptionProofs []*[20]byte
} }
func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error { func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//HTLCKey(8) // HTLCKey(8)
//Expiry(4) // Expiry(4)
//Amount(4) // Amount(4)
//NextHop(20) // NextHop(20)
//ContractType(1) // ContractType(1)
//RedemptionHashes (numOfHashes * 20 + numOfHashes) // RedemptionHashes (numOfHashes * 20 + numOfHashes)
//Blob(2+blobsize) // Blob(2+blobsize)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -39,13 +39,13 @@ func (c *HTLCSettleRequest) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCSettleRequest // Creates a new HTLCSettleRequest
func NewHTLCSettleRequest() *HTLCSettleRequest { func NewHTLCSettleRequest() *HTLCSettleRequest {
return &HTLCSettleRequest{} return &HTLCSettleRequest{}
} }
//Serializes the item from the HTLCSettleRequest struct // Serializes the item from the HTLCSettleRequest struct
//Writes the data to w // Writes the data to w
func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error { func (c *HTLCSettleRequest) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -64,13 +64,13 @@ func (c *HTLCSettleRequest) Command() uint32 {
} }
func (c *HTLCSettleRequest) MaxPayloadLength(uint32) uint32 { func (c *HTLCSettleRequest) MaxPayloadLength(uint32) uint32 {
//21*15+16 // 21*15+16
return 331 return 331
} }
//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)
func (c *HTLCSettleRequest) Validate() error { func (c *HTLCSettleRequest) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -5,7 +5,7 @@ import (
) )
var ( var (
//Need to to do this here // Need to to do this here
_ = copy(redemptionHash[:], redemptionHashBytes) _ = copy(redemptionHash[:], redemptionHashBytes)
emptyRedemptionProofs = []*[20]byte{} emptyRedemptionProofs = []*[20]byte{}
redemptionProofs = append(emptyRedemptionProofs, &redemptionHash) redemptionProofs = append(emptyRedemptionProofs, &redemptionHash)
@ -20,19 +20,19 @@ var (
) )
func TestHTLCSettleRequestEncodeDecode(t *testing.T) { func TestHTLCSettleRequestEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcSettleRequest, htlcSettleRequestSerializedString, filename) s := SerializeTest(t, htlcSettleRequest, htlcSettleRequestSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCSettleRequest() newMessage := NewHTLCSettleRequest()
DeserializeTest(t, s, newMessage, htlcSettleRequest) DeserializeTest(t, s, newMessage, htlcSettleRequest)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcSettleRequest, htlcSettleRequestSerializedMessage) MessageSerializeDeserializeTest(t, htlcSettleRequest, htlcSettleRequestSerializedMessage)
} }

@ -5,19 +5,19 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type HTLCTimeoutAccept struct { type HTLCTimeoutAccept struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//ID of this request // ID of this request
HTLCKey HTLCKey HTLCKey HTLCKey
} }
func (c *HTLCTimeoutAccept) Decode(r io.Reader, pver uint32) error { func (c *HTLCTimeoutAccept) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//HTLCKey(8) // HTLCKey(8)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -29,13 +29,13 @@ func (c *HTLCTimeoutAccept) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCTimeoutAccept // Creates a new HTLCTimeoutAccept
func NewHTLCTimeoutAccept() *HTLCTimeoutAccept { func NewHTLCTimeoutAccept() *HTLCTimeoutAccept {
return &HTLCTimeoutAccept{} return &HTLCTimeoutAccept{}
} }
//Serializes the item from the HTLCTimeoutAccept struct // Serializes the item from the HTLCTimeoutAccept struct
//Writes the data to w // Writes the data to w
func (c *HTLCTimeoutAccept) Encode(w io.Writer, pver uint32) error { func (c *HTLCTimeoutAccept) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -53,13 +53,13 @@ func (c *HTLCTimeoutAccept) Command() uint32 {
} }
func (c *HTLCTimeoutAccept) MaxPayloadLength(uint32) uint32 { func (c *HTLCTimeoutAccept) MaxPayloadLength(uint32) uint32 {
//16 // 16
return 16 return 16
} }
//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)
func (c *HTLCTimeoutAccept) Validate() error { func (c *HTLCTimeoutAccept) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -14,19 +14,19 @@ var (
) )
func TestHTLCTimeoutAcceptEncodeDecode(t *testing.T) { func TestHTLCTimeoutAcceptEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcTimeoutAccept, htlcTimeoutAcceptSerializedString, filename) s := SerializeTest(t, htlcTimeoutAccept, htlcTimeoutAcceptSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCTimeoutAccept() newMessage := NewHTLCTimeoutAccept()
DeserializeTest(t, s, newMessage, htlcTimeoutAccept) DeserializeTest(t, s, newMessage, htlcTimeoutAccept)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcTimeoutAccept, htlcTimeoutAcceptSerializedMessage) MessageSerializeDeserializeTest(t, htlcTimeoutAccept, htlcTimeoutAcceptSerializedMessage)
} }

@ -5,19 +5,19 @@ import (
"io" "io"
) )
//Multiple Clearing Requests are possible by putting this inside an array of // Multiple Clearing Requests are possible by putting this inside an array of
//clearing requests // clearing requests
type HTLCTimeoutRequest struct { type HTLCTimeoutRequest struct {
//We can use a different data type for this if necessary... // We can use a different data type for this if necessary...
ChannelID uint64 ChannelID uint64
//ID of this request // ID of this request
HTLCKey HTLCKey HTLCKey HTLCKey
} }
func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error { func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
//ChannelID(8) // ChannelID(8)
//HTLCKey(8) // HTLCKey(8)
err := readElements(r, err := readElements(r,
&c.ChannelID, &c.ChannelID,
&c.HTLCKey, &c.HTLCKey,
@ -29,13 +29,13 @@ func (c *HTLCTimeoutRequest) Decode(r io.Reader, pver uint32) error {
return nil return nil
} }
//Creates a new HTLCTimeoutRequest // Creates a new HTLCTimeoutRequest
func NewHTLCTimeoutRequest() *HTLCTimeoutRequest { func NewHTLCTimeoutRequest() *HTLCTimeoutRequest {
return &HTLCTimeoutRequest{} return &HTLCTimeoutRequest{}
} }
//Serializes the item from the HTLCTimeoutRequest struct // Serializes the item from the HTLCTimeoutRequest struct
//Writes the data to w // Writes the data to w
func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error { func (c *HTLCTimeoutRequest) Encode(w io.Writer, pver uint32) error {
err := writeElements(w, err := writeElements(w,
c.ChannelID, c.ChannelID,
@ -53,13 +53,13 @@ func (c *HTLCTimeoutRequest) Command() uint32 {
} }
func (c *HTLCTimeoutRequest) MaxPayloadLength(uint32) uint32 { func (c *HTLCTimeoutRequest) MaxPayloadLength(uint32) uint32 {
//16 // 16
return 16 return 16
} }
//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)
func (c *HTLCTimeoutRequest) Validate() error { func (c *HTLCTimeoutRequest) Validate() error {
//We're good! // We're good!
return nil return nil
} }

@ -14,19 +14,19 @@ var (
) )
func TestHTLCTimeoutRequestEncodeDecode(t *testing.T) { func TestHTLCTimeoutRequestEncodeDecode(t *testing.T) {
//All of these types being passed are of the message interface type // All of these types being passed are of the message interface type
//Test serialization, runs: message.Encode(b, 0) // Test serialization, runs: message.Encode(b, 0)
//Returns bytes // Returns bytes
//Compares the expected serialized string from the original // Compares the expected serialized string from the original
s := SerializeTest(t, htlcTimeoutRequest, htlcTimeoutRequestSerializedString, filename) s := SerializeTest(t, htlcTimeoutRequest, htlcTimeoutRequestSerializedString, filename)
//Test deserialization, runs: message.Decode(s, 0) // Test deserialization, runs: message.Decode(s, 0)
//Makes sure the deserialized struct is the same as the original // Makes sure the deserialized struct is the same as the original
newMessage := NewHTLCTimeoutRequest() newMessage := NewHTLCTimeoutRequest()
DeserializeTest(t, s, newMessage, htlcTimeoutRequest) DeserializeTest(t, s, newMessage, htlcTimeoutRequest)
//Test message using Message interface // Test message using Message interface
//Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3) // Serializes into buf: WriteMessage(buf, message, uint32(1), wire.TestNet3)
//Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3) // Deserializes into msg: _, msg, _ , err := ReadMessage(buf, uint32(1), wire.TestNet3)
MessageSerializeDeserializeTest(t, htlcTimeoutRequest, htlcTimeoutRequestSerializedMessage) MessageSerializeDeserializeTest(t, htlcTimeoutRequest, htlcTimeoutRequestSerializedMessage)
} }

@ -13,31 +13,31 @@ import (
var MAX_SLICE_LENGTH = 65535 var MAX_SLICE_LENGTH = 65535
//Actual pkScript, not redeemScript // Actual pkScript, not redeemScript
type PkScript []byte type PkScript []byte
type HTLCKey uint64 type HTLCKey uint64
type CommitHeight uint64 type CommitHeight uint64
//Subsatoshi amount (Micro-Satoshi, 1/1000th) // Subsatoshi amount (Micro-Satoshi, 1/1000th)
//Should be a signed int to account for negative fees // Should be a signed int to account for negative fees
// //
//"In any science-fiction movie, anywhere in the galaxy, currency is referred // "In any science-fiction movie, anywhere in the galaxy, currency is referred
//to as 'credits.'" // to as 'credits.'"
// --Sam Humphries. Ebert, Roger (1999). Ebert's bigger little movie // --Sam Humphries. Ebert, Roger (1999). Ebert's bigger little movie
// glossary. Andrews McMeel. p. 172. // glossary. Andrews McMeel. p. 172.
// //
//https://en.wikipedia.org/wiki/List_of_fictional_currencies // https:// en.wikipedia.org/wiki/List_of_fictional_currencies
//https://en.wikipedia.org/wiki/Fictional_currency#Trends_in_the_use_of_fictional_currencies // https:// en.wikipedia.org/wiki/Fictional_currency#Trends_in_the_use_of_fictional_currencies
//http://tvtropes.org/pmwiki/pmwiki.php/Main/WeWillSpendCreditsInTheFuture // http:// tvtropes.org/pmwiki/pmwiki.php/Main/WeWillSpendCreditsInTheFuture
type CreditsAmount int32 //Credits (XCB, accountants should use XCB :^) type CreditsAmount int32 // Credits (XCB, accountants should use XCB :^)
//US Display format: 1 BTC = 100,000,000'000 XCB // US Display format: 1 BTC = 100,000,000'000 XCB
//Or in BTC = 1.00000000'000 // Or in BTC = 1.00000000'000
//Writes the big endian representation of element // Writes the big endian representation of element
//Unified function to call when writing different types // Unified function to call when writing different types
//Pre-allocate a byte-array of the correct size for cargo-cult security // Pre-allocate a byte-array of the correct size for cargo-cult security
//More copies but whatever... // More copies but whatever...
func writeElement(w io.Writer, element interface{}) error { func writeElement(w io.Writer, element interface{}) error {
var err error var err error
switch e := element.(type) { switch e := element.(type) {
@ -107,12 +107,12 @@ func writeElement(w io.Writer, element interface{}) error {
if numItems > 65535 { if numItems > 65535 {
return fmt.Errorf("Too many []uint64s") return fmt.Errorf("Too many []uint64s")
} }
//Write the size // Write the size
err = writeElement(w, uint16(numItems)) err = writeElement(w, uint16(numItems))
if err != nil { if err != nil {
return err return err
} }
//Write the data // Write the data
for i := 0; i < numItems; i++ { for i := 0; i < numItems; i++ {
err = writeElement(w, e[i]) err = writeElement(w, e[i])
if err != nil { if err != nil {
@ -125,12 +125,12 @@ func writeElement(w io.Writer, element interface{}) error {
if numSigs > 127 { if numSigs > 127 {
return fmt.Errorf("Too many signatures!") return fmt.Errorf("Too many signatures!")
} }
//Write the size // Write the size
err = writeElement(w, uint8(numSigs)) err = writeElement(w, uint8(numSigs))
if err != nil { if err != nil {
return err return err
} }
//Write the data // Write the data
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
err = writeElement(w, e[i]) err = writeElement(w, e[i])
if err != nil { if err != nil {
@ -144,12 +144,12 @@ func writeElement(w io.Writer, element interface{}) error {
if sigLength > 73 { if sigLength > 73 {
return fmt.Errorf("Signature too long!") return fmt.Errorf("Signature too long!")
} }
//Write the size // Write the size
err = writeElement(w, uint8(sigLength)) err = writeElement(w, uint8(sigLength))
if err != nil { if err != nil {
return err return err
} }
//Write the data // Write the data
_, err = w.Write(sig) _, err = w.Write(sig)
if err != nil { if err != nil {
return err return err
@ -162,13 +162,13 @@ func writeElement(w io.Writer, element interface{}) error {
} }
return nil return nil
case []*[20]byte: case []*[20]byte:
//Get size of slice and dump in slice // Get size of slice and dump in slice
sliceSize := len(e) sliceSize := len(e)
err = writeElement(w, uint16(sliceSize)) err = writeElement(w, uint16(sliceSize))
if err != nil { if err != nil {
return err return err
} }
//Write in each sequentially // Write in each sequentially
for _, element := range e { for _, element := range e {
err = writeElement(w, &element) err = writeElement(w, &element)
if err != nil { if err != nil {
@ -200,12 +200,12 @@ func writeElement(w io.Writer, element interface{}) error {
if sliceLength > MAX_SLICE_LENGTH { if sliceLength > MAX_SLICE_LENGTH {
return fmt.Errorf("Slice length too long!") return fmt.Errorf("Slice length too long!")
} }
//Write the size // Write the size
err = writeElement(w, uint16(sliceLength)) err = writeElement(w, uint16(sliceLength))
if err != nil { if err != nil {
return err return err
} }
//Write the data // Write the data
_, err = w.Write(e) _, err = w.Write(e)
if err != nil { if err != nil {
return err return err
@ -213,16 +213,16 @@ func writeElement(w io.Writer, element interface{}) error {
return nil return nil
case PkScript: case PkScript:
scriptLength := len(e) scriptLength := len(e)
//Make sure it's P2PKH or P2SH size or less // Make sure it's P2PKH or P2SH size or less
if scriptLength > 25 { if scriptLength > 25 {
return fmt.Errorf("PkScript too long!") return fmt.Errorf("PkScript too long!")
} }
//Write the size (1-byte) // Write the size (1-byte)
err = writeElement(w, uint8(scriptLength)) err = writeElement(w, uint8(scriptLength))
if err != nil { if err != nil {
return err return err
} }
//Write the data // Write the data
_, err = w.Write(e) _, err = w.Write(e)
if err != nil { if err != nil {
return err return err
@ -233,19 +233,19 @@ func writeElement(w io.Writer, element interface{}) error {
if strlen > 65535 { if strlen > 65535 {
return fmt.Errorf("String too long!") return fmt.Errorf("String too long!")
} }
//Write the size (2-bytes) // Write the size (2-bytes)
err = writeElement(w, uint16(strlen)) err = writeElement(w, uint16(strlen))
if err != nil { if err != nil {
return err return err
} }
//Write the data // Write the data
_, err = w.Write([]byte(e)) _, err = w.Write([]byte(e))
if err != nil { if err != nil {
return err return err
} }
case []*wire.TxIn: case []*wire.TxIn:
//Append the unsigned(!!!) txins // Append the unsigned(!!!) txins
//Write the size (1-byte) // Write the size (1-byte)
if len(e) > 127 { if len(e) > 127 {
return fmt.Errorf("Too many txins") return fmt.Errorf("Too many txins")
} }
@ -253,8 +253,8 @@ func writeElement(w io.Writer, element interface{}) error {
if err != nil { if err != nil {
return err return err
} }
//Append the actual TxIns (Size: NumOfTxins * 36) // Append the actual TxIns (Size: NumOfTxins * 36)
//Do not include the sequence number to eliminate funny business // Do not include the sequence number to eliminate funny business
for _, in := range e { for _, in := range e {
err = writeElement(w, in) err = writeElement(w, in)
if err != nil { if err != nil {
@ -263,14 +263,14 @@ func writeElement(w io.Writer, element interface{}) error {
} }
return nil return nil
case *wire.TxIn: case *wire.TxIn:
//Hash // Hash
var h [32]byte var h [32]byte
copy(h[:], e.PreviousOutPoint.Hash.Bytes()) copy(h[:], e.PreviousOutPoint.Hash.Bytes())
_, err = w.Write(h[:]) _, err = w.Write(h[:])
if err != nil { if err != nil {
return err return err
} }
//Index // Index
var idx [4]byte var idx [4]byte
binary.BigEndian.PutUint32(idx[:], e.PreviousOutPoint.Index) binary.BigEndian.PutUint32(idx[:], e.PreviousOutPoint.Index)
_, err = w.Write(idx[:]) _, err = w.Write(idx[:])
@ -381,11 +381,11 @@ func readElement(r io.Reader, element interface{}) error {
if err != nil { if err != nil {
return err return err
} }
//if numItems > 65535 { // if numItems > 65535 {
// return fmt.Errorf("Too many items in []uint64") // return fmt.Errorf("Too many items in []uint64")
//} // }
//Read the number of items // Read the number of items
var items []uint64 var items []uint64
for i := uint16(0); i < numItems; i++ { for i := uint16(0); i < numItems; i++ {
var item uint64 var item uint64
@ -407,7 +407,7 @@ func readElement(r io.Reader, element interface{}) error {
return fmt.Errorf("Too many signatures!") return fmt.Errorf("Too many signatures!")
} }
//Read that number of signatures // Read that number of signatures
var sigs []*btcec.Signature var sigs []*btcec.Signature
for i := uint8(0); i < numSigs; i++ { for i := uint8(0); i < numSigs; i++ {
sig := new(btcec.Signature) sig := new(btcec.Signature)
@ -430,7 +430,7 @@ func readElement(r io.Reader, element interface{}) error {
return fmt.Errorf("Signature too long!") return fmt.Errorf("Signature too long!")
} }
//Read the sig length // Read the sig length
l := io.LimitReader(r, int64(sigLength)) l := io.LimitReader(r, int64(sigLength))
sig, err := ioutil.ReadAll(l) sig, err := ioutil.ReadAll(l)
if err != nil { if err != nil {
@ -446,14 +446,14 @@ func readElement(r io.Reader, element interface{}) error {
*e = &*btcecSig *e = &*btcecSig
return nil return nil
case *[]*[20]byte: case *[]*[20]byte:
//How many to read // How many to read
var sliceSize uint16 var sliceSize uint16
err = readElement(r, &sliceSize) err = readElement(r, &sliceSize)
if err != nil { if err != nil {
return err return err
} }
var data []*[20]byte var data []*[20]byte
//Append the actual // Append the actual
for i := uint16(0); i < sliceSize; i++ { for i := uint16(0); i < sliceSize; i++ {
var element [20]byte var element [20]byte
err = readElement(r, &element) err = readElement(r, &element)
@ -479,20 +479,20 @@ func readElement(r io.Reader, element interface{}) error {
*e = wire.BitcoinNet(binary.BigEndian.Uint32(b[:])) *e = wire.BitcoinNet(binary.BigEndian.Uint32(b[:]))
return nil return nil
case *[]byte: case *[]byte:
//Get the blob length first // Get the blob length first
var blobLength uint16 var blobLength uint16
err = readElement(r, &blobLength) err = readElement(r, &blobLength)
if err != nil { if err != nil {
return err return err
} }
//Shouldn't need to do this, since it's uint16, but we // Shouldn't need to do this, since it's uint16, but we
//might have a different value for MAX_SLICE_LENGTH... // might have a different value for MAX_SLICE_LENGTH...
if int(blobLength) > MAX_SLICE_LENGTH { if int(blobLength) > MAX_SLICE_LENGTH {
return fmt.Errorf("Slice length too long!") return fmt.Errorf("Slice length too long!")
} }
//Read the slice length // Read the slice length
l := io.LimitReader(r, int64(blobLength)) l := io.LimitReader(r, int64(blobLength))
*e, err = ioutil.ReadAll(l) *e, err = ioutil.ReadAll(l)
if err != nil { if err != nil {
@ -503,7 +503,7 @@ func readElement(r io.Reader, element interface{}) error {
} }
return nil return nil
case *PkScript: case *PkScript:
//Get the script length first // Get the script length first
var scriptLength uint8 var scriptLength uint8
err = readElement(r, &scriptLength) err = readElement(r, &scriptLength)
if err != nil { if err != nil {
@ -514,7 +514,7 @@ func readElement(r io.Reader, element interface{}) error {
return fmt.Errorf("PkScript too long!") return fmt.Errorf("PkScript too long!")
} }
//Read the script length // Read the script length
l := io.LimitReader(r, int64(scriptLength)) l := io.LimitReader(r, int64(scriptLength))
*e, err = ioutil.ReadAll(l) *e, err = ioutil.ReadAll(l)
if err != nil { if err != nil {
@ -525,13 +525,13 @@ func readElement(r io.Reader, element interface{}) error {
} }
return nil return nil
case *string: case *string:
//Get the string length first // Get the string length first
var strlen uint16 var strlen uint16
err = readElement(r, &strlen) err = readElement(r, &strlen)
if err != nil { if err != nil {
return err return err
} }
//Read the string for the length // Read the string for the length
l := io.LimitReader(r, int64(strlen)) l := io.LimitReader(r, int64(strlen))
b, err := ioutil.ReadAll(l) b, err := ioutil.ReadAll(l)
if len(b) != int(strlen) { if len(b) != int(strlen) {
@ -543,7 +543,7 @@ func readElement(r io.Reader, element interface{}) error {
} }
return nil return nil
case *[]*wire.TxIn: case *[]*wire.TxIn:
//Read the size (1-byte number of txins) // Read the size (1-byte number of txins)
var numScripts uint8 var numScripts uint8
err = readElement(r, &numScripts) err = readElement(r, &numScripts)
if err != nil { if err != nil {
@ -553,7 +553,7 @@ func readElement(r io.Reader, element interface{}) error {
return fmt.Errorf("Too many txins") return fmt.Errorf("Too many txins")
} }
//Append the actual TxIns // Append the actual TxIns
var txins []*wire.TxIn var txins []*wire.TxIn
for i := uint8(0); i < numScripts; i++ { for i := uint8(0); i < numScripts; i++ {
outpoint := new(wire.OutPoint) outpoint := new(wire.OutPoint)
@ -567,7 +567,7 @@ func readElement(r io.Reader, element interface{}) error {
*e = *&txins *e = *&txins
return nil return nil
case **wire.TxIn: case **wire.TxIn:
//Hash // Hash
var h [32]byte var h [32]byte
_, err = io.ReadFull(r, h[:]) _, err = io.ReadFull(r, h[:])
if err != nil { if err != nil {
@ -578,7 +578,7 @@ func readElement(r io.Reader, element interface{}) error {
return err return err
} }
(*e).PreviousOutPoint.Hash = *hash (*e).PreviousOutPoint.Hash = *hash
//Index // Index
var idxBytes [4]byte var idxBytes [4]byte
_, err = io.ReadFull(r, idxBytes[:]) _, err = io.ReadFull(r, idxBytes[:])
if err != nil { if err != nil {
@ -603,31 +603,31 @@ func readElements(r io.Reader, elements ...interface{}) error {
return nil return nil
} }
//Validates whether a PkScript byte array is P2SH or P2PKH // Validates whether a PkScript byte array is P2SH or P2PKH
func ValidatePkScript(pkScript PkScript) error { func ValidatePkScript(pkScript PkScript) error {
if &pkScript == nil { if &pkScript == nil {
return fmt.Errorf("PkScript should not be empty!") return fmt.Errorf("PkScript should not be empty!")
} }
if len(pkScript) == 25 { if len(pkScript) == 25 {
//P2PKH // P2PKH
//Begins with OP_DUP OP_HASH160 PUSHDATA(20) // Begins with OP_DUP OP_HASH160 PUSHDATA(20)
if !bytes.Equal(pkScript[0:3], []byte{118, 169, 20}) || if !bytes.Equal(pkScript[0:3], []byte{118, 169, 20}) ||
//Ends with OP_EQUALVERIFY OP_CHECKSIG // Ends with OP_EQUALVERIFY OP_CHECKSIG
!bytes.Equal(pkScript[23:25], []byte{136, 172}) { !bytes.Equal(pkScript[23:25], []byte{136, 172}) {
//If it's not correct, return error // If it's not correct, return error
return fmt.Errorf("PkScript only allows P2SH or P2PKH") return fmt.Errorf("PkScript only allows P2SH or P2PKH")
} }
} else if len(pkScript) == 23 { } else if len(pkScript) == 23 {
//P2SH // P2SH
//Begins with OP_HASH160 PUSHDATA(20) // Begins with OP_HASH160 PUSHDATA(20)
if !bytes.Equal(pkScript[0:2], []byte{169, 20}) || if !bytes.Equal(pkScript[0:2], []byte{169, 20}) ||
//Ends with OP_EQUAL // Ends with OP_EQUAL
!bytes.Equal(pkScript[22:23], []byte{135}) { !bytes.Equal(pkScript[22:23], []byte{135}) {
//If it's not correct, return error // If it's not correct, return error
return fmt.Errorf("PkScript only allows P2SH or P2PKH") return fmt.Errorf("PkScript only allows P2SH or P2PKH")
} }
} else { } else {
//Length not 23 or 25 // Length not 23 or 25
return fmt.Errorf("PkScript only allows P2SH or P2PKH") return fmt.Errorf("PkScript only allows P2SH or P2PKH")
} }

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

@ -1,4 +1,4 @@
//Code derived from https://github.com/btcsuite/btcd/blob/master/wire/message.go // Code derived from https:// github.com/btcsuite/btcd/blob/master/wire/message.go
package lnwire package lnwire
import ( import (
@ -9,7 +9,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
) )
// message type identifyer bytes // message type identifyer bytes
const ( const (
MSGID_FUNDREQUEST = 0x30 MSGID_FUNDREQUEST = 0x30
MSGID_FUNDRESPONSE = 0x31 MSGID_FUNDRESPONSE = 0x31
@ -23,52 +23,52 @@ const (
MSGID_FWDAUTHREQ = 0x21 MSGID_FWDAUTHREQ = 0x21
) )
//4-byte network + 4-byte message id + payload-length 4-byte // 4-byte network + 4-byte message id + payload-length 4-byte
const MessageHeaderSize = 12 const MessageHeaderSize = 12
const MaxMessagePayload = 1024 * 1024 * 32 // 32MB const MaxMessagePayload = 1024 * 1024 * 32 // 32MB
const ( const (
//Funding channel open // Funding channel open
CmdFundingRequest = uint32(200) CmdFundingRequest = uint32(200)
CmdFundingResponse = uint32(210) CmdFundingResponse = uint32(210)
CmdFundingSignAccept = uint32(220) CmdFundingSignAccept = uint32(220)
CmdFundingSignComplete = uint32(230) CmdFundingSignComplete = uint32(230)
//Close channel // Close channel
CmdCloseRequest = uint32(300) CmdCloseRequest = uint32(300)
CmdCloseComplete = uint32(310) CmdCloseComplete = uint32(310)
//TODO Renumber to 1100 // TODO Renumber to 1100
//HTLC payment // HTLC payment
CmdHTLCAddRequest = uint32(1000) CmdHTLCAddRequest = uint32(1000)
CmdHTLCAddAccept = uint32(1010) CmdHTLCAddAccept = uint32(1010)
CmdHTLCAddReject = uint32(1020) CmdHTLCAddReject = uint32(1020)
//TODO Renumber to 1200 // TODO Renumber to 1200
//HTLC settlement // HTLC settlement
CmdHTLCSettleRequest = uint32(1100) CmdHTLCSettleRequest = uint32(1100)
CmdHTLCSettleAccept = uint32(1110) CmdHTLCSettleAccept = uint32(1110)
//HTLC timeout // HTLC timeout
CmdHTLCTimeoutRequest = uint32(1300) CmdHTLCTimeoutRequest = uint32(1300)
CmdHTLCTimeoutAccept = uint32(1310) CmdHTLCTimeoutAccept = uint32(1310)
//Commitments // Commitments
CmdCommitSignature = uint32(2000) CmdCommitSignature = uint32(2000)
CmdCommitRevocation = uint32(2010) CmdCommitRevocation = uint32(2010)
//Error // Error
CmdErrorGeneric = uint32(4000) CmdErrorGeneric = uint32(4000)
) )
//Every message has these functions: // Every message has these functions:
type Message interface { type Message interface {
Decode(io.Reader, uint32) error //(io, protocol version) Decode(io.Reader, uint32) error // (io, protocol version)
Encode(io.Writer, uint32) error //(io, protocol version) Encode(io.Writer, uint32) error // (io, protocol version)
Command() uint32 //returns ID of the message Command() uint32 // returns ID of the message
MaxPayloadLength(uint32) uint32 //(version) maxpayloadsize MaxPayloadLength(uint32) uint32 // (version) maxpayloadsize
Validate() error //Validates the data struct Validate() error // Validates the data struct
String() string String() string
} }
@ -116,10 +116,10 @@ func makeEmptyMessage(command uint32) (Message, error) {
} }
type messageHeader struct { type messageHeader struct {
//NOTE(j): We don't need to worry about the magic overlapping with // NOTE(j): We don't need to worry about the magic overlapping with
//bitcoin since this is inside encrypted comms anyway, but maybe we // bitcoin since this is inside encrypted comms anyway, but maybe we
//should use the XOR (^wire.TestNet3) just in case??? // should use the XOR (^wire.TestNet3) just in case???
magic wire.BitcoinNet //which Blockchain Technology(TM) to use magic wire.BitcoinNet // which Blockchain Technology(TM) to use
command uint32 command uint32
length uint32 length uint32
} }
@ -145,12 +145,12 @@ func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
return n, &hdr, nil return n, &hdr, nil
} }
// discardInput reads n bytes from reader r in chunks and discards the read // discardInput reads n bytes from reader r in chunks and discards the read
// bytes. This is used to skip payloads when various errors occur and helps // bytes. This is used to skip payloads when various errors occur and helps
// prevent rogue nodes from causing massive memory allocation through forging // prevent rogue nodes from causing massive memory allocation through forging
// header length. // header length.
func discardInput(r io.Reader, n uint32) { func discardInput(r io.Reader, n uint32) {
maxSize := uint32(10 * 1024) //10k at a time maxSize := uint32(10 * 1024) // 10k at a time
numReads := n / maxSize numReads := n / maxSize
bytesRemaining := n % maxSize bytesRemaining := n % maxSize
if n > 0 { if n > 0 {
@ -170,7 +170,7 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet wire.BitcoinNet)
cmd := msg.Command() cmd := msg.Command()
//Encode the message payload // Encode the message payload
var bw bytes.Buffer var bw bytes.Buffer
err := msg.Encode(&bw, pver) err := msg.Encode(&bw, pver)
if err != nil { if err != nil {
@ -179,37 +179,37 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet wire.BitcoinNet)
payload := bw.Bytes() payload := bw.Bytes()
lenp := len(payload) lenp := len(payload)
//Enforce maximum overall message payload // Enforce maximum overall message payload
if lenp > MaxMessagePayload { if lenp > MaxMessagePayload {
return totalBytes, fmt.Errorf("message payload is too large - encoded %d bytes, but maximum message payload is %d bytes", lenp, MaxMessagePayload) return totalBytes, fmt.Errorf("message payload is too large - encoded %d bytes, but maximum message payload is %d bytes", lenp, MaxMessagePayload)
} }
//Enforce maximum message payload on the message type // Enforce maximum message payload on the message type
mpl := msg.MaxPayloadLength(pver) mpl := msg.MaxPayloadLength(pver)
if uint32(lenp) > mpl { if uint32(lenp) > mpl {
return totalBytes, fmt.Errorf("message payload is too large - encoded %d bytes, but maximum message payload of type %x is %d bytes", lenp, cmd, mpl) return totalBytes, fmt.Errorf("message payload is too large - encoded %d bytes, but maximum message payload of type %x is %d bytes", lenp, cmd, mpl)
} }
//Create header for the message // Create header for the message
hdr := messageHeader{} hdr := messageHeader{}
hdr.magic = btcnet hdr.magic = btcnet
hdr.command = cmd hdr.command = cmd
hdr.length = uint32(lenp) hdr.length = uint32(lenp)
// Encode the header for the message. This is done to a buffer // Encode the header for the message. This is done to a buffer
// rather than directly to the writer since writeElements doesn't // rather than directly to the writer since writeElements doesn't
// return the number of bytes written. // return the number of bytes written.
hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize)) hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
writeElements(hw, hdr.magic, hdr.command, hdr.length) writeElements(hw, hdr.magic, hdr.command, hdr.length)
//Write header // Write header
n, err := w.Write(hw.Bytes()) n, err := w.Write(hw.Bytes())
totalBytes += n totalBytes += n
if err != nil { if err != nil {
return totalBytes, err return totalBytes, err
} }
//Write payload // Write payload
n, err = w.Write(payload) n, err = w.Write(payload)
totalBytes += n totalBytes += n
if err != nil { if err != nil {
@ -227,18 +227,18 @@ func ReadMessage(r io.Reader, pver uint32, btcnet wire.BitcoinNet) (int, Message
return totalBytes, nil, nil, err return totalBytes, nil, nil, err
} }
//Enforce maximum message payload // Enforce maximum message payload
if hdr.length > MaxMessagePayload { if hdr.length > MaxMessagePayload {
return totalBytes, nil, nil, fmt.Errorf("message payload is too large - header indicates %d bytes, but max message payload is %d bytes.", hdr.length, MaxMessagePayload) return totalBytes, nil, nil, fmt.Errorf("message payload is too large - header indicates %d bytes, but max message payload is %d bytes.", hdr.length, MaxMessagePayload)
} }
//Check for messages in the wrong bitcoin network // Check for messages in the wrong bitcoin network
if hdr.magic != btcnet { if hdr.magic != btcnet {
discardInput(r, hdr.length) discardInput(r, hdr.length)
return totalBytes, nil, nil, fmt.Errorf("message from other network [%v]", hdr.magic) return totalBytes, nil, nil, fmt.Errorf("message from other network [%v]", hdr.magic)
} }
//Create struct of appropriate message type based on the command // Create struct of appropriate message type based on the command
command := hdr.command command := hdr.command
msg, err := makeEmptyMessage(command) msg, err := makeEmptyMessage(command)
if err != nil { if err != nil {
@ -246,14 +246,14 @@ func ReadMessage(r io.Reader, pver uint32, btcnet wire.BitcoinNet) (int, Message
return totalBytes, nil, nil, fmt.Errorf("ReadMessage %s", err.Error()) return totalBytes, nil, nil, fmt.Errorf("ReadMessage %s", err.Error())
} }
//Check for maximum length based on the message type // Check for maximum length based on the message type
mpl := msg.MaxPayloadLength(pver) mpl := msg.MaxPayloadLength(pver)
if hdr.length > mpl { if hdr.length > mpl {
discardInput(r, hdr.length) discardInput(r, hdr.length)
return totalBytes, nil, nil, fmt.Errorf("payload exceeds max length. indicates %v bytes, but max of message type %v is %v.", hdr.length, command, mpl) return totalBytes, nil, nil, fmt.Errorf("payload exceeds max length. indicates %v bytes, but max of message type %v is %v.", hdr.length, command, mpl)
} }
//Read payload // Read payload
payload := make([]byte, hdr.length) payload := make([]byte, hdr.length)
n, err = io.ReadFull(r, payload) n, err = io.ReadFull(r, payload)
totalBytes += n totalBytes += n
@ -261,19 +261,19 @@ func ReadMessage(r io.Reader, pver uint32, btcnet wire.BitcoinNet) (int, Message
return totalBytes, nil, nil, err return totalBytes, nil, nil, err
} }
//Unmarshal message // Unmarshal message
pr := bytes.NewBuffer(payload) pr := bytes.NewBuffer(payload)
err = msg.Decode(pr, pver) err = msg.Decode(pr, pver)
if err != nil { if err != nil {
return totalBytes, nil, nil, err return totalBytes, nil, nil, err
} }
//Validate the data // Validate the data
err = msg.Validate() err = msg.Validate()
if err != nil { if err != nil {
return totalBytes, nil, nil, err return totalBytes, nil, nil, err
} }
//We're good! // We're good!
return totalBytes, msg, payload, nil return totalBytes, msg, payload, nil
} }