Merge pull request #1579 from Roasbeef/gcs-modifications

multi: update primary interfaces to be compatible with latest version of BIP 158, use latest btcd+neutrino+btcwallet
This commit is contained in:
Olaoluwa Osuntokun 2018-08-01 12:41:09 -07:00 committed by GitHub
commit f6ea91af71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 646 additions and 340 deletions

10
Gopkg.lock generated
View File

@ -79,7 +79,7 @@
"txscript",
"wire"
]
revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
revision = "9a2f9524024889e129a5422aca2cff73cb3eabf6"
[[projects]]
name = "github.com/btcsuite/btclog"
@ -97,7 +97,7 @@
"hdkeychain",
"txsort"
]
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b"
[[projects]]
name = "github.com/btcsuite/btcwallet"
@ -118,7 +118,7 @@
"walletdb/bdb",
"wtxmgr"
]
revision = "64b5b448f5e6853a2d870f388504a7807bc951f1"
revision = "a4d9da433fcfaeec50d3e9657e6d511d14cddadf"
[[projects]]
branch = "master"
@ -231,7 +231,7 @@
"filterdb",
"headerfs"
]
revision = "03f4c660ea0d1586331f32561185d45eab1ba4c9"
revision = "d5054cea8fe43c324a473e8aa7e0f6dd93622125"
[[projects]]
name = "github.com/lightningnetwork/lightning-onion"
@ -404,6 +404,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "7ac5bd06ab8aa8f6a01f191092ac37d1e33200f366fa3b52fb4152369d76c5be"
inputs-digest = "dcfe757e222cc26b43d926797fb0cb9f87a18da54dca6615e701eb715c35b375"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -44,7 +44,7 @@
[[constraint]]
name = "github.com/lightninglabs/neutrino"
revision = "03f4c660ea0d1586331f32561185d45eab1ba4c9"
revision = "d5054cea8fe43c324a473e8aa7e0f6dd93622125"
[[constraint]]
name = "github.com/lightningnetwork/lightning-onion"
@ -64,15 +64,15 @@
[[constraint]]
name = "github.com/btcsuite/btcutil"
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b"
[[constraint]]
name = "github.com/btcsuite/btcd"
revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
revision = "9a2f9524024889e129a5422aca2cff73cb3eabf6"
[[constraint]]
name = "github.com/btcsuite/btcwallet"
revision = "64b5b448f5e6853a2d870f388504a7807bc951f1"
revision = "a4d9da433fcfaeec50d3e9657e6d511d14cddadf"
[[constraint]]
name = "github.com/tv42/zbase32"

View File

@ -196,8 +196,10 @@ func (b *breachArbiter) Start() error {
// Register for a notification when the breach transaction is
// confirmed on chain.
breachTXID := retInfo.commitHash
breachScript := retInfo.breachedOutputs[0].signDesc.Output.PkScript
confChan, err := b.cfg.Notifier.RegisterConfirmationsNtfn(
&breachTXID, 1, retInfo.breachHeight)
&breachTXID, breachScript, 1, retInfo.breachHeight,
)
if err != nil {
brarLog.Errorf("unable to register for conf updates "+
"for txid: %v, err: %v", breachTXID, err)
@ -296,6 +298,7 @@ func convertToSecondLevelRevoke(bo *breachedOutput, breachInfo *retributionInfo,
newAmt := spendingTx.TxOut[0].Value
bo.amt = btcutil.Amount(newAmt)
bo.signDesc.Output.Value = newAmt
bo.signDesc.Output.PkScript = spendingTx.TxOut[0].PkScript
// Finally, we'll need to adjust the witness program in the
// SignDescriptor.
@ -357,6 +360,7 @@ func (b *breachArbiter) waitForSpendEvent(breachInfo *retributionInfo,
var err error
spendNtfn, err = b.cfg.Notifier.RegisterSpendNtfn(
&breachedOutput.outpoint,
breachedOutput.signDesc.Output.PkScript,
breachInfo.breachHeight,
)
if err != nil {
@ -556,8 +560,10 @@ justiceTxBroadcast:
// notify the caller that initiated the retribution workflow that the
// deed has been done.
justiceTXID := finalTx.TxHash()
justiceScript := finalTx.TxOut[0].PkScript
confChan, err = b.cfg.Notifier.RegisterConfirmationsNtfn(
&justiceTXID, 1, breachConfHeight)
&justiceTXID, justiceScript, 1, breachConfHeight,
)
if err != nil {
brarLog.Errorf("unable to register for conf for txid(%v): %v",
justiceTXID, err)
@ -720,8 +726,10 @@ func (b *breachArbiter) handleBreachHandoff(breachEvent *ContractBreachEvent) {
// confirmed in the chain to ensure we're not dealing with a moving
// target.
breachTXID := &retInfo.commitHash
cfChan, err := b.cfg.Notifier.RegisterConfirmationsNtfn(breachTXID, 1,
retInfo.breachHeight)
breachScript := retInfo.breachedOutputs[0].signDesc.Output.PkScript
cfChan, err := b.cfg.Notifier.RegisterConfirmationsNtfn(
breachTXID, breachScript, 1, retInfo.breachHeight,
)
if err != nil {
brarLog.Errorf("unable to register for conf updates for "+
"txid: %v, err: %v", breachTXID, err)

View File

@ -18,7 +18,12 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btclog"
"github.com/btcsuite/btcutil"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
@ -27,11 +32,6 @@ import (
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
var (
@ -1012,6 +1012,11 @@ func TestBreachHandoffSuccess(t *testing.T) {
ProcessACK: make(chan error, 1),
BreachRetribution: &lnwallet.BreachRetribution{
BreachTransaction: bobClose.CloseTx,
LocalOutputSignDesc: &lnwallet.SignDescriptor{
Output: &wire.TxOut{
PkScript: breachKeys[0],
},
},
},
}
contractBreaches <- breach
@ -1039,6 +1044,11 @@ func TestBreachHandoffSuccess(t *testing.T) {
ProcessACK: make(chan error, 1),
BreachRetribution: &lnwallet.BreachRetribution{
BreachTransaction: bobClose.CloseTx,
LocalOutputSignDesc: &lnwallet.SignDescriptor{
Output: &wire.TxOut{
PkScript: breachKeys[0],
},
},
},
}
@ -1083,6 +1093,11 @@ func TestBreachHandoffFail(t *testing.T) {
ProcessACK: make(chan error, 1),
BreachRetribution: &lnwallet.BreachRetribution{
BreachTransaction: bobClose.CloseTx,
LocalOutputSignDesc: &lnwallet.SignDescriptor{
Output: &wire.TxOut{
PkScript: breachKeys[0],
},
},
},
}
contractBreaches <- breach
@ -1130,6 +1145,11 @@ func TestBreachHandoffFail(t *testing.T) {
ProcessACK: make(chan error, 1),
BreachRetribution: &lnwallet.BreachRetribution{
BreachTransaction: bobClose.CloseTx,
LocalOutputSignDesc: &lnwallet.SignDescriptor{
Output: &wire.TxOut{
PkScript: breachKeys[0],
},
},
},
}

View File

@ -577,7 +577,7 @@ type spendCancel struct {
// across the 'Spend' channel. The heightHint should represent the earliest
// height in the chain where the transaction could have been spent in.
func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
ntfn := &spendNotification{
targetOutpoint: outpoint,
@ -784,7 +784,7 @@ type confirmationNotification struct {
// which will be triggered once the txid reaches numConfs number of
// confirmations.
func (b *BitcoindNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
_ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
ntfn := &confirmationNotification{
ConfNtfn: chainntnfs.ConfNtfn{

View File

@ -695,7 +695,7 @@ type spendCancel struct {
// across the 'Spend' channel. The heightHint should represent the earliest
// height in the chain where the transaction could have been spent in.
func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
ntfn := &spendNotification{
targetOutpoint: outpoint,
@ -710,6 +710,7 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
case b.notificationRegistry <- ntfn:
}
// TODO(roasbeef): update btcd rescan logic to also use both
if err := b.chainConn.NotifySpent([]*wire.OutPoint{outpoint}); err != nil {
return nil, err
}
@ -822,7 +823,7 @@ type confirmationNotification struct {
// RegisterConfirmationsNtfn registers a notification with BtcdNotifier
// which will be triggered once the txid reaches numConfs number of
// confirmations.
func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, _ []byte,
numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
ntfn := &confirmationNotification{

View File

@ -20,23 +20,27 @@ import (
// resource
type ChainNotifier interface {
// RegisterConfirmationsNtfn registers an intent to be notified once
// txid reaches numConfs confirmations. The returned ConfirmationEvent
// should properly notify the client once the specified number of
// confirmations has been reached for the txid, as well as if the
// original tx gets re-org'd out of the mainchain. The heightHint
// parameter is provided as a convenience to light clients. The
// heightHint denotes the earliest height in the blockchain in which the
// target txid _could_ have been included in the chain. This can be
// used to bound the search space when checking to see if a
// notification can immediately be dispatched due to historical data.
// txid reaches numConfs confirmations. We also pass in the pkScript as
// the default light client instead needs to match on scripts created
// in the block. The returned ConfirmationEvent should properly notify
// the client once the specified number of confirmations has been
// reached for the txid, as well as if the original tx gets re-org'd
// out of the mainchain. The heightHint parameter is provided as a
// convenience to light clients. The heightHint denotes the earliest
// height in the blockchain in which the target txid _could_ have been
// included in the chain. This can be used to bound the search space
// when checking to see if a notification can immediately be dispatched
// due to historical data.
//
// NOTE: Dispatching notifications to multiple clients subscribed to
// the same (txid, numConfs) tuple MUST be supported.
RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs,
RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, numConfs,
heightHint uint32) (*ConfirmationEvent, error)
// RegisterSpendNtfn registers an intent to be notified once the target
// outpoint is successfully spent within a transaction. The returned
// outpoint is successfully spent within a transaction. The script that
// the outpoint creates must also be specified. This allows this
// interface to be implemented by BIP 158-like filtering. The returned
// SpendEvent will receive a send on the 'Spend' transaction once a
// transaction spending the input is detected on the blockchain. The
// heightHint parameter is provided as a convenience to light clients.
@ -48,7 +52,7 @@ type ChainNotifier interface {
//
// NOTE: Dispatching notifications to multiple clients subscribed to a
// spend of the same outpoint MUST be supported.
RegisterSpendNtfn(outpoint *wire.OutPoint,
RegisterSpendNtfn(outpoint *wire.OutPoint, pkScript []byte,
heightHint uint32) (*SpendEvent, error)
// RegisterBlockEpochNtfn registers an intent to be notified of each

View File

@ -58,10 +58,10 @@ var (
testAddr = addrPk.AddressPubKeyHash()
)
func getTestTxId(miner *rpctest.Harness) (*chainhash.Hash, error) {
func getTestTxIdAndScript(miner *rpctest.Harness) (*chainhash.Hash, []byte, error) {
script, err := txscript.PayToAddrScript(testAddr)
if err != nil {
return nil, err
return nil, nil, err
}
outputs := []*wire.TxOut{
@ -70,7 +70,13 @@ func getTestTxId(miner *rpctest.Harness) (*chainhash.Hash, error) {
PkScript: script,
},
}
return miner.SendOutputs(outputs, 10)
txid, err := miner.SendOutputs(outputs, 10)
if err != nil {
return nil, nil, err
}
return txid, script, nil
}
func waitForMempoolTx(r *rpctest.Harness, txid *chainhash.Hash) error {
@ -116,7 +122,7 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
// We're spending from a coinbase output here, so we use the dedicated
// function.
txid, err := getTestTxId(miner)
txid, pkScript, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -134,8 +140,9 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
// Now that we have a txid, register a confirmation notification with
// the chainntfn source.
numConfs := uint32(1)
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
uint32(currentHeight))
confIntent, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -184,7 +191,7 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
//
// Again, we'll begin by creating a fresh transaction, so we can obtain
// a fresh txid.
txid, err := getTestTxId(miner)
txid, pkScript, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test addr: %v", err)
}
@ -200,8 +207,9 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
}
numConfs := uint32(6)
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
uint32(currentHeight))
confIntent, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -242,12 +250,13 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
// verify they're each notified at the proper number of confirmations
// below.
for i, numConfs := range confSpread {
txid, err := getTestTxId(miner)
txid, pkScript, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test addr: %v", err)
}
confIntent, err := notifier.RegisterConfirmationsNtfn(txid,
numConfs, uint32(currentHeight))
confIntent, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -303,7 +312,7 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
func createSpendableOutput(miner *rpctest.Harness,
t *testing.T) (*wire.OutPoint, []byte) {
txid, err := getTestTxId(miner)
txid, _, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test addr: %v", err)
}
@ -411,8 +420,9 @@ func testSpendNotification(miner *rpctest.Harness,
const numClients = 5
spendClients := make([]*chainntnfs.SpendEvent, numClients)
for i := 0; i < numClients; i++ {
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
uint32(currentHeight))
spentIntent, err := notifier.RegisterSpendNtfn(
outpoint, pkScript, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", err)
}
@ -462,8 +472,9 @@ func testSpendNotification(miner *rpctest.Harness,
// Make sure registering a client after the tx is in the mempool still
// doesn't trigger a notification.
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
uint32(currentHeight))
spentIntent, err := notifier.RegisterSpendNtfn(
outpoint, pkScript, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", err)
}
@ -554,7 +565,7 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
// We'd like to test the case of a multiple clients registered to
// receive a confirmation notification for the same transaction.
txid, err := getTestTxId(miner)
txid, pkScript, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -578,8 +589,9 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
// Register for a conf notification for the above generated txid with
// numConfsClients distinct clients.
for i := 0; i < numConfsClients; i++ {
confClient, err := notifier.RegisterConfirmationsNtfn(txid,
numConfs, uint32(currentHeight))
confClient, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register for confirmation: %v", err)
}
@ -620,7 +632,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// spending from a coinbase output here, so we use the dedicated
// function.
txid3, err := getTestTxId(miner)
txid3, pkScript3, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -640,7 +652,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
t.Fatalf("unable to generate block: %v", err)
}
txid1, err := getTestTxId(miner)
txid1, pkScript1, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -650,7 +662,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err)
}
txid2, err := getTestTxId(miner)
txid2, pkScript2, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -675,8 +687,9 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// which is included in the last block. The height hint is the height before
// the block is included. This notification should fire immediately since
// only 1 confirmation is required.
ntfn1, err := notifier.RegisterConfirmationsNtfn(txid1, 1,
uint32(currentHeight))
ntfn1, err := notifier.RegisterConfirmationsNtfn(
txid1, pkScript1, 1, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -713,8 +726,9 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// Register a confirmation notification for tx2, requiring 3 confirmations.
// This transaction is only partially confirmed, so the notification should
// not fire yet.
ntfn2, err := notifier.RegisterConfirmationsNtfn(txid2, 3,
uint32(currentHeight))
ntfn2, err := notifier.RegisterConfirmationsNtfn(
txid2, pkScript2, 3, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -740,8 +754,9 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// Finally register a confirmation notification for tx3, requiring 1
// confirmation. Ensure that conf notifications do not refire on txs
// 1 or 2.
ntfn3, err := notifier.RegisterConfirmationsNtfn(txid3, 1,
uint32(currentHeight-1))
ntfn3, err := notifier.RegisterConfirmationsNtfn(
txid3, pkScript3, 1, uint32(currentHeight-1),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -775,7 +790,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
// Create a transaction to be notified about. We'll register for
// notifications on this transaction but won't be prompt in checking them
txid, err := getTestTxId(miner)
txid, pkScript, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -798,8 +813,9 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
t.Fatalf("unable to generate blocks: %v", err)
}
firstConfIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
uint32(currentHeight))
firstConfIntent, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -812,7 +828,7 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
// Now make another transaction, just because we haven't checked to see
// if the first transaction has confirmed doesn't mean that we shouldn't
// be able to see if this transaction confirms first
txid, err = getTestTxId(miner)
txid, pkScript, err = getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -829,9 +845,9 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
numConfs = 1
secondConfIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
uint32(currentHeight))
secondConfIntent, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}
@ -904,8 +920,9 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
const numClients = 2
spendClients := make([]*chainntnfs.SpendEvent, numClients)
for i := 0; i < numClients; i++ {
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
uint32(currentHeight))
spentIntent, err := notifier.RegisterSpendNtfn(
outpoint, pkScript, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register for spend ntfn: %v",
err)
@ -984,8 +1001,9 @@ func testCancelSpendNtfn(node *rpctest.Harness,
const numClients = 2
spendClients := make([]*chainntnfs.SpendEvent, numClients)
for i := 0; i < numClients; i++ {
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
uint32(currentHeight))
spentIntent, err := notifier.RegisterSpendNtfn(
outpoint, pkScript, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", err)
}
@ -1150,7 +1168,7 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.ChainNotifier,
t.Fatalf("unable to remove node: %v", err)
}
txid, err := getTestTxId(miner)
txid, pkScript, err := getTestTxIdAndScript(miner)
if err != nil {
t.Fatalf("unable to create test tx: %v", err)
}
@ -1168,8 +1186,9 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.ChainNotifier,
// Now that we have a txid, register a confirmation notification with
// the chainntfn source.
numConfs := uint32(2)
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
uint32(currentHeight))
confIntent, err := notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
if err != nil {
t.Fatalf("unable to register ntfn: %v", err)
}

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/gcs/builder"
@ -133,7 +134,7 @@ func (n *NeutrinoNotifier) Start() error {
// required that a user MUST set an addr/outpoint/txid when creating a
// rescan. To get around this, we'll add a "zero" outpoint, that won't
// actually be matched.
var zeroHash chainhash.Hash
var zeroInput neutrino.InputWithScript
rescanOptions := []neutrino.RescanOption{
neutrino.StartBlock(startingPoint),
neutrino.QuitChan(n.quit),
@ -143,11 +144,12 @@ func (n *NeutrinoNotifier) Start() error {
OnFilteredBlockDisconnected: n.onFilteredBlockDisconnected,
},
),
neutrino.WatchTxIDs(zeroHash),
neutrino.WatchInputs(zeroInput),
}
n.txConfNotifier = chainntnfs.NewTxConfNotifier(
bestHeight, reorgSafetyLimit)
bestHeight, reorgSafetyLimit,
)
// Finally, we'll create our rescan struct, start it, and launch all
// the goroutines we need to operate this ChainNotifier instance.
@ -316,8 +318,19 @@ func (n *NeutrinoNotifier) notificationDispatcher() {
defer n.wg.Done()
confDetails, err := n.historicalConfDetails(
msg.TxID, currentHeight,
msg.heightHint,
msg.TxID, msg.pkScript, currentHeight, msg.heightHint,
)
if err != nil {
chainntnfs.Log.Error(err)
}
// We'll map the script into an address
// type so we can instruct neutrino to
// match if the transaction containing
// the script is found in a block.
params := n.p2pNode.ChainParams()
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
msg.pkScript, &params,
)
if err != nil {
chainntnfs.Log.Error(err)
@ -339,7 +352,7 @@ func (n *NeutrinoNotifier) notificationDispatcher() {
// filter so we can be notified of its
// future initial confirmation.
rescanUpdate := []neutrino.UpdateOption{
neutrino.AddTxIDs(*msg.TxID),
neutrino.AddAddrs(addrs...),
neutrino.Rewind(currentHeight),
}
err = n.chainView.Update(rescanUpdate...)
@ -410,9 +423,11 @@ func (n *NeutrinoNotifier) notificationDispatcher() {
}
}
// historicalConfDetails looks up whether a transaction is already included in a
// block in the active chain and, if so, returns details about the confirmation.
// historicalConfDetails looks up whether a transaction is already included in
// a block in the active chain and, if so, returns details about the
// confirmation.
func (n *NeutrinoNotifier) historicalConfDetails(targetHash *chainhash.Hash,
pkScript []byte,
currentHeight, heightHint uint32) (*chainntnfs.TxConfirmation, error) {
// Starting from the height hint, we'll walk forwards in the chain to
@ -437,14 +452,15 @@ func (n *NeutrinoNotifier) historicalConfDetails(targetHash *chainhash.Hash,
// With the hash computed, we can now fetch the basic filter
// for this height.
regFilter, err := n.p2pNode.GetCFilter(blockHash,
wire.GCSFilterRegular)
regFilter, err := n.p2pNode.GetCFilter(
blockHash, wire.GCSFilterRegular,
)
if err != nil {
return nil, fmt.Errorf("unable to retrieve regular filter for "+
"height=%v: %v", scanHeight, err)
}
// If the block has no transactions other than the coinbase
// If the block has no transactions other than the Coinbase
// transaction, then the filter may be nil, so we'll continue
// forward int that case.
if regFilter == nil {
@ -452,9 +468,9 @@ func (n *NeutrinoNotifier) historicalConfDetails(targetHash *chainhash.Hash,
}
// In the case that the filter exists, we'll attempt to see if
// any element in it match our target txid.
// any element in it matches our target public key script.
key := builder.DeriveKey(&blockHash)
match, err := regFilter.Match(key, targetHash[:])
match, err := regFilter.Match(key, pkScript)
if err != nil {
return nil, fmt.Errorf("unable to query filter: %v", err)
}
@ -504,16 +520,15 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
for i, txIn := range mtx.TxIn {
prevOut := txIn.PreviousOutPoint
// If this transaction indeed does spend an output which we have a
// registered notification for, then create a spend summary, finally
// sending off the details to the notification subscriber.
// If this transaction indeed does spend an output
// which we have a registered notification for, then
// create a spend summary, finally sending off the
// details to the notification subscriber.
clients, ok := n.spendNotifications[prevOut]
if !ok {
continue
}
// TODO(roasbeef): many integration tests expect spend to be
// notified within the mempool.
spendDetails := &chainntnfs.SpendDetail{
SpentOutPoint: &prevOut,
SpenderTxHash: &txSha,
@ -523,13 +538,16 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
}
for _, ntfn := range clients {
chainntnfs.Log.Infof("Dispatching spend notification for "+
"outpoint=%v", ntfn.targetOutpoint)
chainntnfs.Log.Infof("Dispatching spend "+
"notification for outpoint=%v",
ntfn.targetOutpoint)
ntfn.spendChan <- spendDetails
// Close spendChan to ensure that any calls to Cancel will not
// block. This is safe to do since the channel is buffered, and
// the message can still be read by the receiver.
// Close spendChan to ensure that any calls to
// Cancel will not block. This is safe to do
// since the channel is buffered, and the
// message can still be read by the receiver.
close(ntfn.spendChan)
}
@ -537,10 +555,12 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
}
}
// A new block has been connected to the main chain.
// Send out any N confirmation notifications which may
// have been triggered by this new block.
n.txConfNotifier.ConnectTip(&newBlock.hash, newBlock.height, newBlock.txns)
// A new block has been connected to the main chain. Send out any N
// confirmation notifications which may have been triggered by this new
// block.
n.txConfNotifier.ConnectTip(
&newBlock.hash, newBlock.height, newBlock.txns,
)
return nil
}
@ -592,7 +612,7 @@ type spendCancel struct {
// target outpoint has been detected, the details of the spending event will be
// sent across the 'Spend' channel.
func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
n.heightMtx.RLock()
currentHeight := n.bestHeight
@ -651,10 +671,15 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
break
}
inputToWatch := neutrino.InputWithScript{
OutPoint: *outpoint,
PkScript: pkScript,
}
// Before sending off the notification request, we'll attempt to see if
// this output is still spent or not at this point in the chain.
spendReport, err := n.p2pNode.GetUtxo(
neutrino.WatchOutPoints(*outpoint),
neutrino.WatchInputs(inputToWatch),
neutrino.StartBlock(&waddrmgr.BlockStamp{
Height: int32(heightHint),
}),
@ -690,7 +715,7 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// If the output is still unspent, then we'll update our rescan's
// filter, and send the request to the dispatcher goroutine.
rescanUpdate := []neutrino.UpdateOption{
neutrino.AddOutPoints(*outpoint),
neutrino.AddInputs(inputToWatch),
neutrino.Rewind(currentHeight),
}
@ -712,12 +737,14 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
type confirmationsNotification struct {
chainntnfs.ConfNtfn
heightHint uint32
pkScript []byte
}
// RegisterConfirmationsNtfn registers a notification with NeutrinoNotifier
// which will be triggered once the txid reaches numConfs number of
// confirmations.
func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
pkScript []byte,
numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
ntfn := &confirmationsNotification{
@ -728,6 +755,7 @@ func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
Event: chainntnfs.NewConfirmationEvent(numConfs),
},
heightHint: heightHint,
pkScript: pkScript,
}
if err := n.txConfNotifier.Register(&ntfn.ConfNtfn); err != nil {

View File

@ -1,13 +1,13 @@
package main
import (
"github.com/lightningnetwork/lnd/keychain"
litecoinCfg "github.com/ltcsuite/ltcd/chaincfg"
litecoinWire "github.com/ltcsuite/ltcd/wire"
"github.com/btcsuite/btcd/chaincfg"
bitcoinCfg "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
bitcoinWire "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/keychain"
litecoinCfg "github.com/ltcsuite/ltcd/chaincfg"
litecoinWire "github.com/ltcsuite/ltcd/wire"
)
// activeNetParams is a pointer to the parameters specific to the currently

View File

@ -10,16 +10,16 @@ import (
"runtime"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
)
var (

View File

@ -2,6 +2,7 @@ package channeldb
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"image/color"
@ -12,6 +13,7 @@ import (
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/coreos/bbolt"
@ -2350,12 +2352,62 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) (*ChannelEdgeInfo, *
return edgeInfo, policy1, policy2, nil
}
// genMultiSigP2WSH generates the p2wsh'd multisig script for 2 of 2 pubkeys.
func genMultiSigP2WSH(aPub, bPub []byte) ([]byte, error) {
if len(aPub) != 33 || len(bPub) != 33 {
return nil, fmt.Errorf("Pubkey size error. Compressed " +
"pubkeys only")
}
// Swap to sort pubkeys if needed. Keys are sorted in lexicographical
// order. The signatures within the scriptSig must also adhere to the
// order, ensuring that the signatures for each public key appears in
// the proper order on the stack.
if bytes.Compare(aPub, bPub) == 1 {
aPub, bPub = bPub, aPub
}
// First, we'll generate the witness script for the multi-sig.
bldr := txscript.NewScriptBuilder()
bldr.AddOp(txscript.OP_2)
bldr.AddData(aPub) // Add both pubkeys (sorted).
bldr.AddData(bPub)
bldr.AddOp(txscript.OP_2)
bldr.AddOp(txscript.OP_CHECKMULTISIG)
witnessScript, err := bldr.Script()
if err != nil {
return nil, err
}
// With the witness script generated, we'll now turn it into a p2sh
// script:
// * OP_0 <sha256(script)>
bldr = txscript.NewScriptBuilder()
bldr.AddOp(txscript.OP_0)
scriptHash := sha256.Sum256(witnessScript)
bldr.AddData(scriptHash[:])
return bldr.Script()
}
// EdgePoint couples the outpoint of a channel with the funding script that it
// creates. The FilteredChainView will use this to watch for spends of this
// edge point on chain. We require both of these values as depending on the
// concrete implementation, either the pkScript, or the out point will be used.
type EdgePoint struct {
// FundingPkScript is the p2wsh multi-sig script of the target channel.
FundingPkScript []byte
// OutPoint is the outpoint of the target channel.
OutPoint wire.OutPoint
}
// ChannelView returns the verifiable edge information for each active channel
// within the known channel graph. The set of UTXO's returned are the ones that
// need to be watched on chain to detect channel closes on the resident
// blockchain.
func (c *ChannelGraph) ChannelView() ([]wire.OutPoint, error) {
var chanPoints []wire.OutPoint
// within the known channel graph. The set of UTXO's (along with their scripts)
// returned are the ones that need to be watched on chain to detect channel
// closes on the resident blockchain.
func (c *ChannelGraph) ChannelView() ([]EdgePoint, error) {
var edgePoints []EdgePoint
if err := c.db.View(func(tx *bolt.Tx) error {
// We're going to iterate over the entire channel index, so
// we'll need to fetch the edgeBucket to get to the index as
@ -2368,11 +2420,15 @@ func (c *ChannelGraph) ChannelView() ([]wire.OutPoint, error) {
if chanIndex == nil {
return ErrGraphNoEdgesFound
}
edgeIndex := edges.Bucket(edgeIndexBucket)
if edgeIndex == nil {
return ErrGraphNoEdgesFound
}
// Once we have the proper bucket, we'll range over each key
// (which is the channel point for the channel) and decode it,
// accumulating each entry.
return chanIndex.ForEach(func(chanPointBytes, _ []byte) error {
return chanIndex.ForEach(func(chanPointBytes, chanID []byte) error {
chanPointReader := bytes.NewReader(chanPointBytes)
var chanPoint wire.OutPoint
@ -2381,14 +2437,33 @@ func (c *ChannelGraph) ChannelView() ([]wire.OutPoint, error) {
return err
}
chanPoints = append(chanPoints, chanPoint)
edgeInfo, err := fetchChanEdgeInfo(
edgeIndex, chanID,
)
if err != nil {
return err
}
pkScript, err := genMultiSigP2WSH(
edgeInfo.BitcoinKey1Bytes[:],
edgeInfo.BitcoinKey2Bytes[:],
)
if err != nil {
return err
}
edgePoints = append(edgePoints, EdgePoint{
FundingPkScript: pkScript,
OutPoint: chanPoint,
})
return nil
})
}); err != nil {
return nil, err
}
return chanPoints, nil
return edgePoints, nil
}
// NewChannelEdgePolicy returns a new blank ChannelEdgePolicy.

View File

@ -997,7 +997,7 @@ func assertNumNodes(t *testing.T, graph *ChannelGraph, n int) {
}
}
func assertChanViewEqual(t *testing.T, a []wire.OutPoint, b []*wire.OutPoint) {
func assertChanViewEqual(t *testing.T, a []EdgePoint, b []EdgePoint) {
if len(a) != len(b) {
_, _, line, _ := runtime.Caller(1)
t.Fatalf("line %v: chan views don't match", line)
@ -1005,14 +1005,34 @@ func assertChanViewEqual(t *testing.T, a []wire.OutPoint, b []*wire.OutPoint) {
chanViewSet := make(map[wire.OutPoint]struct{})
for _, op := range a {
chanViewSet[op] = struct{}{}
chanViewSet[op.OutPoint] = struct{}{}
}
for _, op := range b {
if _, ok := chanViewSet[op.OutPoint]; !ok {
_, _, line, _ := runtime.Caller(1)
t.Fatalf("line %v: chanPoint(%v) not found in first "+
"view", line, op)
}
}
}
func assertChanViewEqualChanPoints(t *testing.T, a []EdgePoint, b []*wire.OutPoint) {
if len(a) != len(b) {
_, _, line, _ := runtime.Caller(1)
t.Fatalf("line %v: chan views don't match", line)
}
chanViewSet := make(map[wire.OutPoint]struct{})
for _, op := range a {
chanViewSet[op.OutPoint] = struct{}{}
}
for _, op := range b {
if _, ok := chanViewSet[*op]; !ok {
_, _, line, _ := runtime.Caller(1)
t.Fatalf("line %v: chanPoint(%v) not found in first view",
line, op)
t.Fatalf("line %v: chanPoint(%v) not found in first "+
"view", line, op)
}
}
}
@ -1056,6 +1076,7 @@ func TestGraphPruning(t *testing.T) {
// With the vertexes created, we'll next create a series of channels
// between them.
channelPoints := make([]*wire.OutPoint, 0, numNodes-1)
edgePoints := make([]EdgePoint, 0, numNodes-1)
for i := 0; i < numNodes-1; i++ {
txHash := sha256.Sum256([]byte{byte(i)})
chanID := uint64(i + 1)
@ -1086,6 +1107,17 @@ func TestGraphPruning(t *testing.T) {
t.Fatalf("unable to add node: %v", err)
}
pkScript, err := genMultiSigP2WSH(
edgeInfo.BitcoinKey1Bytes[:], edgeInfo.BitcoinKey2Bytes[:],
)
if err != nil {
t.Fatalf("unable to gen multi-sig p2wsh: %v", err)
}
edgePoints = append(edgePoints, EdgePoint{
FundingPkScript: pkScript,
OutPoint: op,
})
// Create and add an edge with random data that points from
// node_i -> node_i+1
edge := randEdgePolicy(chanID, op, db)
@ -1113,7 +1145,7 @@ func TestGraphPruning(t *testing.T) {
if err != nil {
t.Fatalf("unable to get graph channel view: %v", err)
}
assertChanViewEqual(t, channelView, channelPoints)
assertChanViewEqual(t, channelView, edgePoints)
// Now with our test graph created, we can test the pruning
// capabilities of the channel graph.
@ -1145,7 +1177,7 @@ func TestGraphPruning(t *testing.T) {
if err != nil {
t.Fatalf("unable to get graph channel view: %v", err)
}
assertChanViewEqual(t, channelView, channelPoints[2:])
assertChanViewEqualChanPoints(t, channelView, channelPoints[2:])
// Next we'll create a block that doesn't close any channels within the
// graph to test the negative error case.

View File

@ -5,13 +5,13 @@ import (
"sync"
"sync/atomic"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
// ResolutionMsg is a message sent by resolvers to outside sub-systems once an
@ -384,22 +384,6 @@ func (c *ChainArbitrator) Start() error {
// the chain any longer, only resolve the contracts on the confirmed
// commitment.
for _, closeChanInfo := range closingChannels {
// If this is a pending cooperative close channel then we'll
// simply launch a goroutine to wait until the closing
// transaction has been confirmed.
// TODO(halseth): can remove this since no coop close channels
// should be "pending close" after the recent changes. Keeping
// it for a bit in case someone with a coop close channel in
// the pending close state upgrades to the new commit.
if closeChanInfo.CloseType == channeldb.CooperativeClose {
go c.watchForChannelClose(closeChanInfo)
// TODO(roasbeef): actually need arb to possibly
// recover from race condition broadcast?
// * if do, can't recover from multi-broadcast
continue
}
blockEpoch, err := c.cfg.Notifier.RegisterBlockEpochNtfn()
if err != nil {
return err
@ -493,46 +477,6 @@ func (c *ChainArbitrator) Stop() error {
return nil
}
// watchForChannelClose is used by the ChainArbitrator to watch for the
// ultimate on-chain conformation of an existing cooperative channel closure.
// This is needed if we started a co-op close, but it wasn't fully confirmed
// before we restarted.
//
// NOTE: This must be launched as a goroutine.
func (c *ChainArbitrator) watchForChannelClose(closeInfo *channeldb.ChannelCloseSummary) {
spendNtfn, err := c.cfg.Notifier.RegisterSpendNtfn(
&closeInfo.ChanPoint, closeInfo.CloseHeight,
)
if err != nil {
log.Errorf("unable to register for spend: %v", err)
return
}
log.Infof("Waiting for ChannelPoint(%v) to be coop closed on chain",
closeInfo.ChanPoint)
var (
commitSpend *chainntnfs.SpendDetail
ok bool
)
select {
case commitSpend, ok = <-spendNtfn.Spend:
if !ok {
return
}
case <-c.quit:
return
}
log.Infof("ChannelPoint(%v) is fully closed, at height: %v",
closeInfo.ChanPoint, commitSpend.SpendingHeight)
if err := c.resolveContract(closeInfo.ChanPoint, nil); err != nil {
log.Errorf("unable to resolve contract: %v", err)
}
}
// ContractSignals wraps the two signals that affect the state of a channel
// being watched by an arbitrator. The two signals we care about are: the
// channel has a new set of HTLC's, and the remote party has just broadcast

View File

@ -173,8 +173,21 @@ func (c *chainWatcher) Start() error {
heightHint = chanState.FundingBroadcastHeight
}
localKey := chanState.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
remoteKey := chanState.RemoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
multiSigScript, err := lnwallet.GenMultiSigScript(
localKey, remoteKey,
)
if err != nil {
return err
}
pkScript, err := lnwallet.WitnessScriptHash(multiSigScript)
if err != nil {
return err
}
spendNtfn, err := c.cfg.notifier.RegisterSpendNtfn(
fundingOut, heightHint,
fundingOut, pkScript, heightHint,
)
if err != nil {
return err

View File

@ -6,18 +6,18 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)
type mockNotifier struct {
spendChan chan *chainntnfs.SpendDetail
}
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs,
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, _ []byte, numConfs,
heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
return nil, nil
}
@ -35,7 +35,7 @@ func (m *mockNotifier) Start() error {
func (m *mockNotifier) Stop() error {
return nil
}
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
return &chainntnfs.SpendEvent{
Spend: m.spendChan,

View File

@ -5,12 +5,12 @@ import (
"sync"
"sync/atomic"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/wire"
)
const (

View File

@ -5,11 +5,11 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)
type mockChainIO struct{}
@ -18,7 +18,7 @@ func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) {
return nil, 0, nil
}
func (*mockChainIO) GetUtxo(op *wire.OutPoint,
func (*mockChainIO) GetUtxo(op *wire.OutPoint, _ []byte,
heightHint uint32) (*wire.TxOut, error) {
return nil, nil
}

View File

@ -172,6 +172,7 @@ func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) {
// has been spent by a confirmed transaction.
spendNtfn, err := h.Notifier.RegisterSpendNtfn(
&h.htlcResolution.ClaimOutpoint,
h.htlcResolution.SweepSignDesc.Output.PkScript,
h.broadcastHeight,
)
if err != nil {
@ -211,8 +212,9 @@ func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) {
// Otherwise, this is our commitment, so we'll watch for the
// second-level transaction to be sufficiently confirmed.
secondLevelTXID := h.htlcResolution.SignedTimeoutTx.TxHash()
sweepScript := h.htlcResolution.SignedTimeoutTx.TxOut[0].PkScript
confNtfn, err := h.Notifier.RegisterConfirmationsNtfn(
&secondLevelTXID, 1, h.broadcastHeight,
&secondLevelTXID, sweepScript, 1, h.broadcastHeight,
)
if err != nil {
return nil, err
@ -521,8 +523,9 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
// With the sweep transaction broadcast, we'll wait for its
// confirmation.
sweepTXID := h.sweepTx.TxHash()
sweepScript := h.sweepTx.TxOut[0].PkScript
confNtfn, err := h.Notifier.RegisterConfirmationsNtfn(
&sweepTXID, 1, h.broadcastHeight,
&sweepTXID, sweepScript, 1, h.broadcastHeight,
)
if err != nil {
return nil, err
@ -580,7 +583,9 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
// To wrap this up, we'll wait until the second-level transaction has
// been spent, then fully resolve the contract.
spendNtfn, err := h.Notifier.RegisterSpendNtfn(
&h.htlcResolution.ClaimOutpoint, h.broadcastHeight,
&h.htlcResolution.ClaimOutpoint,
h.htlcResolution.SweepSignDesc.Output.PkScript,
h.broadcastHeight,
)
if err != nil {
return nil, err
@ -781,17 +786,34 @@ func (h *htlcOutgoingContestResolver) Resolve() (ContractResolver, error) {
// output. If this isn't our commitment transaction, it'll be right on
// the resolution. Otherwise, we fetch this pointer from the input of
// the time out transaction.
var outPointToWatch wire.OutPoint
var (
outPointToWatch wire.OutPoint
scriptToWatch []byte
err error
)
if h.htlcResolution.SignedTimeoutTx == nil {
outPointToWatch = h.htlcResolution.ClaimOutpoint
scriptToWatch = h.htlcResolution.SweepSignDesc.Output.PkScript
} else {
// If this is the remote party's commitment, then we'll need to
// grab watch the output that our timeout transaction points
// to. We can directly grab the outpoint, then also extract the
// witness script (the last element of the witness stack) to
// re-construct the pkScipt we need to watch.
outPointToWatch = h.htlcResolution.SignedTimeoutTx.TxIn[0].PreviousOutPoint
witness := h.htlcResolution.SignedTimeoutTx.TxIn[0].Witness
scriptToWatch, err = lnwallet.WitnessScriptHash(
witness[len(witness)-1],
)
if err != nil {
return nil, err
}
}
// First, we'll register for a spend notification for this output. If
// the remote party sweeps with the pre-image, we'll be notified.
// the remote party sweeps with the pre-image, we'll be notified.
spendNtfn, err := h.Notifier.RegisterSpendNtfn(
&outPointToWatch, h.broadcastHeight,
&outPointToWatch, scriptToWatch, h.broadcastHeight,
)
if err != nil {
return nil, err
@ -800,6 +822,7 @@ func (h *htlcOutgoingContestResolver) Resolve() (ContractResolver, error) {
// We'll quickly check to see if the output has already been spent.
select {
// If the output has already been spent, then we can stop early and
// sweep the pre-image from the output.
case commitSpend, ok := <-spendNtfn.Spend:
if !ok {
return nil, fmt.Errorf("quitting")
@ -1193,8 +1216,9 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
//
// TODO(roasbeef): instead sweep asap if remote commit? yeh
commitTXID := c.commitResolution.SelfOutPoint.Hash
sweepScript := c.commitResolution.SelfOutputSignDesc.Output.PkScript
confNtfn, err := c.Notifier.RegisterConfirmationsNtfn(
&commitTXID, 1, c.broadcastHeight,
&commitTXID, sweepScript, 1, c.broadcastHeight,
)
if err != nil {
return nil, err
@ -1292,6 +1316,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
// until the commitment output has been spent.
spendNtfn, err := c.Notifier.RegisterSpendNtfn(
&c.commitResolution.SelfOutPoint,
c.commitResolution.SelfOutputSignDesc.Output.PkScript,
c.broadcastHeight,
)
if err != nil {
@ -1329,8 +1354,9 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
// Now we'll wait until the sweeping transaction has been fully
// confirmed. Once it's confirmed, we can mark this contract resolved.
sweepTXID := c.sweepTx.TxHash()
sweepingScript := c.sweepTx.TxOut[0].PkScript
confNtfn, err = c.Notifier.RegisterConfirmationsNtfn(
&sweepTXID, 1, c.broadcastHeight,
&sweepTXID, sweepingScript, 1, c.broadcastHeight,
)
if err != nil {
return nil, err

View File

@ -18,6 +18,9 @@ import (
"io/ioutil"
"os"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/chainntnfs"
@ -26,9 +29,6 @@ import (
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)
var (
@ -258,12 +258,12 @@ func newMockNotifier() *mockNotifier {
}
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
numConfs, _ uint32) (*chainntnfs.ConfirmationEvent, error) {
_ []byte, numConfs, _ uint32) (*chainntnfs.ConfirmationEvent, error) {
return nil, nil
}
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
_ uint32) (*chainntnfs.SpendEvent, error) {
return nil, nil
}

View File

@ -1752,6 +1752,20 @@ func (f *fundingManager) waitForFundingWithTimeout(completeChan *channeldb.OpenC
}
}
// makeFundingScript re-creates the funding script for the funding transaction
// of the target channel.
func makeFundingScript(channel *channeldb.OpenChannel) ([]byte, error) {
localKey := channel.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
remoteKey := channel.RemoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
multiSigScript, err := lnwallet.GenMultiSigScript(localKey, remoteKey)
if err != nil {
return nil, err
}
return lnwallet.WitnessScriptHash(multiSigScript)
}
// waitForFundingConfirmation handles the final stages of the channel funding
// process once the funding transaction has been broadcast. The primary
// function of waitForFundingConfirmation is to wait for blockchain
@ -1767,9 +1781,16 @@ func (f *fundingManager) waitForFundingConfirmation(completeChan *channeldb.Open
// Register with the ChainNotifier for a notification once the funding
// transaction reaches `numConfs` confirmations.
txid := completeChan.FundingOutpoint.Hash
fundingScript, err := makeFundingScript(completeChan)
if err != nil {
fndgLog.Errorf("unable to create funding script for "+
"ChannelPoint(%v): %v", completeChan.FundingOutpoint, err)
return
}
numConfs := uint32(completeChan.NumConfsRequired)
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(&txid,
numConfs, completeChan.FundingBroadcastHeight)
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
&txid, fundingScript, numConfs, completeChan.FundingBroadcastHeight,
)
if err != nil {
fndgLog.Errorf("Unable to register for confirmation of "+
"ChannelPoint(%v)", completeChan.FundingOutpoint)
@ -2073,8 +2094,16 @@ func (f *fundingManager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
shortChanID.ToUint64(), completeChan.FundingOutpoint,
numConfs)
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(&txid,
numConfs, completeChan.FundingBroadcastHeight)
fundingScript, err := makeFundingScript(completeChan)
if err != nil {
return fmt.Errorf("unable to create funding script for "+
"ChannelPoint(%v): %v",
completeChan.FundingOutpoint, err)
}
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
&txid, fundingScript, numConfs, completeChan.FundingBroadcastHeight,
)
if err != nil {
return fmt.Errorf("Unable to register for "+
"confirmation of ChannelPoint(%v): %v",

View File

@ -98,8 +98,9 @@ type mockNotifier struct {
epochChan chan *chainntnfs.BlockEpoch
}
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs,
heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
_ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
if numConfs == 6 {
return &chainntnfs.ConfirmationEvent{
Confirmed: m.sixConfChannel,
@ -125,7 +126,7 @@ func (m *mockNotifier) Stop() error {
return nil
}
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
return &chainntnfs.SpendEvent{
Spend: make(chan *chainntnfs.SpendDetail),

View File

@ -13,6 +13,10 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/fastsha256"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lightning-onion"
@ -22,10 +26,6 @@ import (
"github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
)
type mockPreimageCache struct {
@ -781,7 +781,7 @@ type mockNotifier struct {
epochChan chan *chainntnfs.BlockEpoch
}
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, _ []byte,
numConfs uint32, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
return nil, nil
}
@ -800,7 +800,7 @@ func (m *mockNotifier) Stop() error {
return nil
}
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
return &chainntnfs.SpendEvent{

View File

@ -9,10 +9,10 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/lnwallet"
)
var (
@ -33,15 +33,21 @@ func (b *BtcWallet) GetBestBlock() (*chainhash.Hash, int32, error) {
return b.chain.GetBestBlock()
}
// GetUtxo returns the original output referenced by the passed outpoint.
// GetUtxo returns the original output referenced by the passed outpoint that
// creates the target pkScript.
//
// This method is a part of the lnwallet.BlockChainIO interface.
func (b *BtcWallet) GetUtxo(op *wire.OutPoint, heightHint uint32) (*wire.TxOut, error) {
func (b *BtcWallet) GetUtxo(op *wire.OutPoint, pkScript []byte,
heightHint uint32) (*wire.TxOut, error) {
switch backend := b.chain.(type) {
case *chain.NeutrinoClient:
spendReport, err := backend.CS.GetUtxo(
neutrino.WatchOutPoints(*op),
neutrino.WatchInputs(neutrino.InputWithScript{
OutPoint: *op,
PkScript: pkScript,
}),
neutrino.StartBlock(&waddrmgr.BlockStamp{
Height: int32(heightHint),
}),

View File

@ -9,8 +9,6 @@ import (
"sync"
"time"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
@ -21,6 +19,8 @@ import (
"github.com/btcsuite/btcwallet/waddrmgr"
base "github.com/btcsuite/btcwallet/wallet"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
)
const (
@ -745,8 +745,24 @@ func (b *BtcWallet) IsSynced() (bool, int64, error) {
return false, 0, err
}
// If the timestamp no the best header is more than 2 hours in the
// If the timestamp on the best header is more than 2 hours in the
// past, then we're not yet synced.
minus24Hours := time.Now().Add(-2 * time.Hour)
return !blockHeader.Timestamp.Before(minus24Hours), bestTimestamp, nil
if blockHeader.Timestamp.Before(minus24Hours) {
return false, bestTimestamp, nil
}
// If this is neutrino, then we'll also want to wait until the set of
// filter headers also match
if neutrinoNode, ok := b.chain.(*chain.NeutrinoClient); ok {
filterDB := neutrinoNode.CS.RegFilterHeaders
_, filterHeaderTip, err := filterDB.ChainTip()
if err != nil {
return false, 0, err
}
return filterHeaderTip == uint32(bestHeight), bestTimestamp, nil
}
return true, bestTimestamp, nil
}

View File

@ -1427,7 +1427,7 @@ func (lc *LightningChannel) createSignDesc() error {
localKey := lc.localChanCfg.MultiSigKey.PubKey.SerializeCompressed()
remoteKey := lc.remoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
multiSigScript, err := genMultiSigScript(localKey, remoteKey)
multiSigScript, err := GenMultiSigScript(localKey, remoteKey)
if err != nil {
return err
}
@ -2043,8 +2043,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
htlcRetributions := make([]HtlcRetribution, 0, len(revokedSnapshot.Htlcs))
for _, htlc := range revokedSnapshot.Htlcs {
var (
htlcScript []byte
err error
htlcWitnessScript []byte
err error
)
// If the HTLC is dust, then we'll skip it as it doesn't have
@ -2072,7 +2072,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// the sender of the HTLC (relative to us). So we'll
// re-generate the sender HTLC script.
if htlc.Incoming {
htlcScript, err = senderHTLCScript(
htlcWitnessScript, err = senderHTLCScript(
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, htlc.RHash[:],
)
@ -2084,7 +2084,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// Otherwise, is this was an outgoing HTLC that we
// sent, then from the PoV of the remote commitment
// state, they're the receiver of this HTLC.
htlcScript, err = receiverHTLCScript(
htlcWitnessScript, err = receiverHTLCScript(
htlc.RefundTimeout, keyRing.LocalHtlcKey,
keyRing.RemoteHtlcKey, keyRing.RevocationKey,
htlc.RHash[:],
@ -2094,13 +2094,19 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
}
}
htlcPkScript, err := WitnessScriptHash(htlcWitnessScript)
if err != nil {
return nil, err
}
htlcRetributions = append(htlcRetributions, HtlcRetribution{
SignDesc: SignDescriptor{
KeyDesc: chanState.LocalChanCfg.RevocationBasePoint,
DoubleTweak: commitmentSecret,
WitnessScript: htlcScript,
WitnessScript: htlcWitnessScript,
Output: &wire.TxOut{
Value: int64(htlc.Amt.ToSatoshis()),
PkScript: htlcPkScript,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
},
@ -5295,7 +5301,8 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
// With the sign desc created, we can now construct the full witness
// for the timeout transaction, and populate it as well.
timeoutWitness, err := senderHtlcSpendTimeout(
htlc.Signature, signer, &timeoutSignDesc, timeoutTx)
htlc.Signature, signer, &timeoutSignDesc, timeoutTx,
)
if err != nil {
return nil, err
}

View File

@ -237,10 +237,12 @@ type BlockChainIO interface {
// GetUtxo attempts to return the passed outpoint if it's still a
// member of the utxo set. The passed height hint should be the "birth
// height" of the passed outpoint. In the case that the output is in
// height" of the passed outpoint. The script passed should be the
// script that the outpoint creates. In the case that the output is in
// the UTXO set, then the output corresponding to that output is
// returned. Otherwise, a non-nil error will be returned.
GetUtxo(op *wire.OutPoint, heightHint uint32) (*wire.TxOut, error)
GetUtxo(op *wire.OutPoint, pkScript []byte,
heightHint uint32) (*wire.TxOut, error)
// GetBlockHash returns the hash of the block in the best blockchain
// at the given height.

View File

@ -1738,7 +1738,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
t.Fatalf("unable to synchronize mining nodes: %v", err)
}
// Step 3: Do a set of reorgs by disconecting the two miners, mining
// Step 3: Do a set of reorgs by disconnecting the two miners, mining
// one block on the passed miner and two on the created miner,
// connecting them, and waiting for them to sync.
for i := 0; i < 5; i++ {
@ -1918,19 +1918,20 @@ func waitForMempoolTx(r *rpctest.Harness, txid *chainhash.Hash) error {
}
func waitForWalletSync(r *rpctest.Harness, w *lnwallet.LightningWallet) error {
var synced bool
var err error
var bestHash, knownHash *chainhash.Hash
var bestHeight, knownHeight int32
timeout := time.After(10 * time.Second)
var (
synced bool
err error
bestHash, knownHash *chainhash.Hash
bestHeight, knownHeight int32
)
timeout := time.After(30 * time.Second)
for !synced {
// Do a short wait
select {
case <-timeout:
return fmt.Errorf("timeout after 10s")
default:
return fmt.Errorf("timeout after 30s")
case <-time.Tick(50 * time.Millisecond):
}
time.Sleep(100 * time.Millisecond)
// Check whether the chain source of the wallet is caught up to
// the harness it's supposed to be catching up to.

View File

@ -57,9 +57,9 @@ func WitnessScriptHash(witnessScript []byte) ([]byte, error) {
return bldr.Script()
}
// genMultiSigScript generates the non-p2sh'd multisig script for 2 of 2
// GenMultiSigScript generates the non-p2sh'd multisig script for 2 of 2
// pubkeys.
func genMultiSigScript(aPub, bPub []byte) ([]byte, error) {
func GenMultiSigScript(aPub, bPub []byte) ([]byte, error) {
if len(aPub) != 33 || len(bPub) != 33 {
return nil, fmt.Errorf("Pubkey size error. Compressed pubkeys only")
}
@ -91,7 +91,7 @@ func GenFundingPkScript(aPub, bPub []byte, amt int64) ([]byte, *wire.TxOut, erro
}
// First, create the 2-of-2 multi-sig script itself.
witnessScript, err := genMultiSigScript(aPub, bPub)
witnessScript, err := GenMultiSigScript(aPub, bPub)
if err != nil {
return nil, nil, err
}

View File

@ -8,12 +8,12 @@ import (
"testing"
"time"
"github.com/lightningnetwork/lnd/keychain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/keychain"
)
// TestCommitmentSpendValidation test the spendability of both outputs within

View File

@ -8,20 +8,20 @@ import (
"sync"
"sync/atomic"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/lightningnetwork/lnd/shachain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/txsort"
"github.com/lightningnetwork/lnd/shachain"
)
const (
@ -262,15 +262,15 @@ type LightningWallet struct {
// is removed from limbo. Each reservation is tracked by a unique
// monotonically integer. All requests concerning the channel MUST
// carry a valid, active funding ID.
fundingLimbo map[uint64]*ChannelReservation
limboMtx sync.RWMutex
fundingLimbo map[uint64]*ChannelReservation
limboMtx sync.RWMutex
// lockedOutPoints is a set of the currently locked outpoint. This
// information is kept in order to provide an easy way to unlock all
// the currently locked outpoints.
lockedOutPoints map[wire.OutPoint]struct{}
quit chan struct{}
quit chan struct{}
wg sync.WaitGroup
@ -971,8 +971,18 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
// Fetch the alleged previous output along with the
// pkscript referenced by this input.
// TODO(roasbeef): when dual funder pass actual height-hint
output, err := l.Cfg.ChainIO.GetUtxo(&txin.PreviousOutPoint, 0)
//
// TODO(roasbeef): when dual funder pass actual
// height-hint
pkScript, err := WitnessScriptHash(
txin.Witness[len(txin.Witness)-1],
)
if err != nil {
}
output, err := l.Cfg.ChainIO.GetUtxo(
&txin.PreviousOutPoint,
pkScript, 0,
)
if output == nil {
msg.err <- fmt.Errorf("input to funding tx "+
"does not exist: %v", err)

16
mock.go
View File

@ -5,15 +5,15 @@ import (
"fmt"
"sync"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"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/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
)
// The block height returned by the mock BlockChainIO's GetBestBlock.
@ -85,8 +85,8 @@ type mockNotfier struct {
confChannel chan *chainntnfs.TxConfirmation
}
func (m *mockNotfier) RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs,
heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
func (m *mockNotfier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
_ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
return &chainntnfs.ConfirmationEvent{
Confirmed: m.confChannel,
}, nil
@ -105,7 +105,7 @@ func (m *mockNotfier) Start() error {
func (m *mockNotfier) Stop() error {
return nil
}
func (m *mockNotfier) RegisterSpendNtfn(outpoint *wire.OutPoint,
func (m *mockNotfier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
return &chainntnfs.SpendEvent{
Spend: make(chan *chainntnfs.SpendDetail),
@ -131,7 +131,7 @@ func makeMockSpendNotifier() *mockSpendNotifier {
}
func (m *mockSpendNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
heightHint uint32) (*chainntnfs.SpendEvent, error) {
_ []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
m.mtx.Lock()
defer m.mtx.Unlock()
@ -172,7 +172,7 @@ func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) {
return activeNetParams.GenesisHash, fundingBroadcastHeight, nil
}
func (*mockChainIO) GetUtxo(op *wire.OutPoint,
func (*mockChainIO) GetUtxo(op *wire.OutPoint, _ []byte,
heightHint uint32) (*wire.TxOut, error) {
return nil, nil
}

View File

@ -1837,7 +1837,7 @@ func (p *peer) finalizeChanClosure(chanCloser *channelCloser) {
}
go waitForChanToClose(chanCloser.negotiationHeight, notifier, errChan,
chanPoint, &closingTxid, func() {
chanPoint, &closingTxid, closingTx.TxOut[0].PkScript, func() {
// Respond to the local subsystem which requested the
// channel closure.
if closeReq != nil {
@ -1872,15 +1872,16 @@ func (p *peer) finalizeChanClosure(chanCloser *channelCloser) {
// the function, then it will be sent over the errChan.
func waitForChanToClose(bestHeight uint32, notifier chainntnfs.ChainNotifier,
errChan chan error, chanPoint *wire.OutPoint,
closingTxID *chainhash.Hash, cb func()) {
closingTxID *chainhash.Hash, closeScript []byte, cb func()) {
peerLog.Infof("Waiting for confirmation of cooperative close of "+
"ChannelPoint(%v) with txid: %v", chanPoint,
closingTxID)
// TODO(roasbeef): add param for num needed confs
confNtfn, err := notifier.RegisterConfirmationsNtfn(closingTxID, 1,
bestHeight)
confNtfn, err := notifier.RegisterConfirmationsNtfn(
closingTxID, closeScript, 1, bestHeight,
)
if err != nil {
if errChan != nil {
errChan <- err

View File

@ -13,9 +13,9 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightningnetwork/lnd/channeldb"
)
// BitcoindFilteredChainView is an implementation of the FilteredChainView
@ -66,6 +66,7 @@ var _ FilteredChainView = (*BitcoindFilteredChainView)(nil)
func NewBitcoindFilteredChainView(config rpcclient.ConnConfig,
zmqConnect string, params chaincfg.Params) (*BitcoindFilteredChainView,
error) {
chainView := &BitcoindFilteredChainView{
chainFilter: make(map[wire.OutPoint]struct{}),
filterUpdates: make(chan filterUpdate),
@ -308,7 +309,6 @@ func (b *BitcoindFilteredChainView) chainFilterer() {
// filter, so we'll apply the update, possibly rewinding our
// state partially.
case update := <-b.filterUpdates:
// First, we'll add all the new UTXO's to the set of
// watched UTXO's, eliminating any duplicates in the
// process.
@ -325,8 +325,9 @@ func (b *BitcoindFilteredChainView) chainFilterer() {
// will cause all following notifications from and
// calls to it return blocks filtered with the new
// filter.
b.chainClient.LoadTxFilter(false, []btcutil.Address{},
update.newUtxos)
b.chainClient.LoadTxFilter(
false, update.newUtxos,
)
// All blocks gotten after we loaded the filter will
// have the filter applied, but we will need to rescan
@ -362,7 +363,8 @@ func (b *BitcoindFilteredChainView) chainFilterer() {
// block at a time, skipping blocks that might
// have gone missing.
rescanned, err := b.chainClient.RescanBlocks(
[]chainhash.Hash{*blockHash})
[]chainhash.Hash{*blockHash},
)
if err != nil {
log.Warnf("Unable to rescan block "+
"with hash %v at height %d: %v",
@ -379,7 +381,8 @@ func (b *BitcoindFilteredChainView) chainFilterer() {
continue
}
decoded, err := decodeJSONBlock(
&rescanned[0], i)
&rescanned[0], i,
)
if err != nil {
log.Errorf("Unable to decode block: %v",
err)
@ -421,9 +424,12 @@ func (b *BitcoindFilteredChainView) chainFilterer() {
// We've received a new event from the chain client.
case event := <-b.chainClient.Notifications():
switch e := event.(type) {
case chain.FilteredBlockConnected:
b.onFilteredBlockConnected(e.Block.Height,
e.Block.Hash, e.RelevantTxs)
b.onFilteredBlockConnected(
e.Block.Height, e.Block.Hash, e.RelevantTxs,
)
case chain.BlockDisconnected:
b.onFilteredBlockDisconnected(e.Height, e.Hash)
}
@ -442,11 +448,18 @@ func (b *BitcoindFilteredChainView) chainFilterer() {
// rewound to ensure all relevant notifications are dispatched.
//
// NOTE: This is part of the FilteredChainView interface.
func (b *BitcoindFilteredChainView) UpdateFilter(ops []wire.OutPoint, updateHeight uint32) error {
func (b *BitcoindFilteredChainView) UpdateFilter(ops []channeldb.EdgePoint,
updateHeight uint32) error {
newUtxos := make([]wire.OutPoint, len(ops))
for i, op := range ops {
newUtxos[i] = op.OutPoint
}
select {
case b.filterUpdates <- filterUpdate{
newUtxos: ops,
newUtxos: newUtxos,
updateHeight: updateHeight,
}:
return nil

View File

@ -12,6 +12,7 @@ import (
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
)
// BtcdFilteredChainView is an implementation of the FilteredChainView
@ -447,11 +448,18 @@ type filterUpdate struct {
// rewound to ensure all relevant notifications are dispatched.
//
// NOTE: This is part of the FilteredChainView interface.
func (b *BtcdFilteredChainView) UpdateFilter(ops []wire.OutPoint, updateHeight uint32) error {
func (b *BtcdFilteredChainView) UpdateFilter(ops []channeldb.EdgePoint,
updateHeight uint32) error {
newUtxos := make([]wire.OutPoint, len(ops))
for i, op := range ops {
newUtxos[i] = op.OutPoint
}
select {
case b.filterUpdates <- filterUpdate{
newUtxos: ops,
newUtxos: newUtxos,
updateHeight: updateHeight,
}:
return nil

View File

@ -3,6 +3,7 @@ package chainview
import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb"
)
// FilteredChainView represents a subscription to a certain subset of the
@ -42,7 +43,7 @@ type FilteredChainView interface {
// relevant notifications are dispatched, meaning blocks with a height
// lower than the best known height might be sent over the
// FilteredBlocks() channel.
UpdateFilter(ops []wire.OutPoint, updateHeight uint32) error
UpdateFilter(ops []channeldb.EdgePoint, updateHeight uint32) error
// FilterBlock takes a block hash, and returns a FilteredBlocks which
// is the result of applying the current registered UTXO sub-set on the

View File

@ -21,6 +21,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/ltcsuite/ltcd/btcjson"
"github.com/btcsuite/btcwallet/walletdb"
@ -238,8 +239,11 @@ func testFilterBlockNotifications(node *rpctest.Harness,
t.Fatalf("unable to get current height: %v", err)
}
// Now we'll add both output to the current filter.
filter := []wire.OutPoint{*outPoint1, *outPoint2}
// Now we'll add both outpoints to the current filter.
filter := []channeldb.EdgePoint{
{targetScript, *outPoint1},
{targetScript, *outPoint2},
}
err = chainView.UpdateFilter(filter, uint32(currentHeight))
if err != nil {
t.Fatalf("unable to update filter: %v", err)
@ -382,8 +386,9 @@ func testUpdateFilterBackTrack(node *rpctest.Harness,
// After the block has been mined+notified we'll update the filter with
// a _prior_ height so a "rewind" occurs.
filter := []wire.OutPoint{*outPoint}
filter := []channeldb.EdgePoint{
{testScript, *outPoint},
}
err = chainView.UpdateFilter(filter, uint32(currentHeight))
if err != nil {
t.Fatalf("unable to update filter: %v", err)
@ -496,7 +501,10 @@ func testFilterSingleBlock(node *rpctest.Harness, chainView FilteredChainView,
// Now we'll manually trigger filtering the block generated above.
// First, we'll add the two outpoints to our filter.
filter := []wire.OutPoint{*outPoint1, *outPoint2}
filter := []channeldb.EdgePoint{
{testScript, *outPoint1},
{testScript, *outPoint2},
}
err = chainView.UpdateFilter(filter, uint32(currentHeight))
if err != nil {
t.Fatalf("unable to update filter: %v", err)
@ -562,6 +570,13 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
newBlocks := reorgView.FilteredBlocks()
disconnectedBlocks := reorgView.DisconnectedBlocks()
// If this the neutrino backend, then we'll give it some time to catch
// up, as it's a bit slower to consume new blocks compared to the RPC
// backends.
if _, ok := reorgView.(*CfFilteredChainView); ok {
time.Sleep(time.Second * 3)
}
_, oldHeight, err := reorgNode.Node.GetBestBlock()
if err != nil {
t.Fatalf("unable to get current height: %v", err)
@ -591,7 +606,8 @@ func testFilterBlockDisconnected(node *rpctest.Harness,
case block := <-newBlocks:
if i < oldHeight {
t.Fatalf("did not expect to get new block "+
"in iteration %d", i)
"in iteration %d, old height: %v", i,
oldHeight)
}
expectedHeight := uint32(i - oldHeight + 1)
if block.Height != expectedHeight {

View File

@ -12,6 +12,7 @@ import (
"github.com/btcsuite/btcutil/gcs/builder"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/channeldb"
)
// CfFilteredChainView is an implementation of the FilteredChainView interface
@ -96,7 +97,7 @@ func (c *CfFilteredChainView) Start() error {
// required that an user MUST set a addr/outpoint/txid when creating a
// rescan. To get around this, we'll add a "zero" outpoint, that won't
// actually be matched.
var zeroPoint wire.OutPoint
var zeroPoint neutrino.InputWithScript
rescanOptions := []neutrino.RescanOption{
neutrino.StartBlock(startingPoint),
neutrino.QuitChan(c.quit),
@ -106,7 +107,7 @@ func (c *CfFilteredChainView) Start() error {
OnFilteredBlockDisconnected: c.onFilteredBlockDisconnected,
},
),
neutrino.WatchOutPoints(zeroPoint),
neutrino.WatchInputs(zeroPoint),
}
// Finally, we'll create our rescan struct, start it, and launch all
@ -314,7 +315,7 @@ func (c *CfFilteredChainView) FilterBlock(blockHash *chainhash.Hash) (*FilteredB
// rewound to ensure all relevant notifications are dispatched.
//
// NOTE: This is part of the FilteredChainView interface.
func (c *CfFilteredChainView) UpdateFilter(ops []wire.OutPoint,
func (c *CfFilteredChainView) UpdateFilter(ops []channeldb.EdgePoint,
updateHeight uint32) error {
log.Debugf("Updating chain filter with new UTXO's: %v", ops)
@ -323,14 +324,22 @@ func (c *CfFilteredChainView) UpdateFilter(ops []wire.OutPoint,
// UTXO's, ignoring duplicates in the process.
c.filterMtx.Lock()
for _, op := range ops {
c.chainFilter[op] = builder.OutPointToFilterEntry(op)
c.chainFilter[op.OutPoint] = op.FundingPkScript
}
c.filterMtx.Unlock()
inputs := make([]neutrino.InputWithScript, len(ops))
for i, op := range ops {
inputs[i] = neutrino.InputWithScript{
PkScript: op.FundingPkScript,
OutPoint: op.OutPoint,
}
}
// With our internal chain view update, we'll craft a new update to the
// chainView which includes our new UTXO's, and current update height.
rescanUpdate := []neutrino.UpdateOption{
neutrino.AddOutPoints(ops...),
neutrino.AddInputs(inputs...),
neutrino.Rewind(updateHeight),
neutrino.DisableDisconnectedNtfns(true),
}

View File

@ -10,15 +10,15 @@ import (
prand "math/rand"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/chainview"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
var (
@ -176,7 +176,7 @@ func (m *mockChain) addUtxo(op wire.OutPoint, out *wire.TxOut) {
m.utxos[op] = *out
m.Unlock()
}
func (m *mockChain) GetUtxo(op *wire.OutPoint, _ uint32) (*wire.TxOut, error) {
func (m *mockChain) GetUtxo(op *wire.OutPoint, _ []byte, _ uint32) (*wire.TxOut, error) {
m.RLock()
defer m.RUnlock()
@ -242,12 +242,12 @@ func (m *mockChainView) Reset() {
m.staleBlocks = make(chan *chainview.FilteredBlock, 10)
}
func (m *mockChainView) UpdateFilter(ops []wire.OutPoint, updateHeight uint32) error {
func (m *mockChainView) UpdateFilter(ops []channeldb.EdgePoint, updateHeight uint32) error {
m.Lock()
defer m.Unlock()
for _, op := range ops {
m.filter[op] = struct{}{}
m.filter[op.OutPoint] = struct{}{}
}
return nil

View File

@ -967,7 +967,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// to obtain the full funding outpoint that's encoded within
// the channel ID.
channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
fundingPoint, err := r.fetchChanPoint(&channelID)
fundingPoint, _, err := r.fetchChanPoint(&channelID)
if err != nil {
r.rejectMtx.Lock()
r.rejectCache[msg.ChannelID] = struct{}{}
@ -977,11 +977,25 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
"chan_id=%v: %v", msg.ChannelID, err)
}
// Recreate witness output to be sure that declared in channel
// edge bitcoin keys and channel value corresponds to the
// reality.
witnessScript, err := lnwallet.GenMultiSigScript(
msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
)
if err != nil {
return err
}
fundingPkScript, err := lnwallet.WitnessScriptHash(witnessScript)
if err != nil {
return err
}
// Now that we have the funding outpoint of the channel, ensure
// that it hasn't yet been spent. If so, then this channel has
// been closed so we'll ignore it.
chanUtxo, err := r.cfg.Chain.GetUtxo(
fundingPoint, channelID.BlockHeight,
fundingPoint, fundingPkScript, channelID.BlockHeight,
)
if err != nil {
r.rejectMtx.Lock()
@ -993,26 +1007,14 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
fundingPoint, err)
}
// Recreate witness output to be sure that declared in channel
// edge bitcoin keys and channel value corresponds to the
// reality.
_, witnessOutput, err := lnwallet.GenFundingPkScript(
msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
chanUtxo.Value,
)
if err != nil {
return errors.Errorf("unable to create funding pk "+
"script: %v", err)
}
// By checking the equality of witness pkscripts we checks that
// funding witness script is multisignature lock which contains
// both local and remote public keys which was declared in
// channel edge and also that the announced channel value is
// right.
if !bytes.Equal(witnessOutput.PkScript, chanUtxo.PkScript) {
if !bytes.Equal(fundingPkScript, chanUtxo.PkScript) {
return errors.Errorf("pkScript mismatch: expected %x, "+
"got %x", witnessOutput.PkScript, chanUtxo.PkScript)
"got %x", fundingPkScript, chanUtxo.PkScript)
}
// TODO(roasbeef): this is a hack, needs to be removed
@ -1034,7 +1036,12 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// update the current UTXO filter within our active
// FilteredChainView so we are notified if/when this channel is
// closed.
filterUpdate := []wire.OutPoint{*fundingPoint}
filterUpdate := []channeldb.EdgePoint{
{
FundingPkScript: fundingPkScript,
OutPoint: *fundingPoint,
},
}
err = r.cfg.ChainView.UpdateFilter(
filterUpdate, atomic.LoadUint32(&r.bestHeight),
)
@ -1105,7 +1112,9 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// Before we can update the channel information, we'll
// ensure that the target channel is still open by
// querying the utxo-set for its existence.
chanPoint, err := r.fetchChanPoint(&channelID)
chanPoint, fundingPkScript, err := r.fetchChanPoint(
&channelID,
)
if err != nil {
r.rejectMtx.Lock()
r.rejectCache[msg.ChannelID] = struct{}{}
@ -1116,7 +1125,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
msg.ChannelID, err)
}
_, err = r.cfg.Chain.GetUtxo(
chanPoint, channelID.BlockHeight,
chanPoint, fundingPkScript, channelID.BlockHeight,
)
if err != nil {
r.rejectMtx.Lock()
@ -1157,21 +1166,22 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
}
// fetchChanPoint retrieves the original outpoint which is encoded within the
// channelID.
// channelID. This method also return the public key script for the target
// transaction.
//
// TODO(roasbeef): replace with call to GetBlockTransaction? (would allow to
// later use getblocktxn)
func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.OutPoint, error) {
func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.OutPoint, []byte, error) {
// First fetch the block hash by the block number encoded, then use
// that hash to fetch the block itself.
blockNum := int64(chanID.BlockHeight)
blockHash, err := r.cfg.Chain.GetBlockHash(blockNum)
if err != nil {
return nil, err
return nil, nil, err
}
fundingBlock, err := r.cfg.Chain.GetBlock(blockHash)
if err != nil {
return nil, err
return nil, nil, err
}
// As a sanity check, ensure that the advertised transaction index is
@ -1179,7 +1189,7 @@ func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.Out
// block.
numTxns := uint32(len(fundingBlock.Transactions))
if chanID.TxIndex > numTxns-1 {
return nil, fmt.Errorf("tx_index=#%v is out of range "+
return nil, nil, fmt.Errorf("tx_index=#%v is out of range "+
"(max_index=%v), network_chan_id=%v\n", chanID.TxIndex,
numTxns-1, spew.Sdump(chanID))
}
@ -1190,7 +1200,7 @@ func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.Out
return &wire.OutPoint{
Hash: fundingTx.TxHash(),
Index: uint32(chanID.TxPosition),
}, nil
}, fundingTx.TxOut[chanID.TxPosition].PkScript, nil
}
// routingMsg couples a routing related routing topology update to the

View File

@ -1083,7 +1083,7 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
errChan = make(chan error, 1)
notifier := r.server.cc.chainNotifier
go waitForChanToClose(uint32(bestHeight), notifier, errChan, chanPoint,
&closingTxid, func() {
&closingTxid, closingTx.TxOut[0].PkScript, func() {
// Respond to the local subsystem which
// requested the channel closure.
updateChan <- &lnrpc.CloseStatusUpdate{

View File

@ -10,6 +10,10 @@ import (
"net"
"os"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
@ -18,10 +22,6 @@ import (
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
var (

View File

@ -1145,7 +1145,9 @@ func (u *utxoNursery) registerSweepConf(finalTx *wire.MsgTx,
finalTxID := finalTx.TxHash()
confChan, err := u.cfg.Notifier.RegisterConfirmationsNtfn(
&finalTxID, u.cfg.ConfDepth, heightHint)
&finalTxID, finalTx.TxOut[0].PkScript, u.cfg.ConfDepth,
heightHint,
)
if err != nil {
utxnLog.Errorf("unable to register notification for "+
"sweep confirmation: %v", finalTxID)
@ -1251,7 +1253,9 @@ func (u *utxoNursery) registerTimeoutConf(baby *babyOutput, heightHint uint32) e
// Register for the confirmation of presigned htlc txn.
confChan, err := u.cfg.Notifier.RegisterConfirmationsNtfn(
&birthTxID, u.cfg.ConfDepth, heightHint)
&birthTxID, baby.timeoutTx.TxOut[0].PkScript, u.cfg.ConfDepth,
heightHint,
)
if err != nil {
return err
}
@ -1316,8 +1320,10 @@ func (u *utxoNursery) registerPreschoolConf(kid *kidOutput, heightHint uint32) e
// de-duplicate
// * need to do above?
confChan, err := u.cfg.Notifier.RegisterConfirmationsNtfn(&txID,
u.cfg.ConfDepth, heightHint)
pkScript := kid.signDesc.Output.PkScript
confChan, err := u.cfg.Notifier.RegisterConfirmationsNtfn(
&txID, pkScript, u.cfg.ConfDepth, heightHint,
)
if err != nil {
return err
}