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 }