02a9b1e237
he didn't allow for multiple HTLCs. Gotta explain the rationale for that that... will merge the progress in the next commit tomorrow.
190 lines
4.8 KiB
Go
190 lines
4.8 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/btcsuite/btcd/btcec"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/btcsuite/btcutil"
|
|
"io"
|
|
)
|
|
|
|
type FundingRequest struct {
|
|
ChannelType uint8
|
|
|
|
FundingAmount btcutil.Amount
|
|
ReserveAmount btcutil.Amount
|
|
MinFeePerKb btcutil.Amount
|
|
|
|
//Should double-check the total funding later
|
|
MinTotalFundingAmount btcutil.Amount
|
|
|
|
//CLTV lock-time to use
|
|
LockTime uint32
|
|
|
|
//Who pays the fees
|
|
//0: (default) channel initiator
|
|
//1: split
|
|
//2: channel responder
|
|
FeePayer uint8
|
|
|
|
RevocationHash [20]byte
|
|
Pubkey *btcec.PublicKey
|
|
DeliveryPkScript PkScript //*MUST* be either P2PKH or P2SH
|
|
//FIXME: Need a ChangePkScript PkScript for dual-funder CLTV?
|
|
|
|
Inputs []*wire.TxIn
|
|
}
|
|
|
|
func (c *FundingRequest) Decode(r io.Reader, pver uint32) error {
|
|
//Channel Type (0/1)
|
|
// default to 0 for CLTV-only
|
|
//Funding Amount (1/8)
|
|
//Channel Minimum Capacity (9/8)
|
|
//Revocation Hash (17/20)
|
|
//Commitment Pubkey (37/32)
|
|
//Reserve Amount (69/8)
|
|
//Minimum Transaction Fee Per Kb (77/8)
|
|
//LockTime (85/4)
|
|
//FeePayer (89/1)
|
|
//DeliveryPkScript
|
|
// First byte length then pkscript
|
|
//Inputs: Create the TxIns
|
|
// First byte is number of inputs
|
|
// For each input, it's 32bytes txin & 4bytes index
|
|
err := readElements(r, false,
|
|
&c.ChannelType,
|
|
&c.FundingAmount,
|
|
&c.MinTotalFundingAmount,
|
|
&c.RevocationHash,
|
|
&c.Pubkey,
|
|
&c.ReserveAmount,
|
|
&c.MinFeePerKb,
|
|
&c.LockTime,
|
|
&c.FeePayer,
|
|
&c.DeliveryPkScript,
|
|
&c.Inputs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.Validate()
|
|
}
|
|
|
|
//Creates a new FundingRequest
|
|
func NewFundingRequest() *FundingRequest {
|
|
return &FundingRequest{}
|
|
}
|
|
|
|
//Serializes the item from the FundingRequest struct
|
|
//Writes the data to w
|
|
func (c *FundingRequest) Encode(w io.Writer, pver uint32) error {
|
|
//Channel Type
|
|
//Funding Amont
|
|
//Channel Minimum Capacity
|
|
//Revocation Hash
|
|
//Commitment Pubkey
|
|
//Reserve Amount
|
|
//Minimum Transaction Fee Per KB
|
|
//LockTime
|
|
//FeePayer
|
|
//DeliveryPkScript
|
|
//Inputs: Append the actual Txins
|
|
err := writeElements(w, false,
|
|
c.ChannelType,
|
|
c.FundingAmount,
|
|
c.MinTotalFundingAmount,
|
|
c.RevocationHash,
|
|
c.Pubkey,
|
|
c.ReserveAmount,
|
|
c.MinFeePerKb,
|
|
c.LockTime,
|
|
c.FeePayer,
|
|
c.DeliveryPkScript,
|
|
c.Inputs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *FundingRequest) Command() uint32 {
|
|
return CmdFundingRequest
|
|
}
|
|
|
|
func (c *FundingRequest) MaxPayloadLength(uint32) uint32 {
|
|
//90 (base size) + 26 (pkscript) + 1 (numTxes) + 127*36(127 inputs * sha256+idx)
|
|
//4690
|
|
return 4689
|
|
}
|
|
|
|
//Makes sure the struct data is valid (e.g. no negatives or invalid pkscripts)
|
|
func (c *FundingRequest) Validate() error {
|
|
//No negative values
|
|
if c.FundingAmount < 0 {
|
|
return fmt.Errorf("FundingAmount cannot be negative")
|
|
}
|
|
|
|
if c.ReserveAmount < 0 {
|
|
return fmt.Errorf("ReserveAmount cannot be negative")
|
|
}
|
|
|
|
if c.MinFeePerKb < 0 {
|
|
return fmt.Errorf("MinFeePerKb cannot be negative")
|
|
}
|
|
if c.MinTotalFundingAmount < 0 {
|
|
return fmt.Errorf("MinTotalFundingAmount cannot be negative")
|
|
}
|
|
|
|
//PkScript is either P2SH or P2PKH
|
|
if len(c.DeliveryPkScript) == 25 {
|
|
//P2PKH
|
|
//Begins with OP_DUP OP_HASH160 PUSHDATA(20)
|
|
if !bytes.Equal(c.DeliveryPkScript[0:3], []byte{118, 169, 20}) &&
|
|
//Ends with OP_EQUALVERIFY OP_CHECKSIG
|
|
!bytes.Equal(c.DeliveryPkScript[23:25], []byte{136, 172}) {
|
|
//If it's not correct, return error
|
|
return fmt.Errorf("PkScript only allows P2SH or P2PKH")
|
|
}
|
|
} else if len(c.DeliveryPkScript) == 23 {
|
|
//P2SH
|
|
//Begins with OP_HASH160 PUSHDATA(20)
|
|
if !bytes.Equal(c.DeliveryPkScript[0:2], []byte{169, 20}) &&
|
|
//Ends with OP_EQUAL
|
|
!bytes.Equal(c.DeliveryPkScript[22:23], []byte{135}) {
|
|
//If it's not correct, return error
|
|
return fmt.Errorf("PkScript only allows P2SH or P2PKH")
|
|
}
|
|
} else {
|
|
//Length not 23 or 25
|
|
return fmt.Errorf("PkScript only allows P2SH or P2PKH")
|
|
}
|
|
|
|
//We're good!
|
|
return nil
|
|
}
|
|
|
|
func (c *FundingRequest) String() string {
|
|
var inputs string
|
|
for i, in := range c.Inputs {
|
|
inputs += fmt.Sprintf("\n Slice\t%d\n", i)
|
|
inputs += fmt.Sprintf("\tHash\t%s\n", in.PreviousOutPoint.Hash)
|
|
inputs += fmt.Sprintf("\tIndex\t%d\n", in.PreviousOutPoint.Index)
|
|
}
|
|
return fmt.Sprintf("\n--- Begin FundingRequest ---\n") +
|
|
fmt.Sprintf("ChannelType:\t\t%x\n", c.ChannelType) +
|
|
fmt.Sprintf("FundingAmount:\t\t%s\n", c.FundingAmount.String()) +
|
|
fmt.Sprintf("ReserveAmount:\t\t%s\n", c.ReserveAmount.String()) +
|
|
fmt.Sprintf("MinFeePerKb:\t\t%s\n", c.MinFeePerKb.String()) +
|
|
fmt.Sprintf("MinTotalFundingAmount\t%s\n", c.MinTotalFundingAmount.String()) +
|
|
fmt.Sprintf("LockTime\t\t%d\n", c.LockTime) +
|
|
fmt.Sprintf("FeePayer\t\t%x\n", c.FeePayer) +
|
|
fmt.Sprintf("RevocationHash\t\t%x\n", c.RevocationHash) +
|
|
fmt.Sprintf("Pubkey\t\t\t%x\n", c.Pubkey.SerializeCompressed()) +
|
|
fmt.Sprintf("DeliveryPkScript\t%x\n", c.DeliveryPkScript) +
|
|
fmt.Sprintf("Inputs:") +
|
|
inputs +
|
|
fmt.Sprintf("--- End FundingRequest ---\n")
|
|
}
|