2018-04-30 00:31:32 +02:00
|
|
|
package lnwallet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/binary"
|
|
|
|
"encoding/hex"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2019-09-06 13:14:39 +02:00
|
|
|
prand "math/rand"
|
2019-09-06 13:14:38 +02:00
|
|
|
"net"
|
2018-04-30 00:31:32 +02:00
|
|
|
"os"
|
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
2018-06-05 03:34:16 +02:00
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
2018-07-31 09:17:17 +02:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2019-01-16 15:47:43 +01:00
|
|
|
"github.com/lightningnetwork/lnd/input"
|
2018-07-31 09:17:17 +02:00
|
|
|
"github.com/lightningnetwork/lnd/keychain"
|
2019-10-31 03:43:05 +01:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
2018-07-31 09:17:17 +02:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
"github.com/lightningnetwork/lnd/shachain"
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// For simplicity a single priv key controls all of our test outputs.
|
|
|
|
testWalletPrivKey = []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,
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're alice :)
|
|
|
|
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 = chainhash.Hash{
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
|
|
|
// A serializable txn for testing funding txn.
|
|
|
|
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,
|
|
|
|
}
|
2020-04-06 02:07:01 +02:00
|
|
|
|
|
|
|
// A valid, DER-encoded signature (taken from btcec unit tests).
|
|
|
|
testSigBytes = []byte{
|
|
|
|
0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
|
|
|
|
0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3,
|
|
|
|
0xa1, 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32,
|
|
|
|
0xe9, 0xd6, 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab,
|
|
|
|
0x5f, 0xb8, 0xcd, 0x41, 0x02, 0x20, 0x18, 0x15,
|
|
|
|
0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60,
|
|
|
|
0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
|
|
|
|
0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
|
|
|
|
0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
|
|
|
|
}
|
2021-09-28 17:34:10 +02:00
|
|
|
|
|
|
|
aliceDustLimit = btcutil.Amount(200)
|
|
|
|
bobDustLimit = btcutil.Amount(1300)
|
2021-10-19 09:37:47 +02:00
|
|
|
|
|
|
|
testChannelCapacity float64 = 10
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// CreateTestChannels creates to fully populated channels to be used within
|
|
|
|
// testing fixtures. The channels will be returned as if the funding process
|
|
|
|
// has just completed. The channel itself is funded with 10 BTC, with 5 BTC
|
|
|
|
// allocated to each side. Within the channel, Alice is the initiator. The
|
|
|
|
// function also returns a "cleanup" function that is meant to be called once
|
|
|
|
// the test has been finalized. The clean up function will remote all temporary
|
2019-08-01 05:16:52 +02:00
|
|
|
// files created. If tweaklessCommits is true, then the commits within the
|
|
|
|
// channels will use the new format, otherwise the legacy format.
|
2020-03-10 09:33:38 +01:00
|
|
|
func CreateTestChannels(chanType channeldb.ChannelType) (
|
2019-08-01 05:16:52 +02:00
|
|
|
*LightningChannel, *LightningChannel, func(), error) {
|
|
|
|
|
2021-10-19 09:37:47 +02:00
|
|
|
channelCapacity, err := btcutil.NewAmount(testChannelCapacity)
|
2018-04-30 00:31:32 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
channelBal := channelCapacity / 2
|
|
|
|
csvTimeoutAlice := uint32(5)
|
|
|
|
csvTimeoutBob := uint32(4)
|
2021-07-15 02:16:13 +02:00
|
|
|
isAliceInitiator := true
|
2018-04-30 00:31:32 +02:00
|
|
|
|
|
|
|
prevOut := &wire.OutPoint{
|
|
|
|
Hash: chainhash.Hash(testHdSeed),
|
2019-09-06 13:14:39 +02:00
|
|
|
Index: prand.Uint32(),
|
2018-04-30 00:31:32 +02:00
|
|
|
}
|
|
|
|
fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
|
|
|
|
|
|
|
|
// For each party, we'll create a distinct set of keys in order to
|
|
|
|
// emulate the typical set up with live channels.
|
|
|
|
var (
|
|
|
|
aliceKeys []*btcec.PrivateKey
|
|
|
|
bobKeys []*btcec.PrivateKey
|
|
|
|
)
|
|
|
|
for i := 0; i < 5; i++ {
|
|
|
|
key := make([]byte, len(testWalletPrivKey))
|
|
|
|
copy(key[:], testWalletPrivKey[:])
|
|
|
|
key[0] ^= byte(i + 1)
|
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
aliceKey, _ := btcec.PrivKeyFromBytes(key)
|
2018-04-30 00:31:32 +02:00
|
|
|
aliceKeys = append(aliceKeys, aliceKey)
|
|
|
|
|
|
|
|
key = make([]byte, len(bobsPrivKey))
|
|
|
|
copy(key[:], bobsPrivKey)
|
|
|
|
key[0] ^= byte(i + 1)
|
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
bobKey, _ := btcec.PrivKeyFromBytes(key)
|
2018-04-30 00:31:32 +02:00
|
|
|
bobKeys = append(bobKeys, bobKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
aliceCfg := channeldb.ChannelConfig{
|
|
|
|
ChannelConstraints: channeldb.ChannelConstraints{
|
|
|
|
DustLimit: aliceDustLimit,
|
|
|
|
MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity),
|
|
|
|
ChanReserve: channelCapacity / 100,
|
|
|
|
MinHTLC: 0,
|
2019-01-16 15:47:43 +01:00
|
|
|
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
2018-12-10 22:56:41 +01:00
|
|
|
CsvDelay: uint16(csvTimeoutAlice),
|
2018-04-30 00:31:32 +02:00
|
|
|
},
|
|
|
|
MultiSigKey: keychain.KeyDescriptor{
|
|
|
|
PubKey: aliceKeys[0].PubKey(),
|
|
|
|
},
|
|
|
|
RevocationBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: aliceKeys[1].PubKey(),
|
|
|
|
},
|
|
|
|
PaymentBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: aliceKeys[2].PubKey(),
|
|
|
|
},
|
|
|
|
DelayBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: aliceKeys[3].PubKey(),
|
|
|
|
},
|
|
|
|
HtlcBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: aliceKeys[4].PubKey(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
bobCfg := channeldb.ChannelConfig{
|
|
|
|
ChannelConstraints: channeldb.ChannelConstraints{
|
|
|
|
DustLimit: bobDustLimit,
|
|
|
|
MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity),
|
|
|
|
ChanReserve: channelCapacity / 100,
|
|
|
|
MinHTLC: 0,
|
2019-01-16 15:47:43 +01:00
|
|
|
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
2018-12-10 22:56:41 +01:00
|
|
|
CsvDelay: uint16(csvTimeoutBob),
|
2018-04-30 00:31:32 +02:00
|
|
|
},
|
|
|
|
MultiSigKey: keychain.KeyDescriptor{
|
|
|
|
PubKey: bobKeys[0].PubKey(),
|
|
|
|
},
|
|
|
|
RevocationBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: bobKeys[1].PubKey(),
|
|
|
|
},
|
|
|
|
PaymentBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: bobKeys[2].PubKey(),
|
|
|
|
},
|
|
|
|
DelayBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: bobKeys[3].PubKey(),
|
|
|
|
},
|
|
|
|
HtlcBasePoint: keychain.KeyDescriptor{
|
|
|
|
PubKey: bobKeys[4].PubKey(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
bobRoot, err := chainhash.NewHash(bobKeys[0].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
|
|
|
|
}
|
2019-01-16 15:47:43 +01:00
|
|
|
bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
|
2018-04-30 00:31:32 +02:00
|
|
|
|
|
|
|
aliceRoot, err := chainhash.NewHash(aliceKeys[0].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
|
|
|
|
}
|
2019-01-16 15:47:43 +01:00
|
|
|
aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
|
2018-04-30 00:31:32 +02:00
|
|
|
|
2019-08-01 05:10:45 +02:00
|
|
|
aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns(
|
|
|
|
channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint,
|
2021-07-15 02:16:13 +02:00
|
|
|
bobCommitPoint, *fundingTxIn, chanType, isAliceInitiator, 0,
|
2019-08-01 05:10:45 +02:00
|
|
|
)
|
2018-04-30 00:31:32 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
alicePath, err := ioutil.TempDir("", "alicedb")
|
2019-09-13 04:59:07 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:31:32 +02:00
|
|
|
dbAlice, err := channeldb.Open(alicePath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bobPath, err := ioutil.TempDir("", "bobdb")
|
2019-09-13 04:59:07 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:31:32 +02:00
|
|
|
dbBob, err := channeldb.Open(bobPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2019-10-31 03:43:05 +01:00
|
|
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
2018-07-28 03:20:58 +02:00
|
|
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
2018-04-30 00:31:32 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
2020-03-10 09:33:38 +01:00
|
|
|
commitFee := calcStaticFee(chanType, 0)
|
|
|
|
var anchorAmt btcutil.Amount
|
|
|
|
if chanType.HasAnchors() {
|
|
|
|
anchorAmt += 2 * anchorSize
|
|
|
|
}
|
|
|
|
|
|
|
|
aliceBalance := lnwire.NewMSatFromSatoshis(
|
|
|
|
channelBal - commitFee - anchorAmt,
|
|
|
|
)
|
|
|
|
bobBalance := lnwire.NewMSatFromSatoshis(channelBal)
|
2018-04-30 00:31:32 +02:00
|
|
|
|
2020-11-18 22:45:35 +01:00
|
|
|
aliceLocalCommit := channeldb.ChannelCommitment{
|
2018-04-30 00:31:32 +02:00
|
|
|
CommitHeight: 0,
|
2020-03-10 09:33:38 +01:00
|
|
|
LocalBalance: aliceBalance,
|
|
|
|
RemoteBalance: bobBalance,
|
2018-04-30 00:31:32 +02:00
|
|
|
CommitFee: commitFee,
|
|
|
|
FeePerKw: btcutil.Amount(feePerKw),
|
|
|
|
CommitTx: aliceCommitTx,
|
2020-04-06 02:07:01 +02:00
|
|
|
CommitSig: testSigBytes,
|
2018-04-30 00:31:32 +02:00
|
|
|
}
|
2020-11-18 22:45:35 +01:00
|
|
|
aliceRemoteCommit := channeldb.ChannelCommitment{
|
|
|
|
CommitHeight: 0,
|
|
|
|
LocalBalance: aliceBalance,
|
|
|
|
RemoteBalance: bobBalance,
|
|
|
|
CommitFee: commitFee,
|
|
|
|
FeePerKw: btcutil.Amount(feePerKw),
|
|
|
|
CommitTx: bobCommitTx,
|
|
|
|
CommitSig: testSigBytes,
|
|
|
|
}
|
|
|
|
bobLocalCommit := channeldb.ChannelCommitment{
|
2018-04-30 00:31:32 +02:00
|
|
|
CommitHeight: 0,
|
2020-03-10 09:33:38 +01:00
|
|
|
LocalBalance: bobBalance,
|
|
|
|
RemoteBalance: aliceBalance,
|
2018-04-30 00:31:32 +02:00
|
|
|
CommitFee: commitFee,
|
|
|
|
FeePerKw: btcutil.Amount(feePerKw),
|
|
|
|
CommitTx: bobCommitTx,
|
2020-04-06 02:07:01 +02:00
|
|
|
CommitSig: testSigBytes,
|
2018-04-30 00:31:32 +02:00
|
|
|
}
|
2020-11-18 22:45:35 +01:00
|
|
|
bobRemoteCommit := channeldb.ChannelCommitment{
|
|
|
|
CommitHeight: 0,
|
|
|
|
LocalBalance: bobBalance,
|
|
|
|
RemoteBalance: aliceBalance,
|
|
|
|
CommitFee: commitFee,
|
|
|
|
FeePerKw: btcutil.Amount(feePerKw),
|
|
|
|
CommitTx: aliceCommitTx,
|
|
|
|
CommitSig: testSigBytes,
|
|
|
|
}
|
2018-04-30 00:31:32 +02:00
|
|
|
|
|
|
|
var chanIDBytes [8]byte
|
|
|
|
if _, err := io.ReadFull(rand.Reader, chanIDBytes[:]); err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
shortChanID := lnwire.NewShortChanIDFromInt(
|
|
|
|
binary.BigEndian.Uint64(chanIDBytes[:]),
|
|
|
|
)
|
|
|
|
|
|
|
|
aliceChannelState := &channeldb.OpenChannel{
|
|
|
|
LocalChanCfg: aliceCfg,
|
|
|
|
RemoteChanCfg: bobCfg,
|
|
|
|
IdentityPub: aliceKeys[0].PubKey(),
|
|
|
|
FundingOutpoint: *prevOut,
|
2018-05-02 01:27:20 +02:00
|
|
|
ShortChannelID: shortChanID,
|
2020-01-06 11:42:04 +01:00
|
|
|
ChanType: chanType,
|
2021-07-15 02:16:13 +02:00
|
|
|
IsInitiator: isAliceInitiator,
|
2018-04-30 00:31:32 +02:00
|
|
|
Capacity: channelCapacity,
|
|
|
|
RemoteCurrentRevocation: bobCommitPoint,
|
|
|
|
RevocationProducer: alicePreimageProducer,
|
|
|
|
RevocationStore: shachain.NewRevocationStore(),
|
2020-11-18 22:45:35 +01:00
|
|
|
LocalCommitment: aliceLocalCommit,
|
|
|
|
RemoteCommitment: aliceRemoteCommit,
|
2021-09-21 19:18:17 +02:00
|
|
|
Db: dbAlice.ChannelStateDB(),
|
2018-04-30 00:31:32 +02:00
|
|
|
Packager: channeldb.NewChannelPackager(shortChanID),
|
|
|
|
FundingTxn: testTx,
|
|
|
|
}
|
|
|
|
bobChannelState := &channeldb.OpenChannel{
|
|
|
|
LocalChanCfg: bobCfg,
|
|
|
|
RemoteChanCfg: aliceCfg,
|
|
|
|
IdentityPub: bobKeys[0].PubKey(),
|
|
|
|
FundingOutpoint: *prevOut,
|
2018-05-02 01:27:20 +02:00
|
|
|
ShortChannelID: shortChanID,
|
2020-01-06 11:42:04 +01:00
|
|
|
ChanType: chanType,
|
2021-07-15 02:16:13 +02:00
|
|
|
IsInitiator: !isAliceInitiator,
|
2018-04-30 00:31:32 +02:00
|
|
|
Capacity: channelCapacity,
|
|
|
|
RemoteCurrentRevocation: aliceCommitPoint,
|
|
|
|
RevocationProducer: bobPreimageProducer,
|
|
|
|
RevocationStore: shachain.NewRevocationStore(),
|
2020-11-18 22:45:35 +01:00
|
|
|
LocalCommitment: bobLocalCommit,
|
|
|
|
RemoteCommitment: bobRemoteCommit,
|
2021-09-21 19:18:17 +02:00
|
|
|
Db: dbBob.ChannelStateDB(),
|
2018-04-30 00:31:32 +02:00
|
|
|
Packager: channeldb.NewChannelPackager(shortChanID),
|
|
|
|
}
|
|
|
|
|
2019-01-16 15:47:43 +01:00
|
|
|
aliceSigner := &input.MockSigner{Privkeys: aliceKeys}
|
|
|
|
bobSigner := &input.MockSigner{Privkeys: bobKeys}
|
2018-04-30 00:31:32 +02:00
|
|
|
|
|
|
|
// TODO(roasbeef): make mock version of pre-image store
|
multi: replace per channel sigPool with global daemon level sigPool
In this commit, we remove the per channel `sigPool` within the
`lnwallet.LightningChannel` struct. With this change, we ensure that as
the number of channels grows, the number of gouroutines idling in the
sigPool stays constant. It's the case that currently on the daemon, most
channels are likely inactive, with only a hand full actually
consistently carrying out channel updates. As a result, this change
should reduce the amount of idle CPU usage, as we have less active
goroutines in select loops.
In order to make this change, the `SigPool` itself has been publicly
exported such that outside callers can make a `SigPool` and pass it into
newly created channels. Since the sig pool now lives outside the
channel, we were also able to do away with the Stop() method on the
channel all together.
Finally, the server is the sub-system that is currently responsible for
managing the `SigPool` within lnd.
2018-12-15 01:35:07 +01:00
|
|
|
|
|
|
|
alicePool := NewSigPool(1, aliceSigner)
|
2018-04-30 00:31:32 +02:00
|
|
|
channelAlice, err := NewLightningChannel(
|
2019-04-15 14:24:43 +02:00
|
|
|
aliceSigner, aliceChannelState, alicePool,
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
multi: replace per channel sigPool with global daemon level sigPool
In this commit, we remove the per channel `sigPool` within the
`lnwallet.LightningChannel` struct. With this change, we ensure that as
the number of channels grows, the number of gouroutines idling in the
sigPool stays constant. It's the case that currently on the daemon, most
channels are likely inactive, with only a hand full actually
consistently carrying out channel updates. As a result, this change
should reduce the amount of idle CPU usage, as we have less active
goroutines in select loops.
In order to make this change, the `SigPool` itself has been publicly
exported such that outside callers can make a `SigPool` and pass it into
newly created channels. Since the sig pool now lives outside the
channel, we were also able to do away with the Stop() method on the
channel all together.
Finally, the server is the sub-system that is currently responsible for
managing the `SigPool` within lnd.
2018-12-15 01:35:07 +01:00
|
|
|
alicePool.Start()
|
|
|
|
|
2020-01-06 11:42:03 +01:00
|
|
|
obfuscator := createStateHintObfuscator(aliceChannelState)
|
|
|
|
|
multi: replace per channel sigPool with global daemon level sigPool
In this commit, we remove the per channel `sigPool` within the
`lnwallet.LightningChannel` struct. With this change, we ensure that as
the number of channels grows, the number of gouroutines idling in the
sigPool stays constant. It's the case that currently on the daemon, most
channels are likely inactive, with only a hand full actually
consistently carrying out channel updates. As a result, this change
should reduce the amount of idle CPU usage, as we have less active
goroutines in select loops.
In order to make this change, the `SigPool` itself has been publicly
exported such that outside callers can make a `SigPool` and pass it into
newly created channels. Since the sig pool now lives outside the
channel, we were also able to do away with the Stop() method on the
channel all together.
Finally, the server is the sub-system that is currently responsible for
managing the `SigPool` within lnd.
2018-12-15 01:35:07 +01:00
|
|
|
bobPool := NewSigPool(1, bobSigner)
|
2018-04-30 00:31:32 +02:00
|
|
|
channelBob, err := NewLightningChannel(
|
2019-04-15 14:24:43 +02:00
|
|
|
bobSigner, bobChannelState, bobPool,
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
multi: replace per channel sigPool with global daemon level sigPool
In this commit, we remove the per channel `sigPool` within the
`lnwallet.LightningChannel` struct. With this change, we ensure that as
the number of channels grows, the number of gouroutines idling in the
sigPool stays constant. It's the case that currently on the daemon, most
channels are likely inactive, with only a hand full actually
consistently carrying out channel updates. As a result, this change
should reduce the amount of idle CPU usage, as we have less active
goroutines in select loops.
In order to make this change, the `SigPool` itself has been publicly
exported such that outside callers can make a `SigPool` and pass it into
newly created channels. Since the sig pool now lives outside the
channel, we were also able to do away with the Stop() method on the
channel all together.
Finally, the server is the sub-system that is currently responsible for
managing the `SigPool` within lnd.
2018-12-15 01:35:07 +01:00
|
|
|
bobPool.Start()
|
2018-04-30 00:31:32 +02:00
|
|
|
|
|
|
|
err = SetStateNumHint(
|
2020-01-06 11:42:03 +01:00
|
|
|
aliceCommitTx, 0, obfuscator,
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
err = SetStateNumHint(
|
2020-01-06 11:42:03 +01:00
|
|
|
bobCommitTx, 0, obfuscator,
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
2019-09-06 13:14:38 +02:00
|
|
|
addr := &net.TCPAddr{
|
|
|
|
IP: net.ParseIP("127.0.0.1"),
|
|
|
|
Port: 18556,
|
|
|
|
}
|
|
|
|
if err := channelAlice.channelState.SyncPending(addr, 101); err != nil {
|
2018-04-30 00:31:32 +02:00
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
2019-09-06 13:14:38 +02:00
|
|
|
|
|
|
|
addr = &net.TCPAddr{
|
|
|
|
IP: net.ParseIP("127.0.0.1"),
|
|
|
|
Port: 18555,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := channelBob.channelState.SyncPending(addr, 101); err != nil {
|
2018-04-30 00:31:32 +02:00
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanUpFunc := func() {
|
|
|
|
os.RemoveAll(bobPath)
|
|
|
|
os.RemoveAll(alicePath)
|
|
|
|
|
multi: replace per channel sigPool with global daemon level sigPool
In this commit, we remove the per channel `sigPool` within the
`lnwallet.LightningChannel` struct. With this change, we ensure that as
the number of channels grows, the number of gouroutines idling in the
sigPool stays constant. It's the case that currently on the daemon, most
channels are likely inactive, with only a hand full actually
consistently carrying out channel updates. As a result, this change
should reduce the amount of idle CPU usage, as we have less active
goroutines in select loops.
In order to make this change, the `SigPool` itself has been publicly
exported such that outside callers can make a `SigPool` and pass it into
newly created channels. Since the sig pool now lives outside the
channel, we were also able to do away with the Stop() method on the
channel all together.
Finally, the server is the sub-system that is currently responsible for
managing the `SigPool` within lnd.
2018-12-15 01:35:07 +01:00
|
|
|
alicePool.Stop()
|
|
|
|
bobPool.Stop()
|
2018-04-30 00:31:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now that the channel are open, simulate the start of a session by
|
|
|
|
// having Alice and Bob extend their revocation windows to each other.
|
|
|
|
err = initRevocationWindows(channelAlice, channelBob)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return channelAlice, channelBob, cleanUpFunc, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// initRevocationWindows simulates a new channel being opened within the p2p
|
|
|
|
// network by populating the initial revocation windows of the passed
|
|
|
|
// commitment state machines.
|
|
|
|
func initRevocationWindows(chanA, chanB *LightningChannel) error {
|
|
|
|
aliceNextRevoke, err := chanA.NextRevocationKey()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := chanB.InitNextRevocation(aliceNextRevoke); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bobNextRevoke, err := chanB.NextRevocationKey()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := chanA.InitNextRevocation(bobNextRevoke); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// pubkeyFromHex parses a Bitcoin public key from a hex encoded string.
|
|
|
|
func pubkeyFromHex(keyHex string) (*btcec.PublicKey, error) {
|
|
|
|
bytes, err := hex.DecodeString(keyHex)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-02-23 14:48:00 +01:00
|
|
|
return btcec.ParsePubKey(bytes)
|
2018-04-30 00:31:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// privkeyFromHex parses a Bitcoin private key from a hex encoded string.
|
|
|
|
func privkeyFromHex(keyHex string) (*btcec.PrivateKey, error) {
|
|
|
|
bytes, err := hex.DecodeString(keyHex)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-02-23 14:48:00 +01:00
|
|
|
key, _ := btcec.PrivKeyFromBytes(bytes)
|
2018-04-30 00:31:32 +02:00
|
|
|
return key, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// blockFromHex parses a full Bitcoin block from a hex encoded string.
|
|
|
|
func blockFromHex(blockHex string) (*btcutil.Block, error) {
|
|
|
|
bytes, err := hex.DecodeString(blockHex)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return btcutil.NewBlockFromBytes(bytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
// txFromHex parses a full Bitcoin transaction from a hex encoded string.
|
|
|
|
func txFromHex(txHex string) (*btcutil.Tx, error) {
|
|
|
|
bytes, err := hex.DecodeString(txHex)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return btcutil.NewTxFromBytes(bytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
// calcStaticFee calculates appropriate fees for commitment transactions. This
|
|
|
|
// function provides a simple way to allow test balance assertions to take fee
|
|
|
|
// calculations into account.
|
|
|
|
//
|
|
|
|
// TODO(bvu): Refactor when dynamic fee estimation is added.
|
2020-03-10 09:33:38 +01:00
|
|
|
func calcStaticFee(chanType channeldb.ChannelType, numHTLCs int) btcutil.Amount {
|
2018-04-30 00:31:32 +02:00
|
|
|
const (
|
2020-03-10 09:33:38 +01:00
|
|
|
htlcWeight = 172
|
|
|
|
feePerKw = btcutil.Amount(24/4) * 1000
|
2018-04-30 00:31:32 +02:00
|
|
|
)
|
2020-03-10 09:33:38 +01:00
|
|
|
return feePerKw *
|
|
|
|
(btcutil.Amount(CommitWeight(chanType) +
|
|
|
|
htlcWeight*int64(numHTLCs))) / 1000
|
2018-04-30 00:31:32 +02:00
|
|
|
}
|
2019-03-13 03:11:09 +01:00
|
|
|
|
|
|
|
// ForceStateTransition executes the necessary interaction between the two
|
|
|
|
// commitment state machines to transition to a new state locking in any
|
|
|
|
// pending updates. This method is useful when testing interactions between two
|
|
|
|
// live state machines.
|
|
|
|
func ForceStateTransition(chanA, chanB *LightningChannel) error {
|
multi: address lingering TODO by no longer wiping out local HTLCs on remote close
In this commit, we fix a lingering TOOD statement in the channel arb.
Before this commitment, we would simply wipe our our local HTLC set of
the HTLC set that was on the remote commitment transaction on force
close. This was incorrect as if our commitment transaction had an HTLC
that the remote commitment didn't, then we would fail to cancel that
back, and cause both channels to time out on chain.
In order to remedy this, we introduce a new `HtlcSetKey` struct to track
all 3 possible in-flight set of HTLCs: ours, theirs, and their pending.
We also we start to tack on additional data to all the unilateral close
messages we send to subscribers. This new data is the CommitSet, or the
set of valid commitments at channel closure time. This new information
will be used by the channel arb in an upcoming commit to ensure it will
cancel back HTLCs in the case of split commitment state.
Finally, we start to thread through an optional *CommitSet to the
advanceState method. This additional information will give the channel
arb addition information it needs to ensure it properly cancels back
HTLCs that are about to time out or may time out depending on which
commitment is played.
Within the htlcswitch pakage, we modify the `SignNextCommitment` method
to return the new set of pending HTLCs for the remote party's commitment
transaction and `ReceiveRevocation` to return the latest set of
commitment transactions on the remote party's commitment as well. This
is a preparatory change which is part of a larger change to address a
lingering TODO in the cnct.
Additionally, rather than just send of the set of HTLCs after the we
revoke, we'll also send of the set of HTLCs after the remote party
revokes, and we create a pending commitment state for it.
2019-05-17 02:23:26 +02:00
|
|
|
aliceSig, aliceHtlcSigs, _, err := chanA.SignNextCommitment()
|
2019-03-13 03:11:09 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err = chanB.ReceiveNewCommitment(aliceSig, aliceHtlcSigs); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bobRevocation, _, err := chanB.RevokeCurrentCommitment()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
multi: address lingering TODO by no longer wiping out local HTLCs on remote close
In this commit, we fix a lingering TOOD statement in the channel arb.
Before this commitment, we would simply wipe our our local HTLC set of
the HTLC set that was on the remote commitment transaction on force
close. This was incorrect as if our commitment transaction had an HTLC
that the remote commitment didn't, then we would fail to cancel that
back, and cause both channels to time out on chain.
In order to remedy this, we introduce a new `HtlcSetKey` struct to track
all 3 possible in-flight set of HTLCs: ours, theirs, and their pending.
We also we start to tack on additional data to all the unilateral close
messages we send to subscribers. This new data is the CommitSet, or the
set of valid commitments at channel closure time. This new information
will be used by the channel arb in an upcoming commit to ensure it will
cancel back HTLCs in the case of split commitment state.
Finally, we start to thread through an optional *CommitSet to the
advanceState method. This additional information will give the channel
arb addition information it needs to ensure it properly cancels back
HTLCs that are about to time out or may time out depending on which
commitment is played.
Within the htlcswitch pakage, we modify the `SignNextCommitment` method
to return the new set of pending HTLCs for the remote party's commitment
transaction and `ReceiveRevocation` to return the latest set of
commitment transactions on the remote party's commitment as well. This
is a preparatory change which is part of a larger change to address a
lingering TODO in the cnct.
Additionally, rather than just send of the set of HTLCs after the we
revoke, we'll also send of the set of HTLCs after the remote party
revokes, and we create a pending commitment state for it.
2019-05-17 02:23:26 +02:00
|
|
|
bobSig, bobHtlcSigs, _, err := chanB.SignNextCommitment()
|
2019-03-13 03:11:09 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
multi: address lingering TODO by no longer wiping out local HTLCs on remote close
In this commit, we fix a lingering TOOD statement in the channel arb.
Before this commitment, we would simply wipe our our local HTLC set of
the HTLC set that was on the remote commitment transaction on force
close. This was incorrect as if our commitment transaction had an HTLC
that the remote commitment didn't, then we would fail to cancel that
back, and cause both channels to time out on chain.
In order to remedy this, we introduce a new `HtlcSetKey` struct to track
all 3 possible in-flight set of HTLCs: ours, theirs, and their pending.
We also we start to tack on additional data to all the unilateral close
messages we send to subscribers. This new data is the CommitSet, or the
set of valid commitments at channel closure time. This new information
will be used by the channel arb in an upcoming commit to ensure it will
cancel back HTLCs in the case of split commitment state.
Finally, we start to thread through an optional *CommitSet to the
advanceState method. This additional information will give the channel
arb addition information it needs to ensure it properly cancels back
HTLCs that are about to time out or may time out depending on which
commitment is played.
Within the htlcswitch pakage, we modify the `SignNextCommitment` method
to return the new set of pending HTLCs for the remote party's commitment
transaction and `ReceiveRevocation` to return the latest set of
commitment transactions on the remote party's commitment as well. This
is a preparatory change which is part of a larger change to address a
lingering TODO in the cnct.
Additionally, rather than just send of the set of HTLCs after the we
revoke, we'll also send of the set of HTLCs after the remote party
revokes, and we create a pending commitment state for it.
2019-05-17 02:23:26 +02:00
|
|
|
if _, _, _, _, err := chanA.ReceiveRevocation(bobRevocation); err != nil {
|
2019-03-13 03:11:09 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := chanA.ReceiveNewCommitment(bobSig, bobHtlcSigs); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
aliceRevocation, _, err := chanA.RevokeCurrentCommitment()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
multi: address lingering TODO by no longer wiping out local HTLCs on remote close
In this commit, we fix a lingering TOOD statement in the channel arb.
Before this commitment, we would simply wipe our our local HTLC set of
the HTLC set that was on the remote commitment transaction on force
close. This was incorrect as if our commitment transaction had an HTLC
that the remote commitment didn't, then we would fail to cancel that
back, and cause both channels to time out on chain.
In order to remedy this, we introduce a new `HtlcSetKey` struct to track
all 3 possible in-flight set of HTLCs: ours, theirs, and their pending.
We also we start to tack on additional data to all the unilateral close
messages we send to subscribers. This new data is the CommitSet, or the
set of valid commitments at channel closure time. This new information
will be used by the channel arb in an upcoming commit to ensure it will
cancel back HTLCs in the case of split commitment state.
Finally, we start to thread through an optional *CommitSet to the
advanceState method. This additional information will give the channel
arb addition information it needs to ensure it properly cancels back
HTLCs that are about to time out or may time out depending on which
commitment is played.
Within the htlcswitch pakage, we modify the `SignNextCommitment` method
to return the new set of pending HTLCs for the remote party's commitment
transaction and `ReceiveRevocation` to return the latest set of
commitment transactions on the remote party's commitment as well. This
is a preparatory change which is part of a larger change to address a
lingering TODO in the cnct.
Additionally, rather than just send of the set of HTLCs after the we
revoke, we'll also send of the set of HTLCs after the remote party
revokes, and we create a pending commitment state for it.
2019-05-17 02:23:26 +02:00
|
|
|
if _, _, _, _, err := chanB.ReceiveRevocation(aliceRevocation); err != nil {
|
2019-03-13 03:11:09 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|