lbcd/txscript/hashcache_test.go
Conner Fromknecht 5300a19d06
txscript/hashcache_test: call rand.Seed once in init
This resolves the more fundamental flake in the unit tests noted in the
prior commit.

Because multiple unit tests call rand.Seed in parallel, it's possible
they can be executed with the same unix timestamp (in seconds). If the
second call happens between generating the hash cache and checking that
the cache doesn't contain a random txn, the random transaction is in
fact a duplicate of one generated earlier since the RNG state was reset.

To remedy, we initialize rand.Seed once in the init function.
2021-02-02 13:31:47 -08:00

181 lines
4.5 KiB
Go

// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"math/rand"
"testing"
"time"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
)
func init() {
rand.Seed(time.Now().Unix())
}
// genTestTx creates a random transaction for uses within test cases.
func genTestTx() (*wire.MsgTx, error) {
tx := wire.NewMsgTx(2)
tx.Version = rand.Int31()
numTxins := 1 + rand.Intn(11)
for i := 0; i < numTxins; i++ {
randTxIn := wire.TxIn{
PreviousOutPoint: wire.OutPoint{
Index: uint32(rand.Int31()),
},
Sequence: uint32(rand.Int31()),
}
_, err := rand.Read(randTxIn.PreviousOutPoint.Hash[:])
if err != nil {
return nil, err
}
tx.TxIn = append(tx.TxIn, &randTxIn)
}
numTxouts := 1 + rand.Intn(11)
for i := 0; i < numTxouts; i++ {
randTxOut := wire.TxOut{
Value: rand.Int63(),
PkScript: make([]byte, rand.Intn(30)),
}
if _, err := rand.Read(randTxOut.PkScript); err != nil {
return nil, err
}
tx.TxOut = append(tx.TxOut, &randTxOut)
}
return tx, nil
}
// TestHashCacheAddContainsHashes tests that after items have been added to the
// hash cache, the ContainsHashes method returns true for all the items
// inserted. Conversely, ContainsHashes should return false for any items
// _not_ in the hash cache.
func TestHashCacheAddContainsHashes(t *testing.T) {
t.Parallel()
cache := NewHashCache(10)
var err error
// First, we'll generate 10 random transactions for use within our
// tests.
const numTxns = 10
txns := make([]*wire.MsgTx, numTxns)
for i := 0; i < numTxns; i++ {
txns[i], err = genTestTx()
if err != nil {
t.Fatalf("unable to generate test tx: %v", err)
}
}
// With the transactions generated, we'll add each of them to the hash
// cache.
for _, tx := range txns {
cache.AddSigHashes(tx)
}
// Next, we'll ensure that each of the transactions inserted into the
// cache are properly located by the ContainsHashes method.
for _, tx := range txns {
txid := tx.TxHash()
if ok := cache.ContainsHashes(&txid); !ok {
t.Fatalf("txid %v not found in cache but should be: ",
txid)
}
}
randTx, err := genTestTx()
if err != nil {
t.Fatalf("unable to generate tx: %v", err)
}
// Finally, we'll assert that a transaction that wasn't added to the
// cache won't be reported as being present by the ContainsHashes
// method.
randTxid := randTx.TxHash()
if ok := cache.ContainsHashes(&randTxid); ok {
t.Fatalf("txid %v wasn't inserted into cache but was found",
randTxid)
}
}
// TestHashCacheAddGet tests that the sighashes for a particular transaction
// are properly retrieved by the GetSigHashes function.
func TestHashCacheAddGet(t *testing.T) {
t.Parallel()
cache := NewHashCache(10)
// To start, we'll generate a random transaction and compute the set of
// sighashes for the transaction.
randTx, err := genTestTx()
if err != nil {
t.Fatalf("unable to generate tx: %v", err)
}
sigHashes := NewTxSigHashes(randTx)
// Next, add the transaction to the hash cache.
cache.AddSigHashes(randTx)
// The transaction inserted into the cache above should be found.
txid := randTx.TxHash()
cacheHashes, ok := cache.GetSigHashes(&txid)
if !ok {
t.Fatalf("tx %v wasn't found in cache", txid)
}
// Finally, the sighashes retrieved should exactly match the sighash
// originally inserted into the cache.
if *sigHashes != *cacheHashes {
t.Fatalf("sighashes don't match: expected %v, got %v",
spew.Sdump(sigHashes), spew.Sdump(cacheHashes))
}
}
// TestHashCachePurge tests that items are able to be properly removed from the
// hash cache.
func TestHashCachePurge(t *testing.T) {
t.Parallel()
cache := NewHashCache(10)
var err error
// First we'll start by inserting numTxns transactions into the hash cache.
const numTxns = 10
txns := make([]*wire.MsgTx, numTxns)
for i := 0; i < numTxns; i++ {
txns[i], err = genTestTx()
if err != nil {
t.Fatalf("unable to generate test tx: %v", err)
}
}
for _, tx := range txns {
cache.AddSigHashes(tx)
}
// Once all the transactions have been inserted, we'll purge them from
// the hash cache.
for _, tx := range txns {
txid := tx.TxHash()
cache.PurgeSigHashes(&txid)
}
// At this point, none of the transactions inserted into the hash cache
// should be found within the cache.
for _, tx := range txns {
txid := tx.TxHash()
if ok := cache.ContainsHashes(&txid); ok {
t.Fatalf("tx %v found in cache but should have "+
"been purged: ", txid)
}
}
}