2015-12-30 16:38:57 +03:00
|
|
|
package lnwire
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2016-05-23 23:54:34 +03:00
|
|
|
"io"
|
|
|
|
|
2016-05-15 17:17:44 +03:00
|
|
|
"github.com/roasbeef/btcd/btcec"
|
|
|
|
"github.com/roasbeef/btcd/wire"
|
|
|
|
"github.com/roasbeef/btcutil"
|
2015-12-30 16:38:57 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type FundingResponse struct {
|
|
|
|
ChannelType uint8
|
|
|
|
|
|
|
|
ReservationID uint64
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
ResponderFundingAmount btcutil.Amount // Responder's funding amount
|
|
|
|
ResponderReserveAmount btcutil.Amount // Responder's reserve amount
|
|
|
|
MinFeePerKb btcutil.Amount // Lock-in min fee
|
2015-12-31 09:28:14 +03:00
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Minimum depth
|
2015-12-31 09:28:14 +03:00
|
|
|
MinDepth uint32
|
2015-12-30 16:38:57 +03:00
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// CLTV/CSV lock-time to use
|
2015-12-30 16:38:57 +03:00
|
|
|
LockTime uint32
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Who pays the fees
|
|
|
|
// 0: (default) channel initiator
|
|
|
|
// 1: split
|
|
|
|
// 2: channel responder
|
2015-12-30 16:38:57 +03:00
|
|
|
FeePayer uint8
|
|
|
|
|
|
|
|
RevocationHash [20]byte
|
|
|
|
Pubkey *btcec.PublicKey
|
2016-01-17 04:14:35 +03:00
|
|
|
CommitSig *btcec.Signature // Requester's Commitment
|
|
|
|
DeliveryPkScript PkScript // *MUST* be either P2PKH or P2SH
|
|
|
|
ChangePkScript PkScript // *MUST* be either P2PKH or P2SH
|
2015-12-30 16:38:57 +03:00
|
|
|
|
|
|
|
Inputs []*wire.TxIn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FundingResponse) Decode(r io.Reader, pver uint32) error {
|
2016-01-17 04:14:35 +03:00
|
|
|
// ReservationID (8)
|
|
|
|
// Channel Type (1)
|
|
|
|
// Funding Amount (8)
|
|
|
|
// Revocation Hash (20)
|
|
|
|
// Commitment Pubkey (32)
|
|
|
|
// Reserve Amount (8)
|
|
|
|
// Minimum Transaction Fee Per Kb (8)
|
|
|
|
// MinDepth (4)
|
|
|
|
// LockTime (4)
|
|
|
|
// FeePayer (1)
|
|
|
|
// DeliveryPkScript (final delivery)
|
|
|
|
// First byte length then pkscript
|
|
|
|
// ChangePkScript (change for extra from inputs)
|
|
|
|
// First byte length then pkscript
|
|
|
|
// CommitSig
|
|
|
|
// First byte length then sig
|
|
|
|
// Inputs: Create the TxIns
|
|
|
|
// First byte is number of inputs
|
|
|
|
// For each input, it's 32bytes txin & 4bytes index
|
2015-12-31 10:34:40 +03:00
|
|
|
err := readElements(r,
|
2015-12-30 16:38:57 +03:00
|
|
|
&c.ReservationID,
|
|
|
|
&c.ChannelType,
|
2015-12-31 09:28:14 +03:00
|
|
|
&c.ResponderFundingAmount,
|
2015-12-30 16:38:57 +03:00
|
|
|
&c.RevocationHash,
|
|
|
|
&c.Pubkey,
|
2015-12-31 09:28:14 +03:00
|
|
|
&c.ResponderReserveAmount,
|
2015-12-30 16:38:57 +03:00
|
|
|
&c.MinFeePerKb,
|
2015-12-31 09:28:14 +03:00
|
|
|
&c.MinDepth,
|
2015-12-30 16:38:57 +03:00
|
|
|
&c.LockTime,
|
|
|
|
&c.FeePayer,
|
|
|
|
&c.DeliveryPkScript,
|
|
|
|
&c.ChangePkScript,
|
|
|
|
&c.CommitSig,
|
|
|
|
&c.Inputs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Creates a new FundingResponse
|
2015-12-30 16:38:57 +03:00
|
|
|
func NewFundingResponse() *FundingResponse {
|
|
|
|
return &FundingResponse{}
|
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Serializes the item from the FundingResponse struct
|
|
|
|
// Writes the data to w
|
2015-12-30 16:38:57 +03:00
|
|
|
func (c *FundingResponse) Encode(w io.Writer, pver uint32) error {
|
2016-01-17 04:14:35 +03:00
|
|
|
// ReservationID (8)
|
|
|
|
// Channel Type (1)
|
|
|
|
// Funding Amount (8)
|
|
|
|
// Revocation Hash (20)
|
|
|
|
// Commitment Pubkey (32)
|
|
|
|
// Reserve Amount (8)
|
|
|
|
// Minimum Transaction Fee Per Kb (8)
|
|
|
|
// LockTime (4)
|
|
|
|
// FeePayer (1)
|
|
|
|
// DeliveryPkScript (final delivery)
|
|
|
|
// ChangePkScript (change for extra from inputs)
|
|
|
|
// CommitSig
|
|
|
|
// Inputs
|
2015-12-31 10:34:40 +03:00
|
|
|
err := writeElements(w,
|
2015-12-30 16:38:57 +03:00
|
|
|
c.ReservationID,
|
|
|
|
c.ChannelType,
|
2015-12-31 09:28:14 +03:00
|
|
|
c.ResponderFundingAmount,
|
2015-12-30 16:38:57 +03:00
|
|
|
c.RevocationHash,
|
|
|
|
c.Pubkey,
|
2015-12-31 09:28:14 +03:00
|
|
|
c.ResponderReserveAmount,
|
2015-12-30 16:38:57 +03:00
|
|
|
c.MinFeePerKb,
|
2015-12-31 09:28:14 +03:00
|
|
|
c.MinDepth,
|
2015-12-30 16:38:57 +03:00
|
|
|
c.LockTime,
|
|
|
|
c.FeePayer,
|
|
|
|
c.DeliveryPkScript,
|
|
|
|
c.ChangePkScript,
|
|
|
|
c.CommitSig,
|
|
|
|
c.Inputs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FundingResponse) Command() uint32 {
|
|
|
|
return CmdFundingResponse
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FundingResponse) MaxPayloadLength(uint32) uint32 {
|
2016-01-17 04:14:35 +03:00
|
|
|
// 86 (base size) + 26 (pkscript) + 26 (pkscript) + 74sig + 1 (numTxes) + 127*36(127 inputs * sha256+idx)
|
2015-12-31 09:28:14 +03:00
|
|
|
return 4785
|
2015-12-30 16:38:57 +03:00
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
|
2015-12-30 16:38:57 +03:00
|
|
|
func (c *FundingResponse) Validate() error {
|
2016-01-17 04:14:35 +03:00
|
|
|
// No negative values
|
2015-12-31 09:28:14 +03:00
|
|
|
if c.ResponderFundingAmount < 0 {
|
|
|
|
return fmt.Errorf("ResponderFundingAmount cannot be negative")
|
2015-12-30 16:38:57 +03:00
|
|
|
}
|
|
|
|
|
2015-12-31 09:28:14 +03:00
|
|
|
if c.ResponderReserveAmount < 0 {
|
|
|
|
return fmt.Errorf("ResponderReserveAmount cannot be negative")
|
2015-12-30 16:38:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if c.MinFeePerKb < 0 {
|
|
|
|
return fmt.Errorf("MinFeePerKb cannot be negative")
|
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Validation of what makes sense...
|
2015-12-31 09:28:14 +03:00
|
|
|
if c.ResponderFundingAmount < c.ResponderReserveAmount {
|
|
|
|
return fmt.Errorf("Reserve must be below Funding Amount")
|
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Make sure there's not more than 127 inputs
|
2015-12-31 09:28:14 +03:00
|
|
|
if len(c.Inputs) > 127 {
|
|
|
|
return fmt.Errorf("Too many inputs")
|
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Delivery PkScript is either P2SH or P2PKH
|
2016-05-23 23:54:34 +03:00
|
|
|
if !isValidPkScript(c.DeliveryPkScript) {
|
|
|
|
return fmt.Errorf("Valid delivery public key scripts MUST be: " +
|
|
|
|
"P2PKH, P2WKH, P2SH, or P2WSH.")
|
2015-12-30 16:38:57 +03:00
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// Change PkScript is either P2SH or P2PKH
|
2016-05-23 23:54:34 +03:00
|
|
|
if !isValidPkScript(c.ChangePkScript) {
|
|
|
|
// TODO(roasbeef): move into actual error
|
|
|
|
return fmt.Errorf("Valid change public key scripts MUST be: " +
|
|
|
|
"P2PKH, P2WKH, P2SH, or P2WSH.")
|
2015-12-30 16:38:57 +03:00
|
|
|
}
|
|
|
|
|
2016-01-17 04:14:35 +03:00
|
|
|
// We're good!
|
2015-12-30 16:38:57 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FundingResponse) String() string {
|
|
|
|
var inputs string
|
|
|
|
for i, in := range c.Inputs {
|
|
|
|
inputs += fmt.Sprintf("\n Slice\t%d\n", i)
|
2015-12-31 09:28:14 +03:00
|
|
|
if &in != nil {
|
|
|
|
inputs += fmt.Sprintf("\tHash\t%s\n", in.PreviousOutPoint.Hash)
|
|
|
|
inputs += fmt.Sprintf("\tIndex\t%d\n", in.PreviousOutPoint.Index)
|
|
|
|
}
|
2015-12-30 16:38:57 +03:00
|
|
|
}
|
2015-12-31 10:34:40 +03:00
|
|
|
|
|
|
|
var serializedPubkey []byte
|
|
|
|
if &c.Pubkey != nil && c.Pubkey.X != nil {
|
|
|
|
serializedPubkey = c.Pubkey.SerializeCompressed()
|
|
|
|
}
|
|
|
|
|
2015-12-30 16:38:57 +03:00
|
|
|
return fmt.Sprintf("\n--- Begin FundingResponse ---\n") +
|
2015-12-31 09:28:14 +03:00
|
|
|
fmt.Sprintf("ChannelType:\t\t\t%x\n", c.ChannelType) +
|
|
|
|
fmt.Sprintf("ReservationID:\t\t\t%d\n", c.ReservationID) +
|
|
|
|
fmt.Sprintf("ResponderFundingAmount:\t\t%s\n", c.ResponderFundingAmount.String()) +
|
|
|
|
fmt.Sprintf("ResponderReserveAmount:\t\t%s\n", c.ResponderReserveAmount.String()) +
|
|
|
|
fmt.Sprintf("MinFeePerKb:\t\t\t%s\n", c.MinFeePerKb.String()) +
|
|
|
|
fmt.Sprintf("MinDepth:\t\t\t%d\n", c.MinDepth) +
|
|
|
|
fmt.Sprintf("LockTime\t\t\t%d\n", c.LockTime) +
|
|
|
|
fmt.Sprintf("FeePayer\t\t\t%x\n", c.FeePayer) +
|
|
|
|
fmt.Sprintf("RevocationHash\t\t\t%x\n", c.RevocationHash) +
|
2015-12-31 10:34:40 +03:00
|
|
|
fmt.Sprintf("Pubkey\t\t\t\t%x\n", serializedPubkey) +
|
2015-12-31 09:28:14 +03:00
|
|
|
fmt.Sprintf("CommitSig\t\t\t%x\n", c.CommitSig.Serialize()) +
|
|
|
|
fmt.Sprintf("DeliveryPkScript\t\t%x\n", c.DeliveryPkScript) +
|
|
|
|
fmt.Sprintf("ChangePkScript\t\t%x\n", c.ChangePkScript) +
|
2015-12-30 16:38:57 +03:00
|
|
|
fmt.Sprintf("Inputs:") +
|
|
|
|
inputs +
|
|
|
|
fmt.Sprintf("--- End FundingResponse ---\n")
|
|
|
|
}
|