696 lines
18 KiB
Go
696 lines
18 KiB
Go
|
package peer
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
crand "crypto/rand"
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"math/rand"
|
||
|
"net"
|
||
|
"os"
|
||
|
"time"
|
||
|
|
||
|
"github.com/btcsuite/btcd/btcec"
|
||
|
"github.com/btcsuite/btcd/chaincfg"
|
||
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||
|
"github.com/btcsuite/btcd/txscript"
|
||
|
"github.com/btcsuite/btcd/wire"
|
||
|
"github.com/btcsuite/btcutil"
|
||
|
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||
|
"github.com/btcsuite/btcwallet/wtxmgr"
|
||
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||
|
"github.com/lightningnetwork/lnd/input"
|
||
|
"github.com/lightningnetwork/lnd/keychain"
|
||
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||
|
"github.com/lightningnetwork/lnd/netann"
|
||
|
"github.com/lightningnetwork/lnd/queue"
|
||
|
"github.com/lightningnetwork/lnd/shachain"
|
||
|
"github.com/lightningnetwork/lnd/ticker"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
broadcastHeight = 100
|
||
|
)
|
||
|
|
||
|
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
|
||
|
|
||
|
// testTx is used as the default funding txn for single-funder channels.
|
||
|
testTx = &wire.MsgTx{
|
||
|
Version: 1,
|
||
|
TxIn: []*wire.TxIn{
|
||
|
{
|
||
|
PreviousOutPoint: wire.OutPoint{
|
||
|
Hash: chainhash.Hash{},
|
||
|
Index: 0xffffffff,
|
||
|
},
|
||
|
SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62},
|
||
|
Sequence: 0xffffffff,
|
||
|
},
|
||
|
},
|
||
|
TxOut: []*wire.TxOut{
|
||
|
{
|
||
|
Value: 5000000000,
|
||
|
PkScript: []byte{
|
||
|
0x41, // OP_DATA_65
|
||
|
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
||
|
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
||
|
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
||
|
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
||
|
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
||
|
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
||
|
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
||
|
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
||
|
0xa6, // 65-byte signature
|
||
|
0xac, // OP_CHECKSIG
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
LockTime: 5,
|
||
|
}
|
||
|
)
|
||
|
|
||
|
// noUpdate is a function which can be used as a parameter in createTestPeer to
|
||
|
// call the setup code with no custom values on the channels set up.
|
||
|
var noUpdate = func(a, b *channeldb.OpenChannel) {}
|
||
|
|
||
|
type mockSigner struct {
|
||
|
key *btcec.PrivateKey
|
||
|
}
|
||
|
|
||
|
func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx,
|
||
|
signDesc *input.SignDescriptor) (input.Signature, error) {
|
||
|
amt := signDesc.Output.Value
|
||
|
witnessScript := signDesc.WitnessScript
|
||
|
privKey := m.key
|
||
|
|
||
|
if !privKey.PubKey().IsEqual(signDesc.KeyDesc.PubKey) {
|
||
|
return nil, fmt.Errorf("incorrect key passed")
|
||
|
}
|
||
|
|
||
|
switch {
|
||
|
case signDesc.SingleTweak != nil:
|
||
|
privKey = input.TweakPrivKey(privKey,
|
||
|
signDesc.SingleTweak)
|
||
|
case signDesc.DoubleTweak != nil:
|
||
|
privKey = input.DeriveRevocationPrivKey(privKey,
|
||
|
signDesc.DoubleTweak)
|
||
|
}
|
||
|
|
||
|
sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes,
|
||
|
signDesc.InputIndex, amt, witnessScript, signDesc.HashType,
|
||
|
privKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return btcec.ParseDERSignature(sig[:len(sig)-1], btcec.S256())
|
||
|
}
|
||
|
|
||
|
func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx,
|
||
|
signDesc *input.SignDescriptor) (*input.Script, error) {
|
||
|
|
||
|
// TODO(roasbeef): expose tweaked signer from lnwallet so don't need to
|
||
|
// duplicate this code?
|
||
|
|
||
|
privKey := m.key
|
||
|
|
||
|
switch {
|
||
|
case signDesc.SingleTweak != nil:
|
||
|
privKey = input.TweakPrivKey(privKey,
|
||
|
signDesc.SingleTweak)
|
||
|
case signDesc.DoubleTweak != nil:
|
||
|
privKey = input.DeriveRevocationPrivKey(privKey,
|
||
|
signDesc.DoubleTweak)
|
||
|
}
|
||
|
|
||
|
witnessScript, err := txscript.WitnessSignature(tx, signDesc.SigHashes,
|
||
|
signDesc.InputIndex, signDesc.Output.Value, signDesc.Output.PkScript,
|
||
|
signDesc.HashType, privKey, true)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &input.Script{
|
||
|
Witness: witnessScript,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
var _ input.Signer = (*mockSigner)(nil)
|
||
|
|
||
|
type mockChainIO struct {
|
||
|
bestHeight int32
|
||
|
}
|
||
|
|
||
|
func (m *mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) {
|
||
|
return nil, m.bestHeight, nil
|
||
|
}
|
||
|
|
||
|
func (*mockChainIO) GetUtxo(op *wire.OutPoint, _ []byte,
|
||
|
heightHint uint32, _ <-chan struct{}) (*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
|
||
|
}
|
||
|
|
||
|
var _ lnwallet.BlockChainIO = (*mockChainIO)(nil)
|
||
|
|
||
|
type mockWalletController struct {
|
||
|
rootKey *btcec.PrivateKey
|
||
|
publishedTxns chan *wire.MsgTx
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) FetchInputInfo(prevOut *wire.OutPoint) (
|
||
|
*lnwallet.Utxo, error) {
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) ConfirmedBalance(confs int32) (btcutil.Amount,
|
||
|
error) {
|
||
|
|
||
|
return 0, nil
|
||
|
}
|
||
|
|
||
|
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) LastUnusedAddress(addrType lnwallet.AddressType) (
|
||
|
btcutil.Address, error) {
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) IsOurAddress(a btcutil.Address) bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) SendOutputs(outputs []*wire.TxOut,
|
||
|
feeRate chainfee.SatPerKWeight, label string) (*wire.MsgTx, error) {
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) CreateSimpleTx(outputs []*wire.TxOut,
|
||
|
feeRate chainfee.SatPerKWeight, dryRun bool) (*txauthor.AuthoredTx, error) {
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) ListUnspentWitness(minconfirms,
|
||
|
maxconfirms int32) ([]*lnwallet.Utxo, error) {
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) ListTransactionDetails(startHeight,
|
||
|
endHeight int32) ([]*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,
|
||
|
label string) error {
|
||
|
m.publishedTxns <- tx
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) LabelTransaction(hash chainhash.Hash,
|
||
|
label string, overwrite bool) error {
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) SubscribeTransactions() (
|
||
|
lnwallet.TransactionSubscription, error) {
|
||
|
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) IsSynced() (bool, int64, error) {
|
||
|
return false, 0, nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) Start() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) Stop() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) BackEnd() string {
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) LeaseOutput(wtxmgr.LockID,
|
||
|
wire.OutPoint) (time.Time, error) {
|
||
|
|
||
|
return time.Now(), nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) ReleaseOutput(wtxmgr.LockID, wire.OutPoint) error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (*mockWalletController) GetRecoveryInfo() (bool, float64, error) {
|
||
|
return false, 0, nil
|
||
|
}
|
||
|
|
||
|
var _ lnwallet.WalletController = (*mockWalletController)(nil)
|
||
|
|
||
|
type mockNotifier struct {
|
||
|
confChannel chan *chainntnfs.TxConfirmation
|
||
|
}
|
||
|
|
||
|
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
|
||
|
_ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent,
|
||
|
error) {
|
||
|
|
||
|
return &chainntnfs.ConfirmationEvent{
|
||
|
Confirmed: m.confChannel,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
|
||
|
heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
||
|
|
||
|
return &chainntnfs.SpendEvent{
|
||
|
Spend: make(chan *chainntnfs.SpendDetail),
|
||
|
Cancel: func() {},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (m *mockNotifier) RegisterBlockEpochNtfn(
|
||
|
bestBlock *chainntnfs.BlockEpoch) (*chainntnfs.BlockEpochEvent, error) {
|
||
|
|
||
|
return &chainntnfs.BlockEpochEvent{
|
||
|
Epochs: make(chan *chainntnfs.BlockEpoch),
|
||
|
Cancel: func() {},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (m *mockNotifier) Start() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *mockNotifier) Stop() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *mockNotifier) Started() bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
var _ chainntnfs.ChainNotifier = (*mockNotifier)(nil)
|
||
|
|
||
|
// createTestPeer creates a channel between two nodes, and returns a peer for
|
||
|
// one of the nodes, together with the channel seen from both nodes. It takes
|
||
|
// an updateChan function which can be used to modify the default values on
|
||
|
// the channel states for each peer.
|
||
|
func createTestPeer(notifier chainntnfs.ChainNotifier,
|
||
|
publTx chan *wire.MsgTx, updateChan func(a, b *channeldb.OpenChannel)) (
|
||
|
*Brontide, *lnwallet.LightningChannel, func(), error) {
|
||
|
|
||
|
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
|
||
|
btcec.S256(), alicesPrivKey,
|
||
|
)
|
||
|
aliceKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: aliceKeyPriv}
|
||
|
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: lnwire.MilliSatoshi(rand.Int63()),
|
||
|
ChanReserve: btcutil.Amount(rand.Int63()),
|
||
|
MinHTLC: lnwire.MilliSatoshi(rand.Int63()),
|
||
|
MaxAcceptedHtlcs: uint16(rand.Int31()),
|
||
|
CsvDelay: uint16(csvTimeoutAlice),
|
||
|
},
|
||
|
MultiSigKey: keychain.KeyDescriptor{
|
||
|
PubKey: aliceKeyPub,
|
||
|
},
|
||
|
RevocationBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: aliceKeyPub,
|
||
|
},
|
||
|
PaymentBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: aliceKeyPub,
|
||
|
},
|
||
|
DelayBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: aliceKeyPub,
|
||
|
},
|
||
|
HtlcBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: aliceKeyPub,
|
||
|
},
|
||
|
}
|
||
|
bobCfg := channeldb.ChannelConfig{
|
||
|
ChannelConstraints: channeldb.ChannelConstraints{
|
||
|
DustLimit: bobDustLimit,
|
||
|
MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()),
|
||
|
ChanReserve: btcutil.Amount(rand.Int63()),
|
||
|
MinHTLC: lnwire.MilliSatoshi(rand.Int63()),
|
||
|
MaxAcceptedHtlcs: uint16(rand.Int31()),
|
||
|
CsvDelay: uint16(csvTimeoutBob),
|
||
|
},
|
||
|
MultiSigKey: keychain.KeyDescriptor{
|
||
|
PubKey: bobKeyPub,
|
||
|
},
|
||
|
RevocationBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: bobKeyPub,
|
||
|
},
|
||
|
PaymentBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: bobKeyPub,
|
||
|
},
|
||
|
DelayBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: bobKeyPub,
|
||
|
},
|
||
|
HtlcBasePoint: keychain.KeyDescriptor{
|
||
|
PubKey: bobKeyPub,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
bobRoot, err := chainhash.NewHash(bobKeyPriv.Serialize())
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
bobPreimageProducer := shachain.NewRevocationProducer(*bobRoot)
|
||
|
bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
|
||
|
|
||
|
aliceRoot, err := chainhash.NewHash(aliceKeyPriv.Serialize())
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
alicePreimageProducer := shachain.NewRevocationProducer(*aliceRoot)
|
||
|
aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
|
||
|
|
||
|
aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(
|
||
|
channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint,
|
||
|
bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
alicePath, err := ioutil.TempDir("", "alicedb")
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
dbAlice, err := channeldb.Open(alicePath)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
bobPath, err := ioutil.TempDir("", "bobdb")
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
dbBob, err := channeldb.Open(bobPath)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
estimator := chainfee.NewStaticEstimator(12500, 0)
|
||
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
// TODO(roasbeef): need to factor in commit fee?
|
||
|
aliceCommit := channeldb.ChannelCommitment{
|
||
|
CommitHeight: 0,
|
||
|
LocalBalance: lnwire.NewMSatFromSatoshis(channelBal),
|
||
|
RemoteBalance: lnwire.NewMSatFromSatoshis(channelBal),
|
||
|
FeePerKw: btcutil.Amount(feePerKw),
|
||
|
CommitFee: feePerKw.FeeForWeight(input.CommitWeight),
|
||
|
CommitTx: aliceCommitTx,
|
||
|
CommitSig: bytes.Repeat([]byte{1}, 71),
|
||
|
}
|
||
|
bobCommit := channeldb.ChannelCommitment{
|
||
|
CommitHeight: 0,
|
||
|
LocalBalance: lnwire.NewMSatFromSatoshis(channelBal),
|
||
|
RemoteBalance: lnwire.NewMSatFromSatoshis(channelBal),
|
||
|
FeePerKw: btcutil.Amount(feePerKw),
|
||
|
CommitFee: feePerKw.FeeForWeight(input.CommitWeight),
|
||
|
CommitTx: bobCommitTx,
|
||
|
CommitSig: bytes.Repeat([]byte{1}, 71),
|
||
|
}
|
||
|
|
||
|
var chanIDBytes [8]byte
|
||
|
if _, err := io.ReadFull(crand.Reader, chanIDBytes[:]); err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
shortChanID := lnwire.NewShortChanIDFromInt(
|
||
|
binary.BigEndian.Uint64(chanIDBytes[:]),
|
||
|
)
|
||
|
|
||
|
aliceChannelState := &channeldb.OpenChannel{
|
||
|
LocalChanCfg: aliceCfg,
|
||
|
RemoteChanCfg: bobCfg,
|
||
|
IdentityPub: aliceKeyPub,
|
||
|
FundingOutpoint: *prevOut,
|
||
|
ShortChannelID: shortChanID,
|
||
|
ChanType: channeldb.SingleFunderTweaklessBit,
|
||
|
IsInitiator: true,
|
||
|
Capacity: channelCapacity,
|
||
|
RemoteCurrentRevocation: bobCommitPoint,
|
||
|
RevocationProducer: alicePreimageProducer,
|
||
|
RevocationStore: shachain.NewRevocationStore(),
|
||
|
LocalCommitment: aliceCommit,
|
||
|
RemoteCommitment: aliceCommit,
|
||
|
Db: dbAlice,
|
||
|
Packager: channeldb.NewChannelPackager(shortChanID),
|
||
|
FundingTxn: testTx,
|
||
|
}
|
||
|
bobChannelState := &channeldb.OpenChannel{
|
||
|
LocalChanCfg: bobCfg,
|
||
|
RemoteChanCfg: aliceCfg,
|
||
|
IdentityPub: bobKeyPub,
|
||
|
FundingOutpoint: *prevOut,
|
||
|
ChanType: channeldb.SingleFunderTweaklessBit,
|
||
|
IsInitiator: false,
|
||
|
Capacity: channelCapacity,
|
||
|
RemoteCurrentRevocation: aliceCommitPoint,
|
||
|
RevocationProducer: bobPreimageProducer,
|
||
|
RevocationStore: shachain.NewRevocationStore(),
|
||
|
LocalCommitment: bobCommit,
|
||
|
RemoteCommitment: bobCommit,
|
||
|
Db: dbBob,
|
||
|
Packager: channeldb.NewChannelPackager(shortChanID),
|
||
|
}
|
||
|
|
||
|
// Set custom values on the channel states.
|
||
|
updateChan(aliceChannelState, bobChannelState)
|
||
|
|
||
|
aliceAddr := &net.TCPAddr{
|
||
|
IP: net.ParseIP("127.0.0.1"),
|
||
|
Port: 18555,
|
||
|
}
|
||
|
|
||
|
if err := aliceChannelState.SyncPending(aliceAddr, 0); err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
bobAddr := &net.TCPAddr{
|
||
|
IP: net.ParseIP("127.0.0.1"),
|
||
|
Port: 18556,
|
||
|
}
|
||
|
|
||
|
if err := bobChannelState.SyncPending(bobAddr, 0); err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
cleanUpFunc := func() {
|
||
|
os.RemoveAll(bobPath)
|
||
|
os.RemoveAll(alicePath)
|
||
|
}
|
||
|
|
||
|
aliceSigner := &mockSigner{aliceKeyPriv}
|
||
|
bobSigner := &mockSigner{bobKeyPriv}
|
||
|
|
||
|
alicePool := lnwallet.NewSigPool(1, aliceSigner)
|
||
|
channelAlice, err := lnwallet.NewLightningChannel(
|
||
|
aliceSigner, aliceChannelState, alicePool,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
_ = alicePool.Start()
|
||
|
|
||
|
bobPool := lnwallet.NewSigPool(1, bobSigner)
|
||
|
channelBob, err := lnwallet.NewLightningChannel(
|
||
|
bobSigner, bobChannelState, bobPool,
|
||
|
)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
_ = bobPool.Start()
|
||
|
|
||
|
chainIO := &mockChainIO{
|
||
|
bestHeight: broadcastHeight,
|
||
|
}
|
||
|
wallet := &lnwallet.LightningWallet{
|
||
|
WalletController: &mockWalletController{
|
||
|
rootKey: aliceKeyPriv,
|
||
|
publishedTxns: publTx,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
_, currentHeight, err := chainIO.GetBestBlock()
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
htlcSwitch, err := htlcswitch.New(htlcswitch.Config{
|
||
|
DB: dbAlice,
|
||
|
SwitchPackager: channeldb.NewSwitchPackager(),
|
||
|
Notifier: notifier,
|
||
|
FwdEventTicker: ticker.New(
|
||
|
htlcswitch.DefaultFwdEventInterval),
|
||
|
LogEventTicker: ticker.New(
|
||
|
htlcswitch.DefaultLogInterval),
|
||
|
AckEventTicker: ticker.New(
|
||
|
htlcswitch.DefaultAckInterval),
|
||
|
}, uint32(currentHeight))
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
if err = htlcSwitch.Start(); err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
nodeSignerAlice := netann.NewNodeSigner(aliceKeySigner)
|
||
|
|
||
|
const chanActiveTimeout = time.Minute
|
||
|
|
||
|
chanStatusMgr, err := netann.NewChanStatusManager(&netann.ChanStatusConfig{
|
||
|
ChanStatusSampleInterval: 30 * time.Second,
|
||
|
ChanEnableTimeout: chanActiveTimeout,
|
||
|
ChanDisableTimeout: 2 * time.Minute,
|
||
|
DB: dbAlice,
|
||
|
Graph: dbAlice.ChannelGraph(),
|
||
|
MessageSigner: nodeSignerAlice,
|
||
|
OurPubKey: aliceKeyPub,
|
||
|
IsChannelActive: htlcSwitch.HasActiveLink,
|
||
|
ApplyChannelUpdate: func(*lnwire.ChannelUpdate) error { return nil },
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
if err = chanStatusMgr.Start(); err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
errBuffer, err := queue.NewCircularBuffer(ErrorBufferSize)
|
||
|
if err != nil {
|
||
|
return nil, nil, nil, err
|
||
|
}
|
||
|
|
||
|
var pubKey [33]byte
|
||
|
copy(pubKey[:], aliceKeyPub.SerializeCompressed())
|
||
|
|
||
|
cfgAddr := &lnwire.NetAddress{
|
||
|
IdentityKey: aliceKeyPub,
|
||
|
Address: aliceAddr,
|
||
|
ChainNet: wire.SimNet,
|
||
|
}
|
||
|
|
||
|
cfg := &Config{
|
||
|
Addr: cfgAddr,
|
||
|
PubKeyBytes: pubKey,
|
||
|
ErrorBuffer: errBuffer,
|
||
|
ChainIO: chainIO,
|
||
|
Switch: htlcSwitch,
|
||
|
|
||
|
ChanActiveTimeout: chanActiveTimeout,
|
||
|
InterceptSwitch: htlcswitch.NewInterceptableSwitch(htlcSwitch),
|
||
|
|
||
|
ChannelDB: dbAlice,
|
||
|
FeeEstimator: estimator,
|
||
|
Wallet: wallet,
|
||
|
ChainNotifier: notifier,
|
||
|
ChanStatusMgr: chanStatusMgr,
|
||
|
DisconnectPeer: func(b *btcec.PublicKey) error { return nil },
|
||
|
}
|
||
|
|
||
|
alicePeer := NewBrontide(*cfg)
|
||
|
|
||
|
chanID := lnwire.NewChanIDFromOutPoint(channelAlice.ChannelPoint())
|
||
|
alicePeer.activeChannels[chanID] = channelAlice
|
||
|
|
||
|
alicePeer.wg.Add(1)
|
||
|
go alicePeer.channelManager()
|
||
|
|
||
|
return alicePeer, channelBob, cleanUpFunc, nil
|
||
|
}
|