Skip to content

Commit

Permalink
Merge e8e8732 into 48be926
Browse files Browse the repository at this point in the history
  • Loading branch information
halseth committed Aug 11, 2017
2 parents 48be926 + e8e8732 commit 3568511
Show file tree
Hide file tree
Showing 7 changed files with 1,314 additions and 364 deletions.
149 changes: 4 additions & 145 deletions fundingmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,10 @@ import (
_ "github.com/roasbeef/btcwallet/walletdb/bdb"

"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/txscript"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
)

// The block height returned by the mock BlockChainIO's GetBestBlock.
const fundingBroadcastHeight = 123

var (
privPass = []byte("dummy-pass")

Expand Down Expand Up @@ -70,143 +66,6 @@ var (
}
)

// mockWalletController is used by the LightningWallet, and let us mock the
// interaction with the bitcoin network.
type mockWalletController struct {
rootKey *btcec.PrivateKey
prevAddres btcutil.Address
publishedTransactions chan *wire.MsgTx
}

// FetchInputInfo will be called to get info about the inputs to the funding
// transaction.
func (*mockWalletController) FetchInputInfo(
prevOut *wire.OutPoint) (*wire.TxOut, error) {
txOut := &wire.TxOut{
Value: int64(10 * btcutil.SatoshiPerBitcoin),
PkScript: []byte("dummy"),
}
return txOut, nil
}
func (*mockWalletController) ConfirmedBalance(confs int32,
witness bool) (btcutil.Amount, error) {
return 0, nil
}

// NewAddress is called to get new addresses for delivery, change etc.
func (m *mockWalletController) NewAddress(addrType lnwallet.AddressType,
change bool) (btcutil.Address, error) {
addr, _ := btcutil.NewAddressPubKey(
m.rootKey.PubKey().SerializeCompressed(), &chaincfg.MainNetParams)
return addr, nil
}
func (*mockWalletController) GetPrivKey(a btcutil.Address) (*btcec.PrivateKey, error) {
return nil, nil
}

// NewRawKey will be called to get keys to be used for the funding tx and the
// commitment tx.
func (m *mockWalletController) NewRawKey() (*btcec.PublicKey, error) {
return m.rootKey.PubKey(), nil
}

// FetchRootKey will be called to provide the wallet with a root key.
func (m *mockWalletController) FetchRootKey() (*btcec.PrivateKey, error) {
return m.rootKey, nil
}
func (*mockWalletController) SendOutputs(outputs []*wire.TxOut) (*chainhash.Hash, error) {
return nil, nil
}

// ListUnspentWitness is called by the wallet when doing coin selection. We just
// need one unspent for the funding transaction.
func (*mockWalletController) ListUnspentWitness(confirms int32) ([]*lnwallet.Utxo, error) {
utxo := &lnwallet.Utxo{
Value: btcutil.Amount(10 * btcutil.SatoshiPerBitcoin),
OutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0,
},
}
var ret []*lnwallet.Utxo
ret = append(ret, utxo)
return ret, nil
}
func (*mockWalletController) ListTransactionDetails() ([]*lnwallet.TransactionDetail, error) {
return nil, nil
}
func (*mockWalletController) LockOutpoint(o wire.OutPoint) {}
func (*mockWalletController) UnlockOutpoint(o wire.OutPoint) {}
func (m *mockWalletController) PublishTransaction(tx *wire.MsgTx) error {
m.publishedTransactions <- tx
return nil
}
func (*mockWalletController) SubscribeTransactions() (lnwallet.TransactionSubscription, error) {
return nil, nil
}
func (*mockWalletController) IsSynced() (bool, error) {
return true, nil
}
func (*mockWalletController) Start() error {
return nil
}
func (*mockWalletController) Stop() error {
return nil
}

type mockSigner struct {
key *btcec.PrivateKey
}

func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx,
signDesc *lnwallet.SignDescriptor) ([]byte, error) {
amt := signDesc.Output.Value
witnessScript := signDesc.WitnessScript
privKey := m.key

sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes,
signDesc.InputIndex, amt, witnessScript, txscript.SigHashAll,
privKey)
if err != nil {
return nil, err
}

return sig[:len(sig)-1], nil
}

func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx,
signDesc *lnwallet.SignDescriptor) (*lnwallet.InputScript, error) {
witnessScript, err := txscript.WitnessScript(tx, signDesc.SigHashes,
signDesc.InputIndex, signDesc.Output.Value,
signDesc.Output.PkScript, txscript.SigHashAll, m.key, true)
if err != nil {
return nil, err
}

return &lnwallet.InputScript{
Witness: witnessScript,
}, nil
}

type mockChainIO struct{}

func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) {
return activeNetParams.GenesisHash, fundingBroadcastHeight, nil
}

func (*mockChainIO) GetUtxo(op *wire.OutPoint,
heightHint uint32) (*wire.TxOut, error) {
return nil, nil
}

func (*mockChainIO) GetBlockHash(blockHeight int64) (*chainhash.Hash, error) {
return nil, nil
}

func (*mockChainIO) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error) {
return nil, nil
}

type mockNotifier struct {
confChannel chan *chainntnfs.TxConfirmation
epochChan chan *chainntnfs.BlockEpoch
Expand Down Expand Up @@ -250,7 +109,7 @@ type testNode struct {
testDir string
}

func disableLogger(t *testing.T) {
func disableFndgLogger(t *testing.T) {
channeldb.UseLogger(btclog.Disabled)
lnwallet.UseLogger(btclog.Disabled)
fndgLog = btclog.Disabled
Expand Down Expand Up @@ -652,7 +511,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
}

func TestFundingManagerNormalWorkflow(t *testing.T) {
disableLogger(t)
disableFndgLogger(t)

shutdownChannel := make(chan struct{})

Expand Down Expand Up @@ -860,7 +719,7 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
}

func TestFundingManagerRestartBehavior(t *testing.T) {
disableLogger(t)
disableFndgLogger(t)

shutdownChannel := make(chan struct{})

Expand Down Expand Up @@ -1095,7 +954,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
}

func TestFundingManagerFundingTimeout(t *testing.T) {
disableLogger(t)
disableFndgLogger(t)

shutdownChannel := make(chan struct{})

Expand Down
16 changes: 10 additions & 6 deletions lnwallet/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -3671,22 +3671,21 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) {
//
// TODO(roasbeef): caller should initiate signal to reject all incoming HTLCs,
// settle any in flight.
func (lc *LightningChannel) CreateCloseProposal(feeRate uint64,
func (lc *LightningChannel) CreateCloseProposal(proposedFee uint64,
localDeliveryScript, remoteDeliveryScript []byte) ([]byte, uint64, error) {

lc.Lock()
defer lc.Unlock()

// If we're already closing the channel, then ignore this request.
if lc.status == channelClosing || lc.status == channelClosed {
// If we've already closed the channel, then ignore this request.
if lc.status == channelClosed {
// TODO(roasbeef): check to ensure no pending payments
return nil, 0, ErrChanClosing
}

// Subtract the proposed fee from the appropriate balance, taking care
// not to persist the adjusted balance, as the feeRate may change
// during the channel closing process.
proposedFee := (feeRate * uint64(commitWeight)) / 1000
ourBalance := lc.channelState.LocalBalance
theirBalance := lc.channelState.RemoteBalance

Expand Down Expand Up @@ -3734,7 +3733,7 @@ func (lc *LightningChannel) CreateCloseProposal(feeRate uint64,
// signatures including the proper sighash byte.
func (lc *LightningChannel) CompleteCooperativeClose(localSig, remoteSig,
localDeliveryScript, remoteDeliveryScript []byte,
feeRate uint64) (*wire.MsgTx, error) {
proposedFee uint64) (*wire.MsgTx, error) {

lc.Lock()
defer lc.Unlock()
Expand All @@ -3748,7 +3747,6 @@ func (lc *LightningChannel) CompleteCooperativeClose(localSig, remoteSig,
// Subtract the proposed fee from the appropriate balance, taking care
// not to persist the adjusted balance, as the feeRate may change
// during the channel closing process.
proposedFee := (feeRate * uint64(commitWeight)) / 1000
ourBalance := lc.channelState.LocalBalance
theirBalance := lc.channelState.RemoteBalance

Expand Down Expand Up @@ -3947,3 +3945,9 @@ func CreateCooperativeCloseTx(fundingTxIn *wire.TxIn,

return closeTx
}

// CalcFee returns the commitment fee to use for the given
// fee rate (fee-per-kw).
func (lc *LightningChannel) CalcFee(feeRate uint64) uint64 {
return (feeRate * uint64(commitWeight)) / 1000
}
32 changes: 18 additions & 14 deletions lnwallet/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -737,17 +737,19 @@ func TestCooperativeChannelClosure(t *testing.T) {
bobFeeRate := uint64(bobChannel.channelState.FeePerKw)

// We'll store with both Alice and Bob creating a new close proposal
// with the same fee rate.
// with the same fee.
aliceFee := aliceChannel.CalcFee(aliceFeeRate)
aliceSig, _, err := aliceChannel.CreateCloseProposal(
aliceFeeRate, aliceDeliveryScript, bobDeliveryScript,
aliceFee, aliceDeliveryScript, bobDeliveryScript,
)
if err != nil {
t.Fatalf("unable to create alice coop close proposal: %v", err)
}
aliceCloseSig := append(aliceSig, byte(txscript.SigHashAll))

bobFee := bobChannel.CalcFee(bobFeeRate)
bobSig, _, err := bobChannel.CreateCloseProposal(
bobFeeRate, bobDeliveryScript, aliceDeliveryScript,
bobFee, bobDeliveryScript, aliceDeliveryScript,
)
if err != nil {
t.Fatalf("unable to create bob coop close proposal: %v", err)
Expand All @@ -759,15 +761,15 @@ func TestCooperativeChannelClosure(t *testing.T) {
// transaction is well formed, and the signatures verify.
aliceCloseTx, err := bobChannel.CompleteCooperativeClose(
bobCloseSig, aliceCloseSig, bobDeliveryScript,
aliceDeliveryScript, bobFeeRate)
aliceDeliveryScript, bobFee)
if err != nil {
t.Fatalf("unable to complete alice cooperative close: %v", err)
}
bobCloseSha := aliceCloseTx.TxHash()

bobCloseTx, err := aliceChannel.CompleteCooperativeClose(
aliceCloseSig, bobCloseSig, aliceDeliveryScript,
bobDeliveryScript, aliceFeeRate)
bobDeliveryScript, aliceFee)
if err != nil {
t.Fatalf("unable to complete bob cooperative close: %v", err)
}
Expand Down Expand Up @@ -1590,14 +1592,16 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
// Both sides currently have over 1 BTC settled as part of their
// balances. As a result, performing a cooperative closure now result
// in both sides having an output within the closure transaction.
aliceSig, _, err := aliceChannel.CreateCloseProposal(aliceFeeRate,
aliceFee := aliceChannel.CalcFee(aliceFeeRate)
aliceSig, _, err := aliceChannel.CreateCloseProposal(aliceFee,
aliceDeliveryScript, bobDeliveryScript)
if err != nil {
t.Fatalf("unable to close channel: %v", err)
}
aliceCloseSig := append(aliceSig, byte(txscript.SigHashAll))

bobSig, _, err := bobChannel.CreateCloseProposal(bobFeeRate,
bobFee := bobChannel.CalcFee(bobFeeRate)
bobSig, _, err := bobChannel.CreateCloseProposal(bobFee,
bobDeliveryScript, aliceDeliveryScript)
if err != nil {
t.Fatalf("unable to close channel: %v", err)
Expand All @@ -1606,7 +1610,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {

closeTx, err := bobChannel.CompleteCooperativeClose(
bobCloseSig, aliceCloseSig,
bobDeliveryScript, aliceDeliveryScript, bobFeeRate)
bobDeliveryScript, aliceDeliveryScript, bobFee)
if err != nil {
t.Fatalf("unable to accept channel close: %v", err)
}
Expand All @@ -1628,14 +1632,14 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {

// Attempt another cooperative channel closure. It should succeed
// without any issues.
aliceSig, _, err = aliceChannel.CreateCloseProposal(aliceFeeRate,
aliceSig, _, err = aliceChannel.CreateCloseProposal(aliceFee,
aliceDeliveryScript, bobDeliveryScript)
if err != nil {
t.Fatalf("unable to close channel: %v", err)
}
aliceCloseSig = append(aliceSig, byte(txscript.SigHashAll))

bobSig, _, err = bobChannel.CreateCloseProposal(bobFeeRate,
bobSig, _, err = bobChannel.CreateCloseProposal(bobFee,
bobDeliveryScript, aliceDeliveryScript)
if err != nil {
t.Fatalf("unable to close channel: %v", err)
Expand All @@ -1644,7 +1648,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {

closeTx, err = bobChannel.CompleteCooperativeClose(
bobCloseSig, aliceCloseSig,
bobDeliveryScript, aliceDeliveryScript, bobFeeRate)
bobDeliveryScript, aliceDeliveryScript, bobFee)
if err != nil {
t.Fatalf("unable to accept channel close: %v", err)
}
Expand All @@ -1667,14 +1671,14 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {

// Our final attempt at another cooperative channel closure. It should
// succeed without any issues.
aliceSig, _, err = aliceChannel.CreateCloseProposal(aliceFeeRate,
aliceSig, _, err = aliceChannel.CreateCloseProposal(aliceFee,
aliceDeliveryScript, bobDeliveryScript)
if err != nil {
t.Fatalf("unable to close channel: %v", err)
}
aliceCloseSig = append(aliceSig, byte(txscript.SigHashAll))

bobSig, _, err = bobChannel.CreateCloseProposal(bobFeeRate,
bobSig, _, err = bobChannel.CreateCloseProposal(bobFee,
bobDeliveryScript, aliceDeliveryScript)
if err != nil {
t.Fatalf("unable to close channel: %v", err)
Expand All @@ -1683,7 +1687,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {

closeTx, err = bobChannel.CompleteCooperativeClose(
bobCloseSig, aliceCloseSig,
bobDeliveryScript, aliceDeliveryScript, bobFeeRate)
bobDeliveryScript, aliceDeliveryScript, bobFee)
if err != nil {
t.Fatalf("unable to accept channel close: %v", err)
}
Expand Down

0 comments on commit 3568511

Please sign in to comment.