lnd.xprv/test_utils.go
Johan T. Halseth e8e87322dd
peer: add channel close fee negotiation
This commit adds the fee negotiation procedure performed
on channel shutdown. The current algorithm picks an ideal
a fee based on the FeeEstimator and commit weigth, then
accepts the remote's fee if it is at most 50%-200% away
from the ideal. The fee negotiation procedure is similar
both as sender and receiver of the initial shutdown
message, and this commit also make both sides use the
same code path for handling these messages.
2017-08-11 12:10:32 +02:00

269 lines
8.0 KiB
Go

package main
import (
"bytes"
"io/ioutil"
"math/rand"
"net"
"os"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
)
var (
alicesPrivKey = []byte{
0x2b, 0xd8, 0x06, 0xc9, 0x7f, 0x0e, 0x00, 0xaf,
0x1a, 0x1f, 0xc3, 0x32, 0x8f, 0xa7, 0x63, 0xa9,
0x26, 0x97, 0x23, 0xc8, 0xdb, 0x8f, 0xac, 0x4f,
0x93, 0xaf, 0x71, 0xdb, 0x18, 0x6d, 0x6e, 0x90,
}
bobsPrivKey = []byte{
0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
0xd, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
}
// Use a hard-coded HD seed.
testHdSeed = [32]byte{
0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
}
// Just use some arbitrary bytes as delivery script.
dummyDeliveryScript = alicesPrivKey[:]
)
// createTestPeer creates a channel between two nodes, and returns a peer for
// one of the nodes, together with the channel seen from both nodes.
func createTestPeer(notifier chainntnfs.ChainNotifier,
publTx chan *wire.MsgTx) (*peer, *lnwallet.LightningChannel,
*lnwallet.LightningChannel, func(), error) {
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
alicesPrivKey)
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
bobsPrivKey)
channelCapacity := btcutil.Amount(10 * 1e8)
channelBal := channelCapacity / 2
aliceDustLimit := btcutil.Amount(200)
bobDustLimit := btcutil.Amount(1300)
csvTimeoutAlice := uint32(5)
csvTimeoutBob := uint32(4)
prevOut := &wire.OutPoint{
Hash: chainhash.Hash(testHdSeed),
Index: 0,
}
fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
aliceCfg := channeldb.ChannelConfig{
ChannelConstraints: channeldb.ChannelConstraints{
DustLimit: aliceDustLimit,
MaxPendingAmount: btcutil.Amount(rand.Int63()),
ChanReserve: btcutil.Amount(rand.Int63()),
MinHTLC: btcutil.Amount(rand.Int63()),
MaxAcceptedHtlcs: uint16(rand.Int31()),
},
CsvDelay: uint16(csvTimeoutAlice),
MultiSigKey: aliceKeyPub,
RevocationBasePoint: aliceKeyPub,
PaymentBasePoint: aliceKeyPub,
DelayBasePoint: aliceKeyPub,
}
bobCfg := channeldb.ChannelConfig{
ChannelConstraints: channeldb.ChannelConstraints{
DustLimit: bobDustLimit,
MaxPendingAmount: btcutil.Amount(rand.Int63()),
ChanReserve: btcutil.Amount(rand.Int63()),
MinHTLC: btcutil.Amount(rand.Int63()),
MaxAcceptedHtlcs: uint16(rand.Int31()),
},
CsvDelay: uint16(csvTimeoutBob),
MultiSigKey: bobKeyPub,
RevocationBasePoint: bobKeyPub,
PaymentBasePoint: bobKeyPub,
DelayBasePoint: bobKeyPub,
}
bobRoot := lnwallet.DeriveRevocationRoot(bobKeyPriv, testHdSeed, aliceKeyPub)
bobPreimageProducer := shachain.NewRevocationProducer(bobRoot)
bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
if err != nil {
return nil, nil, nil, nil, err
}
bobCommitPoint := lnwallet.ComputeCommitmentPoint(bobFirstRevoke[:])
aliceRoot := lnwallet.DeriveRevocationRoot(aliceKeyPriv, testHdSeed, bobKeyPub)
alicePreimageProducer := shachain.NewRevocationProducer(aliceRoot)
aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
if err != nil {
return nil, nil, nil, nil, err
}
aliceCommitPoint := lnwallet.ComputeCommitmentPoint(aliceFirstRevoke[:])
aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(channelBal,
channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint,
fundingTxIn)
if err != nil {
return nil, nil, nil, nil, err
}
alicePath, err := ioutil.TempDir("", "alicedb")
dbAlice, err := channeldb.Open(alicePath)
if err != nil {
return nil, nil, nil, nil, err
}
bobPath, err := ioutil.TempDir("", "bobdb")
dbBob, err := channeldb.Open(bobPath)
if err != nil {
return nil, nil, nil, nil, err
}
var obsfucator [lnwallet.StateHintSize]byte
copy(obsfucator[:], aliceFirstRevoke[:])
estimator := &lnwallet.StaticFeeEstimator{FeeRate: 50}
feePerKw := btcutil.Amount(estimator.EstimateFeePerWeight(1) * 1000)
aliceChannelState := &channeldb.OpenChannel{
LocalChanCfg: aliceCfg,
RemoteChanCfg: bobCfg,
IdentityPub: aliceKeyPub,
FundingOutpoint: *prevOut,
ChanType: channeldb.SingleFunder,
FeePerKw: feePerKw,
IsInitiator: true,
Capacity: channelCapacity,
LocalBalance: channelBal,
RemoteBalance: channelBal,
CommitTx: *aliceCommitTx,
CommitSig: bytes.Repeat([]byte{1}, 71),
RemoteCurrentRevocation: bobCommitPoint,
RevocationProducer: alicePreimageProducer,
RevocationStore: shachain.NewRevocationStore(),
Db: dbAlice,
}
addr := &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 18555,
}
if err := aliceChannelState.SyncPending(addr, 0); err != nil {
return nil, nil, nil, nil, err
}
bobChannelState := &channeldb.OpenChannel{
LocalChanCfg: bobCfg,
RemoteChanCfg: aliceCfg,
IdentityPub: bobKeyPub,
FeePerKw: feePerKw,
FundingOutpoint: *prevOut,
ChanType: channeldb.SingleFunder,
IsInitiator: false,
Capacity: channelCapacity,
LocalBalance: channelBal,
RemoteBalance: channelBal,
CommitTx: *bobCommitTx,
CommitSig: bytes.Repeat([]byte{1}, 71),
RemoteCurrentRevocation: aliceCommitPoint,
RevocationProducer: bobPreimageProducer,
RevocationStore: shachain.NewRevocationStore(),
Db: dbBob,
}
addr = &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 18556,
}
if err := bobChannelState.SyncPending(addr, 0); err != nil {
return nil, nil, nil, nil, err
}
cleanUpFunc := func() {
os.RemoveAll(bobPath)
os.RemoveAll(alicePath)
}
aliceSigner := &mockSigner{aliceKeyPriv}
bobSigner := &mockSigner{bobKeyPriv}
channelAlice, err := lnwallet.NewLightningChannel(aliceSigner, notifier,
estimator, aliceChannelState)
if err != nil {
return nil, nil, nil, nil, err
}
channelBob, err := lnwallet.NewLightningChannel(bobSigner, notifier,
estimator, bobChannelState)
if err != nil {
return nil, nil, nil, nil, err
}
chainIO := &mockChainIO{}
wallet := &lnwallet.LightningWallet{
WalletController: &mockWalletController{
rootKey: aliceKeyPriv,
publishedTransactions: publTx,
},
}
cc := &chainControl{
feeEstimator: estimator,
chainIO: chainIO,
chainNotifier: notifier,
wallet: wallet,
}
breachArbiter := &breachArbiter{
settledContracts: make(chan *wire.OutPoint, 10),
}
s := &server{
chanDB: dbAlice,
cc: cc,
breachArbiter: breachArbiter,
}
s.htlcSwitch = htlcswitch.New(htlcswitch.Config{})
s.htlcSwitch.Start()
alicePeer := &peer{
server: s,
sendQueue: make(chan outgoinMsg, 1),
outgoingQueue: make(chan outgoinMsg, outgoingQueueLen),
activeChannels: make(map[lnwire.ChannelID]*lnwallet.LightningChannel),
newChannels: make(chan *newChannelMsg, 1),
localCloseChanReqs: make(chan *htlcswitch.ChanClose),
shutdownChanReqs: make(chan *lnwire.Shutdown),
closingSignedChanReqs: make(chan *lnwire.ClosingSigned),
localSharedFeatures: nil,
globalSharedFeatures: nil,
queueQuit: make(chan struct{}),
quit: make(chan struct{}),
}
chanID := lnwire.NewChanIDFromOutPoint(channelAlice.ChannelPoint())
alicePeer.activeChannels[chanID] = channelAlice
go alicePeer.channelManager()
return alicePeer, channelAlice, channelBob, cleanUpFunc, nil
}