chainntnfs: extract helper test vars and functions
In this commit, we extract some of the helper test variables and functions into their own file and guard them under a build flag. This is needed as some unit tests will be introduced in a future commit where most of the same functions within the interface tests are reused. In order to prevent these variables and functions from being exportable, we guard them by the "debug" build tag.
This commit is contained in:
parent
625b210f44
commit
f88f6f68d4
@ -1,3 +1,5 @@
|
||||
// +build debug
|
||||
|
||||
package chainntnfs_test
|
||||
|
||||
import (
|
||||
@ -5,25 +7,15 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/integration/rpctest"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcwallet/chain"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/lightninglabs/neutrino"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
@ -41,78 +33,10 @@ import (
|
||||
"github.com/lightningnetwork/lnd/chainntnfs/neutrinonotify"
|
||||
|
||||
// Required to register the boltdb walletdb implementation.
|
||||
"github.com/btcsuite/btcwallet/chain"
|
||||
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
|
||||
)
|
||||
|
||||
var (
|
||||
testPrivKey = []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,
|
||||
}
|
||||
|
||||
netParams = &chaincfg.RegressionNetParams
|
||||
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), testPrivKey)
|
||||
addrPk, _ = btcutil.NewAddressPubKey(pubKey.SerializeCompressed(),
|
||||
netParams)
|
||||
testAddr = addrPk.AddressPubKeyHash()
|
||||
)
|
||||
|
||||
func getTestTxIdAndScript(miner *rpctest.Harness) (*chainhash.Hash, []byte, error) {
|
||||
script, err := txscript.PayToAddrScript(testAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
outputs := []*wire.TxOut{
|
||||
{
|
||||
Value: 2e8,
|
||||
PkScript: script,
|
||||
},
|
||||
}
|
||||
|
||||
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 {
|
||||
var found bool
|
||||
var tx *btcutil.Tx
|
||||
var err error
|
||||
timeout := time.After(10 * time.Second)
|
||||
for !found {
|
||||
// Do a short wait
|
||||
select {
|
||||
case <-timeout:
|
||||
return fmt.Errorf("timeout after 10s")
|
||||
default:
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Check for the harness' knowledge of the txid
|
||||
tx, err = r.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
case *btcjson.RPCError:
|
||||
if e.Code == btcjson.ErrRPCNoTxInfo {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
}
|
||||
return err
|
||||
}
|
||||
if tx != nil && tx.MsgTx().TxHash() == *txid {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testSingleConfirmationNotification(miner *rpctest.Harness,
|
||||
notifier chainntnfs.TestChainNotifier, t *testing.T) {
|
||||
|
||||
@ -122,14 +46,11 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
|
||||
// So first, let's send some coins to "ourself", obtaining a txid.
|
||||
// We're spending from a coinbase output here, so we use the dedicated
|
||||
// function.
|
||||
|
||||
txid, pkScript, err := getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -192,13 +113,11 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
|
||||
//
|
||||
// Again, we'll begin by creating a fresh transaction, so we can obtain
|
||||
// a fresh txid.
|
||||
txid, pkScript, err := getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test addr: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -251,7 +170,7 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
|
||||
// verify they're each notified at the proper number of confirmations
|
||||
// below.
|
||||
for i, numConfs := range confSpread {
|
||||
txid, pkScript, err := getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test addr: %v", err)
|
||||
}
|
||||
@ -262,8 +181,7 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to register ntfn: %v", err)
|
||||
}
|
||||
confIntents[i] = confIntent
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -310,70 +228,6 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
|
||||
}
|
||||
}
|
||||
|
||||
func createSpendableOutput(miner *rpctest.Harness,
|
||||
t *testing.T) (*wire.OutPoint, []byte) {
|
||||
|
||||
txid, _, err := getTestTxIdAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test addr: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
// Mine a single block which should include that txid above.
|
||||
if _, err := miner.Node.Generate(1); err != nil {
|
||||
t.Fatalf("unable to generate single block: %v", err)
|
||||
}
|
||||
|
||||
// Now that we have the txid, fetch the transaction itself.
|
||||
wrappedTx, err := miner.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get new tx: %v", err)
|
||||
}
|
||||
tx := wrappedTx.MsgTx()
|
||||
|
||||
// Locate the output index sent to us. We need this so we can construct
|
||||
// a spending txn below.
|
||||
outIndex := -1
|
||||
var pkScript []byte
|
||||
for i, txOut := range tx.TxOut {
|
||||
if bytes.Contains(txOut.PkScript, testAddr.ScriptAddress()) {
|
||||
pkScript = txOut.PkScript
|
||||
outIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if outIndex == -1 {
|
||||
t.Fatalf("unable to locate new output")
|
||||
}
|
||||
|
||||
return wire.NewOutPoint(txid, uint32(outIndex)), pkScript
|
||||
}
|
||||
|
||||
func createSpendTx(outpoint *wire.OutPoint, pkScript []byte,
|
||||
t *testing.T) *wire.MsgTx {
|
||||
|
||||
spendingTx := wire.NewMsgTx(1)
|
||||
spendingTx.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: *outpoint,
|
||||
})
|
||||
spendingTx.AddTxOut(&wire.TxOut{
|
||||
Value: 1e8,
|
||||
PkScript: pkScript,
|
||||
})
|
||||
sigScript, err := txscript.SignatureScript(spendingTx, 0, pkScript,
|
||||
txscript.SigHashAll, privKey, true)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to sign tx: %v", err)
|
||||
}
|
||||
spendingTx.TxIn[0].SignatureScript = sigScript
|
||||
|
||||
return spendingTx
|
||||
}
|
||||
|
||||
func checkNotificationFields(ntfn *chainntnfs.SpendDetail,
|
||||
outpoint *wire.OutPoint, spenderSha *chainhash.Hash,
|
||||
height int32, t *testing.T) {
|
||||
@ -407,7 +261,7 @@ func testSpendNotification(miner *rpctest.Harness,
|
||||
// concrete implementations.
|
||||
//
|
||||
// To do so, we first create a new output to our test target address.
|
||||
outpoint, pkScript := createSpendableOutput(miner, t)
|
||||
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, miner)
|
||||
|
||||
_, currentHeight, err := miner.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
@ -432,7 +286,7 @@ func testSpendNotification(miner *rpctest.Harness,
|
||||
}
|
||||
|
||||
// Next, create a new transaction spending that output.
|
||||
spendingTx := createSpendTx(outpoint, pkScript, t)
|
||||
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript)
|
||||
|
||||
// Broadcast our spending transaction.
|
||||
spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true)
|
||||
@ -440,8 +294,7 @@ func testSpendNotification(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to broadcast tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, spenderSha)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, spenderSha); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -565,14 +418,11 @@ 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, pkScript, err := getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -632,14 +482,11 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
// First, let's send some coins to "ourself", obtaining a txid. We're
|
||||
// spending from a coinbase output here, so we use the dedicated
|
||||
// function.
|
||||
|
||||
txid3, pkScript3, err := getTestTxIdAndScript(miner)
|
||||
txid3, pkScript3, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid3)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid3); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -653,23 +500,19 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to generate block: %v", err)
|
||||
}
|
||||
|
||||
txid1, pkScript1, err := getTestTxIdAndScript(miner)
|
||||
txid1, pkScript1, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid1)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid1); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
txid2, pkScript2, err := getTestTxIdAndScript(miner)
|
||||
txid2, pkScript2, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid2)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid2); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -791,13 +634,11 @@ 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, pkScript, err := getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -829,13 +670,11 @@ 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, pkScript, err = getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err = chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -884,16 +723,15 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
// concrete implementations.
|
||||
//
|
||||
// To do so, we first create a new output to our test target address.
|
||||
outpoint, pkScript := createSpendableOutput(miner, t)
|
||||
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, miner)
|
||||
|
||||
// We'll then spend this output and broadcast the spend transaction.
|
||||
spendingTx := createSpendTx(outpoint, pkScript, t)
|
||||
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript)
|
||||
spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to broadcast tx: %v", err)
|
||||
}
|
||||
err = waitForMempoolTx(miner, spenderSha)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, spenderSha); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -989,7 +827,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
|
||||
|
||||
// First, we'll start by creating a new output that we can spend
|
||||
// ourselves.
|
||||
outpoint, pkScript := createSpendableOutput(node, t)
|
||||
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, node)
|
||||
|
||||
_, currentHeight, err := node.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
@ -1013,7 +851,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
|
||||
}
|
||||
|
||||
// Next, create a new transaction spending that output.
|
||||
spendingTx := createSpendTx(outpoint, pkScript, t)
|
||||
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript)
|
||||
|
||||
// Before we broadcast the spending transaction, we'll cancel the
|
||||
// notification of the first client.
|
||||
@ -1025,8 +863,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
|
||||
t.Fatalf("unable to broadcast tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(node, spenderSha)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(node, spenderSha); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -1127,7 +964,7 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.TestChainNotifier
|
||||
t *testing.T) {
|
||||
|
||||
// Set up a new miner that we can use to cause a reorg.
|
||||
miner2, err := rpctest.New(netParams, nil, nil)
|
||||
miner2, err := rpctest.New(chainntnfs.NetParams, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create mining node: %v", err)
|
||||
}
|
||||
@ -1169,13 +1006,11 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.TestChainNotifier
|
||||
t.Fatalf("unable to remove node: %v", err)
|
||||
}
|
||||
|
||||
txid, pkScript, err := getTestTxIdAndScript(miner)
|
||||
txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -1257,9 +1092,7 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.TestChainNotifier
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get send tx: %v", err)
|
||||
}
|
||||
|
||||
err = waitForMempoolTx(miner, txid)
|
||||
if err != nil {
|
||||
if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
|
||||
@ -1470,7 +1303,7 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Set up a new miner that we can use to cause a reorg.
|
||||
miner2, err := rpctest.New(netParams, nil, nil)
|
||||
miner2, err := rpctest.New(chainntnfs.NetParams, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create mining node: %v", err)
|
||||
}
|
||||
@ -1629,13 +1462,12 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
|
||||
|
||||
type testCase struct {
|
||||
name string
|
||||
|
||||
test func(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier, t *testing.T)
|
||||
test func(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier,
|
||||
t *testing.T)
|
||||
}
|
||||
|
||||
type blockCatchupTestCase struct {
|
||||
name string
|
||||
|
||||
test func(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier,
|
||||
t *testing.T)
|
||||
}
|
||||
@ -1722,25 +1554,14 @@ func TestInterfaces(t *testing.T) {
|
||||
// dedicated miner to generate blocks, cause re-orgs, etc. We'll set up
|
||||
// this node with a chain length of 125, so we have plenty of BTC to
|
||||
// play around with.
|
||||
miner, err := rpctest.New(netParams, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create mining node: %v", err)
|
||||
}
|
||||
defer miner.TearDown()
|
||||
if err := miner.SetUp(true, 25); err != nil {
|
||||
t.Fatalf("unable to set up mining node: %v", err)
|
||||
}
|
||||
miner, tearDown := chainntnfs.NewMiner(t, nil, true, 25)
|
||||
defer tearDown()
|
||||
|
||||
rpcConfig := miner.RPCConfig()
|
||||
p2pAddr := miner.P2PAddress()
|
||||
|
||||
log.Printf("Running %v ChainNotifier interface tests\n", len(ntfnTests))
|
||||
var (
|
||||
notifier chainntnfs.TestChainNotifier
|
||||
cleanUp func()
|
||||
log.Printf("Running %v ChainNotifier interface tests", len(ntfnTests))
|
||||
|
||||
newNotifier func() (chainntnfs.TestChainNotifier, error)
|
||||
)
|
||||
for _, notifierDriver := range chainntnfs.RegisteredNotifiers() {
|
||||
// Initialize a height hint cache for each notifier.
|
||||
tempDir, err := ioutil.TempDir("", "channeldb")
|
||||
@ -1756,72 +1577,21 @@ func TestInterfaces(t *testing.T) {
|
||||
t.Fatalf("unable to create height hint cache: %v", err)
|
||||
}
|
||||
|
||||
notifierType := notifierDriver.NotifierType
|
||||
var (
|
||||
cleanUp func()
|
||||
newNotifier func() (chainntnfs.TestChainNotifier, error)
|
||||
notifierType = notifierDriver.NotifierType
|
||||
)
|
||||
|
||||
switch notifierType {
|
||||
case "bitcoind":
|
||||
// Start a bitcoind instance.
|
||||
tempBitcoindDir, err := ioutil.TempDir("", "bitcoind")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create temp dir: %v", err)
|
||||
}
|
||||
zmqBlockHost := "ipc:///" + tempBitcoindDir + "/blocks.socket"
|
||||
zmqTxHost := "ipc:///" + tempBitcoindDir + "/tx.socket"
|
||||
cleanUp1 := func() {
|
||||
os.RemoveAll(tempBitcoindDir)
|
||||
}
|
||||
cleanUp = cleanUp1
|
||||
rpcPort := rand.Int()%(65536-1024) + 1024
|
||||
bitcoind := exec.Command(
|
||||
"bitcoind",
|
||||
"-datadir="+tempBitcoindDir,
|
||||
"-regtest",
|
||||
"-connect="+p2pAddr,
|
||||
"-txindex",
|
||||
"-rpcauth=weks:469e9bb14ab2360f8e226efed5ca6f"+
|
||||
"d$507c670e800a95284294edb5773b05544b"+
|
||||
"220110063096c221be9933c82d38e1",
|
||||
fmt.Sprintf("-rpcport=%d", rpcPort),
|
||||
"-disablewallet",
|
||||
"-zmqpubrawblock="+zmqBlockHost,
|
||||
"-zmqpubrawtx="+zmqTxHost,
|
||||
var bitcoindConn *chain.BitcoindConn
|
||||
bitcoindConn, cleanUp = chainntnfs.NewBitcoindBackend(
|
||||
t, p2pAddr, true,
|
||||
)
|
||||
err = bitcoind.Start()
|
||||
if err != nil {
|
||||
cleanUp1()
|
||||
t.Fatalf("Couldn't start bitcoind: %v", err)
|
||||
}
|
||||
cleanUp2 := func() {
|
||||
bitcoind.Process.Kill()
|
||||
bitcoind.Wait()
|
||||
cleanUp1()
|
||||
}
|
||||
cleanUp = cleanUp2
|
||||
|
||||
// Wait for the bitcoind instance to start up.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
host := fmt.Sprintf("127.0.0.1:%d", rpcPort)
|
||||
chainConn, err := chain.NewBitcoindConn(
|
||||
netParams, host, "weks", "weks", zmqBlockHost,
|
||||
zmqTxHost, 100*time.Millisecond,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to establish connection to "+
|
||||
"bitcoind: %v", err)
|
||||
}
|
||||
if err := chainConn.Start(); err != nil {
|
||||
t.Fatalf("unable to establish connection to "+
|
||||
"bitcoind: %v", err)
|
||||
}
|
||||
cleanUp3 := func() {
|
||||
chainConn.Stop()
|
||||
cleanUp2()
|
||||
}
|
||||
cleanUp = cleanUp3
|
||||
|
||||
newNotifier = func() (chainntnfs.TestChainNotifier, error) {
|
||||
return bitcoindnotify.New(
|
||||
chainConn, hintCache, hintCache,
|
||||
bitcoindConn, hintCache, hintCache,
|
||||
), nil
|
||||
}
|
||||
|
||||
@ -1832,45 +1602,11 @@ func TestInterfaces(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
cleanUp = func() {}
|
||||
|
||||
case "neutrino":
|
||||
spvDir, err := ioutil.TempDir("", "neutrino")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create temp dir: %v", err)
|
||||
}
|
||||
|
||||
dbName := filepath.Join(spvDir, "neutrino.db")
|
||||
spvDatabase, err := walletdb.Create("bdb", dbName)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create walletdb: %v", err)
|
||||
}
|
||||
|
||||
// Create an instance of neutrino connected to the
|
||||
// running btcd instance.
|
||||
spvConfig := neutrino.Config{
|
||||
DataDir: spvDir,
|
||||
Database: spvDatabase,
|
||||
ChainParams: *netParams,
|
||||
ConnectPeers: []string{p2pAddr},
|
||||
}
|
||||
spvNode, err := neutrino.NewChainService(spvConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create neutrino: %v", err)
|
||||
}
|
||||
spvNode.Start()
|
||||
|
||||
cleanUp = func() {
|
||||
spvNode.Stop()
|
||||
spvDatabase.Close()
|
||||
os.RemoveAll(spvDir)
|
||||
}
|
||||
|
||||
// We'll also wait for the instance to sync up fully to
|
||||
// the chain generated by the btcd instance.
|
||||
for !spvNode.IsCurrent() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
var spvNode *neutrino.ChainService
|
||||
spvNode, cleanUp = chainntnfs.NewNeutrinoBackend(
|
||||
t, p2pAddr,
|
||||
)
|
||||
newNotifier = func() (chainntnfs.TestChainNotifier, error) {
|
||||
return neutrinonotify.New(
|
||||
spvNode, hintCache, hintCache,
|
||||
@ -1878,13 +1614,14 @@ func TestInterfaces(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("Running ChainNotifier interface tests for: %v", notifierType)
|
||||
log.Printf("Running ChainNotifier interface tests for: %v",
|
||||
notifierType)
|
||||
|
||||
notifier, err = newNotifier()
|
||||
notifier, err := newNotifier()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create %v notifier: %v", notifierType, err)
|
||||
t.Fatalf("unable to create %v notifier: %v",
|
||||
notifierType, err)
|
||||
}
|
||||
|
||||
if err := notifier.Start(); err != nil {
|
||||
t.Fatalf("unable to start notifier %v: %v",
|
||||
notifierType, err)
|
||||
@ -1897,7 +1634,6 @@ func TestInterfaces(t *testing.T) {
|
||||
success := t.Run(testName, func(t *testing.T) {
|
||||
ntfnTest.test(miner, notifier, t)
|
||||
})
|
||||
|
||||
if !success {
|
||||
break
|
||||
}
|
||||
@ -1905,8 +1641,8 @@ func TestInterfaces(t *testing.T) {
|
||||
|
||||
notifier.Stop()
|
||||
|
||||
// Run catchup tests separately since they require
|
||||
// restarting the notifier every time.
|
||||
// Run catchup tests separately since they require restarting
|
||||
// the notifier every time.
|
||||
for _, blockCatchupTest := range blockCatchupTests {
|
||||
notifier, err = newNotifier()
|
||||
if err != nil {
|
||||
@ -1931,6 +1667,5 @@ func TestInterfaces(t *testing.T) {
|
||||
if cleanUp != nil {
|
||||
cleanUp()
|
||||
}
|
||||
cleanUp = nil
|
||||
}
|
||||
}
|
||||
|
268
chainntnfs/test_utils.go
Normal file
268
chainntnfs/test_utils.go
Normal file
@ -0,0 +1,268 @@
|
||||
// +build debug
|
||||
|
||||
package chainntnfs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/integration/rpctest"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcwallet/chain"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/lightninglabs/neutrino"
|
||||
)
|
||||
|
||||
var (
|
||||
NetParams = &chaincfg.RegressionNetParams
|
||||
|
||||
testPrivKey = []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,
|
||||
}
|
||||
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), testPrivKey)
|
||||
addrPk, _ = btcutil.NewAddressPubKey(
|
||||
pubKey.SerializeCompressed(), NetParams,
|
||||
)
|
||||
testAddr = addrPk.AddressPubKeyHash()
|
||||
)
|
||||
|
||||
// GetTestTxidAndScript generate a new test transaction and returns its txid and
|
||||
// the script of the output being generated.
|
||||
func GetTestTxidAndScript(h *rpctest.Harness) (*chainhash.Hash, []byte, error) {
|
||||
script, err := txscript.PayToAddrScript(testAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
output := &wire.TxOut{Value: 2e8, PkScript: script}
|
||||
txid, err := h.SendOutputs([]*wire.TxOut{output}, 10)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return txid, script, nil
|
||||
}
|
||||
|
||||
// WaitForMempoolTx waits for the txid to be seen in the miner's mempool.
|
||||
func WaitForMempoolTx(miner *rpctest.Harness, txid *chainhash.Hash) error {
|
||||
timeout := time.After(10 * time.Second)
|
||||
for {
|
||||
// Check for the harness' knowledge of the txid.
|
||||
tx, err := miner.Node.GetRawTransaction(txid)
|
||||
if err != nil {
|
||||
jsonErr, ok := err.(*btcjson.RPCError)
|
||||
if ok && jsonErr.Code == btcjson.ErrRPCNoTxInfo {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if tx != nil && tx.Hash().IsEqual(txid) {
|
||||
break
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-timeout:
|
||||
return errors.New("timed out waiting for tx")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateSpendableOutput creates and returns an output that can be spent later
|
||||
// on.
|
||||
func CreateSpendableOutput(t *testing.T, miner *rpctest.Harness) (*wire.OutPoint, []byte) {
|
||||
t.Helper()
|
||||
|
||||
// Create a transaction that only has one output, the one destined for
|
||||
// the recipient.
|
||||
script, err := txscript.PayToAddrScript(testAddr)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create p2pkh script: %v", err)
|
||||
}
|
||||
output := &wire.TxOut{Value: 2e8, PkScript: script}
|
||||
txid, err := miner.SendOutputsWithoutChange([]*wire.TxOut{output}, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create tx: %v", err)
|
||||
}
|
||||
|
||||
// Mine the transaction to mark the output as spendable.
|
||||
if err := WaitForMempoolTx(miner, txid); err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
if _, err := miner.Node.Generate(1); err != nil {
|
||||
t.Fatalf("unable to generate single block: %v", err)
|
||||
}
|
||||
|
||||
return wire.NewOutPoint(txid, 0), script
|
||||
}
|
||||
|
||||
// CreateSpendTx creates a transaction spending the specified output.
|
||||
func CreateSpendTx(t *testing.T, outpoint *wire.OutPoint, pkScript []byte) *wire.MsgTx {
|
||||
t.Helper()
|
||||
|
||||
spendingTx := wire.NewMsgTx(1)
|
||||
spendingTx.AddTxIn(&wire.TxIn{PreviousOutPoint: *outpoint})
|
||||
spendingTx.AddTxOut(&wire.TxOut{Value: 1e8, PkScript: pkScript})
|
||||
|
||||
sigScript, err := txscript.SignatureScript(
|
||||
spendingTx, 0, pkScript, txscript.SigHashAll, privKey, true,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to sign tx: %v", err)
|
||||
}
|
||||
spendingTx.TxIn[0].SignatureScript = sigScript
|
||||
|
||||
return spendingTx
|
||||
}
|
||||
|
||||
// NewMiner spawns testing harness backed by a btcd node that can serve as a
|
||||
// miner.
|
||||
func NewMiner(t *testing.T, extraArgs []string, createChain bool,
|
||||
spendableOutputs uint32) (*rpctest.Harness, func()) {
|
||||
|
||||
t.Helper()
|
||||
|
||||
node, err := rpctest.New(NetParams, nil, extraArgs)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create backend node: %v", err)
|
||||
}
|
||||
if err := node.SetUp(createChain, spendableOutputs); err != nil {
|
||||
node.TearDown()
|
||||
t.Fatalf("unable to set up backend node: %v", err)
|
||||
}
|
||||
|
||||
return node, func() { node.TearDown() }
|
||||
}
|
||||
|
||||
// NewBitcoindBackend spawns a new bitcoind node that connects to a miner at the
|
||||
// specified address. The txindex boolean can be set to determine whether the
|
||||
// backend node should maintain a transaction index. A connection to the newly
|
||||
// spawned bitcoind node is returned.
|
||||
func NewBitcoindBackend(t *testing.T, minerAddr string,
|
||||
txindex bool) (*chain.BitcoindConn, func()) {
|
||||
|
||||
t.Helper()
|
||||
|
||||
tempBitcoindDir, err := ioutil.TempDir("", "bitcoind")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create temp dir: %v", err)
|
||||
}
|
||||
|
||||
rpcPort := rand.Intn(65536-1024) + 1024
|
||||
zmqBlockHost := "ipc:///" + tempBitcoindDir + "/blocks.socket"
|
||||
zmqTxHost := "ipc:///" + tempBitcoindDir + "/tx.socket"
|
||||
|
||||
args := []string{
|
||||
"-connect=" + minerAddr,
|
||||
"-datadir=" + tempBitcoindDir,
|
||||
"-regtest",
|
||||
"-rpcauth=weks:469e9bb14ab2360f8e226efed5ca6fd$507c670e800a952" +
|
||||
"84294edb5773b05544b220110063096c221be9933c82d38e1",
|
||||
fmt.Sprintf("-rpcport=%d", rpcPort),
|
||||
"-disablewallet",
|
||||
"-zmqpubrawblock=" + zmqBlockHost,
|
||||
"-zmqpubrawtx=" + zmqTxHost,
|
||||
}
|
||||
if txindex {
|
||||
args = append(args, "-txindex")
|
||||
}
|
||||
|
||||
bitcoind := exec.Command("bitcoind", args...)
|
||||
if err := bitcoind.Start(); err != nil {
|
||||
os.RemoveAll(tempBitcoindDir)
|
||||
t.Fatalf("unable to start bitcoind: %v", err)
|
||||
}
|
||||
|
||||
// Wait for the bitcoind instance to start up.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
host := fmt.Sprintf("127.0.0.1:%d", rpcPort)
|
||||
conn, err := chain.NewBitcoindConn(
|
||||
NetParams, host, "weks", "weks", zmqBlockHost, zmqTxHost,
|
||||
100*time.Millisecond,
|
||||
)
|
||||
if err != nil {
|
||||
bitcoind.Process.Kill()
|
||||
bitcoind.Wait()
|
||||
os.RemoveAll(tempBitcoindDir)
|
||||
t.Fatalf("unable to establish connection to bitcoind: %v", err)
|
||||
}
|
||||
if err := conn.Start(); err != nil {
|
||||
bitcoind.Process.Kill()
|
||||
bitcoind.Wait()
|
||||
os.RemoveAll(tempBitcoindDir)
|
||||
t.Fatalf("unable to establish connection to bitcoind: %v", err)
|
||||
}
|
||||
|
||||
return conn, func() {
|
||||
conn.Stop()
|
||||
bitcoind.Process.Kill()
|
||||
bitcoind.Wait()
|
||||
os.RemoveAll(tempBitcoindDir)
|
||||
}
|
||||
}
|
||||
|
||||
// NewNeutrinoBackend spawns a new neutrino node that connects to a miner at
|
||||
// the specified address.
|
||||
func NewNeutrinoBackend(t *testing.T, minerAddr string) (*neutrino.ChainService, func()) {
|
||||
t.Helper()
|
||||
|
||||
spvDir, err := ioutil.TempDir("", "neutrino")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create temp dir: %v", err)
|
||||
}
|
||||
|
||||
dbName := filepath.Join(spvDir, "neutrino.db")
|
||||
spvDatabase, err := walletdb.Create("bdb", dbName)
|
||||
if err != nil {
|
||||
os.RemoveAll(spvDir)
|
||||
t.Fatalf("unable to create walletdb: %v", err)
|
||||
}
|
||||
|
||||
// Create an instance of neutrino connected to the running btcd
|
||||
// instance.
|
||||
spvConfig := neutrino.Config{
|
||||
DataDir: spvDir,
|
||||
Database: spvDatabase,
|
||||
ChainParams: *NetParams,
|
||||
ConnectPeers: []string{minerAddr},
|
||||
}
|
||||
spvNode, err := neutrino.NewChainService(spvConfig)
|
||||
if err != nil {
|
||||
os.RemoveAll(spvDir)
|
||||
spvDatabase.Close()
|
||||
t.Fatalf("unable to create neutrino: %v", err)
|
||||
}
|
||||
|
||||
// We'll also wait for the instance to sync up fully to the chain
|
||||
// generated by the btcd instance.
|
||||
spvNode.Start()
|
||||
for !spvNode.IsCurrent() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
return spvNode, func() {
|
||||
spvNode.Stop()
|
||||
spvDatabase.Close()
|
||||
os.RemoveAll(spvDir)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user