github.com/decred/dcrlnd@v0.7.6/chainntnfs/test_utils.go (about)

     1  //go:build dev
     2  // +build dev
     3  
     4  package chainntnfs
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/decred/dcrd/chaincfg/chainhash"
    14  	"github.com/decred/dcrd/chaincfg/v3"
    15  	"github.com/decred/dcrd/dcrec"
    16  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    17  	"github.com/decred/dcrd/dcrutil/v4"
    18  	jsonrpctypes "github.com/decred/dcrd/rpc/jsonrpc/types/v4"
    19  	"github.com/decred/dcrd/txscript/v4"
    20  	"github.com/decred/dcrd/txscript/v4/sign"
    21  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    22  	"github.com/decred/dcrd/wire"
    23  	"github.com/decred/dcrlnd/input"
    24  	rpctest "github.com/decred/dcrtest/dcrdtest"
    25  )
    26  
    27  var (
    28  	// trickleInterval is the interval at which the miner should trickle
    29  	// transactions to its peers. We'll set it small to ensure the miner
    30  	// propagates transactions quickly in the tests.
    31  	trickleInterval = 10 * time.Millisecond
    32  
    33  	testFeeRate = dcrutil.Amount(1e4)
    34  )
    35  
    36  var (
    37  	netParams = chaincfg.SimNetParams()
    38  )
    39  
    40  // randPubKeyHashScript generates a P2PKH script that pays to the public key of
    41  // a randomly-generated private key.
    42  func randPubKeyHashScript() ([]byte, *secp256k1.PrivateKey, error) {
    43  	privKey, err := secp256k1.GeneratePrivateKey()
    44  	if err != nil {
    45  		return nil, nil, err
    46  	}
    47  	addrPk, _ := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0(
    48  		privKey.PubKey(), netParams,
    49  	)
    50  	testAddr := addrPk.AddressPubKeyHash()
    51  
    52  	pkScript, err := input.PayToAddrScript(testAddr)
    53  	if err != nil {
    54  		return nil, nil, err
    55  	}
    56  	return pkScript, privKey, nil
    57  }
    58  
    59  // GetTestTxidAndScript generate a new test transaction and returns its txid and
    60  // the script of the output being generated.
    61  func GetTestTxidAndScript(h *rpctest.Harness) (*chainhash.Hash, []byte, error) {
    62  	pkScript, _, err := randPubKeyHashScript()
    63  	if err != nil {
    64  		return nil, nil, fmt.Errorf("unable to generate pkScript: %v", err)
    65  	}
    66  	output := &wire.TxOut{Value: 2e8, PkScript: pkScript}
    67  	txid, err := h.SendOutputs(context.Background(), []*wire.TxOut{output}, testFeeRate)
    68  	if err != nil {
    69  		return nil, nil, err
    70  	}
    71  
    72  	return txid, pkScript, nil
    73  }
    74  
    75  // WaitForMempoolTx waits for the txid to be seen in the miner's mempool.
    76  func WaitForMempoolTx(miner *rpctest.Harness, txid *chainhash.Hash) error {
    77  	timeout := time.After(10 * time.Second)
    78  	trickle := time.After(2 * trickleInterval)
    79  
    80  checkmempool:
    81  	for {
    82  		// Check via the raw mempool as this is a better hint as to
    83  		// whether a new template will be generated once we attempt to
    84  		// generate a block.
    85  		mempool, err := miner.Node.GetRawMempool(context.Background(), jsonrpctypes.GRMRegular)
    86  		if err != nil {
    87  			return err
    88  		}
    89  
    90  		for _, mtx := range mempool {
    91  			if mtx.IsEqual(txid) {
    92  				break checkmempool
    93  			}
    94  		}
    95  
    96  		select {
    97  		case <-time.After(100 * time.Millisecond):
    98  		case <-timeout:
    99  			return errors.New("timed out waiting for tx")
   100  		}
   101  	}
   102  
   103  	// To ensure any transactions propagate from the miner to the peers
   104  	// before returning, ensure we have waited for at least
   105  	// 2*trickleInterval before returning.
   106  	select {
   107  	case <-trickle:
   108  	case <-timeout:
   109  		return errors.New("timeout waiting for trickle interval. " +
   110  			"Trickle interval to large?")
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  // CreateSpendableOutput creates and returns an output that can be spent later
   117  // on.
   118  func CreateSpendableOutput(t *testing.T,
   119  	miner *rpctest.Harness,
   120  	vw *rpctest.VotingWallet) (*wire.OutPoint, *wire.TxOut, *secp256k1.PrivateKey) {
   121  
   122  	t.Helper()
   123  
   124  	// Create a transaction that only has one output, the one destined for
   125  	// the recipient.
   126  	pkScript, privKey, err := randPubKeyHashScript()
   127  	if err != nil {
   128  		t.Fatalf("unable to generate pkScript: %v", err)
   129  	}
   130  	output := &wire.TxOut{Value: 2e8, PkScript: pkScript}
   131  	// TODO(decred): SendOutputsWithoutChange
   132  	txid, err := miner.SendOutputs(context.Background(), []*wire.TxOut{output}, testFeeRate)
   133  	if err != nil {
   134  		t.Fatalf("unable to create tx: %v", err)
   135  	}
   136  
   137  	// Mine the transaction to mark the output as spendable.
   138  	if err := WaitForMempoolTx(miner, txid); err != nil {
   139  		t.Fatalf("tx not relayed to miner: %v", err)
   140  	}
   141  	generate := miner.Node.Generate
   142  	if vw != nil {
   143  		generate = vw.GenerateBlocks
   144  	}
   145  	if _, err := generate(context.Background(), 1); err != nil {
   146  		t.Fatalf("unable to generate single block: %v", err)
   147  	}
   148  
   149  	return wire.NewOutPoint(txid, 0, wire.TxTreeRegular), output, privKey
   150  }
   151  
   152  // CreateSpendTx creates a transaction spending the specified output.
   153  func CreateSpendTx(t *testing.T, prevOutPoint *wire.OutPoint,
   154  	prevOutput *wire.TxOut, privKey *secp256k1.PrivateKey) *wire.MsgTx {
   155  
   156  	t.Helper()
   157  
   158  	spendingTx := wire.NewMsgTx()
   159  	spendingTx.Version = 1
   160  	spendingTx.AddTxIn(&wire.TxIn{PreviousOutPoint: *prevOutPoint})
   161  	spendingTx.AddTxOut(&wire.TxOut{Value: 1e8, PkScript: prevOutput.PkScript})
   162  
   163  	sigScript, err := sign.SignatureScript(
   164  		spendingTx, 0, prevOutput.PkScript, txscript.SigHashAll,
   165  		privKey.Serialize(), dcrec.STEcdsaSecp256k1, true,
   166  	)
   167  	if err != nil {
   168  		t.Fatalf("unable to sign tx: %v", err)
   169  	}
   170  	spendingTx.TxIn[0].SignatureScript = sigScript
   171  
   172  	return spendingTx
   173  }