chainntnfs/bitcoindnotify: support registration for script confirmations
In this commit, we extend the BitcoindNotifier to support registering scripts for confirmation notifications. Once the script has been detected as confirmed within the chain, a confirmation notification will be dispatched to through the Confirmed channel of the ConfirmationEvent returned upon registration. For scripts that have confirmed in the past, the `historicalConfDetails` method has been modified to skip the txindex and go straight to scanning the chain manually if confirmation request is for a script. When scanning the chain, we'll determine whether the script has been confirmed by locating the script in an output of a confirmed transaction. For scripts that have yet to confirm, they will be properly tracked within the TxNotifier.
This commit is contained in:
2 files changed
+103
-45
No files matched your search
@@ -3,6 +3,7 @@
|
||||
package bitcoindnotify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -14,6 +15,20 @@ import (
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
)
|
||||
|
||||
var (
|
||||
testScript = []byte{
|
||||
// OP_HASH160
|
||||
0xA9,
|
||||
// OP_DATA_20
|
||||
0x14,
|
||||
// <20-byte hash>
|
||||
0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c, 0xa5, 0x15,
|
||||
0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03, 0x06, 0xf6, 0x96, 0xcd,
|
||||
// OP_EQUAL
|
||||
0x87,
|
||||
}
|
||||
)
|
||||
|
||||
func initHintCache(t *testing.T) *chainntnfs.HeightHintCache {
|
||||
t.Helper()
|
||||
|
||||
@@ -107,8 +122,13 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
|
||||
// A transaction unknown to the node should not be found within the
|
||||
// txindex even if it is enabled, so we should not proceed with any
|
||||
// fallback methods.
|
||||
var zeroHash chainhash.Hash
|
||||
_, txStatus, err := notifier.historicalConfDetails(&zeroHash, 0, 0)
|
||||
var unknownHash chainhash.Hash
|
||||
copy(unknownHash[:], bytes.Repeat([]byte{0x10}, 32))
|
||||
unknownConfReq, err := chainntnfs.NewConfRequest(&unknownHash, testScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create conf request: %v", err)
|
||||
}
|
||||
_, txStatus, err := notifier.historicalConfDetails(unknownConfReq, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to retrieve historical conf details: %v", err)
|
||||
}
|
||||
@@ -123,16 +143,20 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
|
||||
|
||||
// Now, we'll create a test transaction, confirm it, and attempt to
|
||||
// retrieve its confirmation details.
|
||||
txid, _, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create tx: %v", err)
|
||||
}
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
confReq, err := chainntnfs.NewConfRequest(txid, pkScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create conf request: %v", err)
|
||||
}
|
||||
|
||||
// The transaction should be found in the mempool at this point.
|
||||
_, txStatus, err = notifier.historicalConfDetails(txid, 0, 0)
|
||||
_, txStatus, err = notifier.historicalConfDetails(confReq, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to retrieve historical conf details: %v", err)
|
||||
}
|
||||
@@ -154,7 +178,7 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
|
||||
// the txindex includes the transaction just mined.
|
||||
syncNotifierWithMiner(t, notifier, miner)
|
||||
|
||||
_, txStatus, err = notifier.historicalConfDetails(txid, 0, 0)
|
||||
_, txStatus, err = notifier.historicalConfDetails(confReq, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to retrieve historical conf details: %v", err)
|
||||
}
|
||||
@@ -173,7 +197,7 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
|
||||
// historical confirmation details using the set of fallback methods when the
|
||||
// backend node's txindex is disabled.
|
||||
func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
|
||||
miner, tearDown := chainntnfs.NewMiner(t, nil, true, 25)
|
||||
miner, tearDown := chainntnfs.NewMiner(t, nil, true, 400)
|
||||
defer tearDown()
|
||||
|
||||
bitcoindConn, cleanUp := chainntnfs.NewBitcoindBackend(
|
||||
@@ -189,10 +213,15 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
|
||||
// Since the node has its txindex disabled, we fall back to scanning the
|
||||
// chain manually. A transaction unknown to the network should not be
|
||||
// found.
|
||||
var zeroHash chainhash.Hash
|
||||
var unknownHash chainhash.Hash
|
||||
copy(unknownHash[:], bytes.Repeat([]byte{0x10}, 32))
|
||||
unknownConfReq, err := chainntnfs.NewConfRequest(&unknownHash, testScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create conf request: %v", err)
|
||||
}
|
||||
broadcastHeight := syncNotifierWithMiner(t, notifier, miner)
|
||||
_, txStatus, err := notifier.historicalConfDetails(
|
||||
&zeroHash, uint32(broadcastHeight), uint32(broadcastHeight),
|
||||
unknownConfReq, uint32(broadcastHeight), uint32(broadcastHeight),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to retrieve historical conf details: %v", err)
|
||||
@@ -213,8 +242,8 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
|
||||
// one output, which we will manually spend. The backend node's
|
||||
// transaction index should also be disabled, which we've already
|
||||
// ensured above.
|
||||
output, pkScript := chainntnfs.CreateSpendableOutput(t, miner)
|
||||
spendTx := chainntnfs.CreateSpendTx(t, output, pkScript)
|
||||
outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
|
||||
spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
|
||||
spendTxHash, err := miner.Node.SendRawTransaction(spendTx, true)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to broadcast tx: %v", err)
|
||||
@@ -228,9 +257,13 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
|
||||
|
||||
// Ensure the notifier and miner are synced to the same height to ensure
|
||||
// we can find the transaction when manually scanning the chain.
|
||||
confReq, err := chainntnfs.NewConfRequest(&outpoint.Hash, output.PkScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create conf request: %v", err)
|
||||
}
|
||||
currentHeight := syncNotifierWithMiner(t, notifier, miner)
|
||||
_, txStatus, err = notifier.historicalConfDetails(
|
||||
&output.Hash, uint32(broadcastHeight), uint32(currentHeight),
|
||||
confReq, uint32(broadcastHeight), uint32(currentHeight),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to retrieve historical conf details: %v", err)
|
||||
|
||||
Reference in new issue
Block a user