Skip to content

Commit

Permalink
multi: repo-wide bandaid for rand.Seed abuses
Browse files Browse the repository at this point in the history
Early on we got in the habit of building tests on data with reproducible
random sequences using the math/rand package's global *math.Rand
instance, seeding it with some arbitrary hard coded numbers to get
certain sequence. That proved quite problematic for test maintenance,
concurrency, and now the standard library rightly has deprecated the use
of rand.Seed and they have made the default initialization actually
random instead of with "1" as the seed.

> The math/rand package now automatically seeds the global random number
> generator (used by top-level functions like Float64 and Int) with a
> random value, and the top-level Seed function has been deprecated.
> Programs that need a reproducible sequence of random numbers should
> prefer to allocate their own random source, using
> rand.New(rand.NewSource(seed)).
>
> Programs that need the earlier consistent global seeding behavior can
> set GODEBUG=randautoseed=0 in their environment.
>
> The top-level Read function has been deprecated. In almost all cases,
> crypto/rand.Read is more appropriate.

This commit is a bandaid to get the test passing given the new random
seeding of the package level math/rand.Rand. We should look at rewriting
some of these tests to not have unrecorded but expected magic values to
produce certain test data set.
  • Loading branch information
chappjc committed Feb 21, 2023
1 parent 237fe94 commit 15998d6
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 62 deletions.
4 changes: 0 additions & 4 deletions client/db/bolt/db_test.go
Expand Up @@ -20,10 +20,6 @@ import (
"go.etcd.io/bbolt"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

var (
tLogger = dex.StdOutLogger("db_TEST", dex.LevelTrace)
)
Expand Down
13 changes: 6 additions & 7 deletions dex/order/match_test.go
Expand Up @@ -8,14 +8,13 @@ import (
"time"
)

// randomCommitment creates a random order commitment. If you require a matching
// commitment, generate a Preimage, then Preimage.Commit().
func randomCommitment() (com Commitment) {
rand.Read(com[:])
return
}

func TestMatchID(t *testing.T) {
rnd := rand.New(rand.NewSource(1))
randomCommitment := func() (com Commitment) {
rnd.Read(com[:])
return
}

// taker
marketID0, _ := hex.DecodeString("f1f4fb29235f5eeef55b27d909aac860828f6cf45f0b0fab92c6265844c50e54")
var marketID OrderID
Expand Down
49 changes: 39 additions & 10 deletions dex/order/test/helpers.go
Expand Up @@ -2,6 +2,7 @@ package test

import (
"bytes"
crand "crypto/rand"
"encoding/binary"
"fmt"
"math/rand"
Expand All @@ -18,6 +19,34 @@ const (
addressLength = 34
)

var rnd = rand.New(CryptoSource)

func UseRand(use *rand.Rand) {
rnd = use
}

var CryptoSource cryptoSource

type cryptoSource struct{}

func (cs cryptoSource) Uint64() uint64 {
var b [8]byte
crand.Read(b[:])
return binary.LittleEndian.Uint64(b[:])
}

func (cs cryptoSource) Int63() int64 {
const rngMask = 1<<63 - 1
return int64(cs.Uint64() & rngMask)
}

func (cs cryptoSource) Seed(seed int64) { /* no-op */ }

var _ rand.Source = cryptoSource{}
var _ rand.Source = (*cryptoSource)(nil)
var _ rand.Source64 = cryptoSource{}
var _ rand.Source64 = (*cryptoSource)(nil)

var (
acctTemplate = account.AccountID{
0x22, 0x4c, 0xba, 0xaa, 0xfa, 0x80, 0xbf, 0x3b, 0xd1, 0xff, 0x73, 0x15,
Expand All @@ -29,22 +58,22 @@ var (

func randBytes(l int) []byte {
b := make([]byte, l)
rand.Read(b)
rnd.Read(b)
return b
}

func randUint32() uint32 { return uint32(rand.Int31()) }
func randUint64() uint64 { return uint64(rand.Int63()) }
func randUint32() uint32 { return uint32(rnd.Int31()) }
func randUint64() uint64 { return uint64(rnd.Int63()) }

func randBool() bool {
return rand.Intn(2) == 1
return rnd.Intn(2) == 1
}

// A random base-58 string.
func RandomAddress() string {
b := make([]byte, addressLength)
for i := range b {
b[i] = b58Set[rand.Intn(58)]
b[i] = b58Set[rnd.Intn(58)]
}
return string(b)
}
Expand Down Expand Up @@ -76,14 +105,14 @@ func RandomMatchID() order.MatchID {

// RandomPreimage creates a random order preimage.
func RandomPreimage() (pi order.Preimage) {
rand.Read(pi[:])
rnd.Read(pi[:])
return
}

// RandomCommitment creates a random order commitment. Use RandomPreimage
// followed by Preimage.Commit() if you require a matching commitment.
func RandomCommitment() (com order.Commitment) {
rand.Read(com[:])
rnd.Read(com[:])
return
}

Expand Down Expand Up @@ -143,7 +172,7 @@ func WriteLimitOrder(writer *Writer, rate, lots uint64, force order.TimeInForce,

// RandomLimitOrder creates a random limit order with a random writer.
func RandomLimitOrder() (*order.LimitOrder, order.Preimage) {
return WriteLimitOrder(RandomWriter(), randUint64(), randUint64(), order.TimeInForce(rand.Intn(2)), 0)
return WriteLimitOrder(RandomWriter(), randUint64(), randUint64(), order.TimeInForce(rnd.Intn(2)), 0)
}

// WriteMarketOrder creates a market order with the specified writer and
Expand Down Expand Up @@ -255,8 +284,8 @@ func RandomUserMatch() *order.UserMatch {
Quantity: randUint64(),
Rate: randUint64(),
Address: RandomAddress(),
Status: order.MatchStatus(rand.Intn(5)),
Side: order.MatchSide(rand.Intn(2)),
Status: order.MatchStatus(rnd.Intn(5)),
Side: order.MatchSide(rnd.Intn(2)),
FeeRateSwap: randUint64(),
}
}
Expand Down
5 changes: 2 additions & 3 deletions server/auth/cancel_test.go
@@ -1,6 +1,7 @@
package auth

import (
crand "crypto/rand"
"math/rand"
"sort"
"testing"
Expand All @@ -9,7 +10,7 @@ import (
)

func randomOrderID() (oid order.OrderID) {
rand.Read(oid[:])
crand.Read(oid[:])
return
}

Expand Down Expand Up @@ -79,8 +80,6 @@ func Test_latestOrders(t *testing.T) {
t.Errorf("expected 1 cancels, got %d", total)
}

rand.Seed(1324)

for i := total; i < int(cap); i++ {
ts++
ordList.add(&oidStamped{
Expand Down
30 changes: 17 additions & 13 deletions server/book/orderpq_test.go
Expand Up @@ -3,6 +3,7 @@ package book
import (
"flag"
"math/rand"
crand "math/rand"
"os"
"sort"
"testing"
Expand All @@ -15,25 +16,20 @@ type Order = order.LimitOrder

var (
bigList []*Order
orders = []*Order{
newLimitOrder(false, 42000000, 2, order.StandingTiF, 0),
newLimitOrder(false, 10000, 2, order.StandingTiF, 0),
newLimitOrder(false, 42000000, 2, order.StandingTiF, -1000), // rate dup, different time
newLimitOrder(false, 123000000, 2, order.StandingTiF, 0),
newLimitOrder(false, 42000000, 1, order.StandingTiF, 0), // rate and time dup, different OrderID
}
orders []*Order
rnd = rand.New(rand.NewSource(1))
)

func randomAccount() (user account.AccountID) {
rand.Read(user[:])
crand.Read(user[:])
return
}

func newFakeAddr() string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b := make([]byte, 35)
for i := range b {
b[i] = letters[rand.Int63()%int64(len(letters))]
b[i] = letters[rnd.Int63()%int64(len(letters))]
}
b[0], b[1] = 'D', 's' // at least have it resemble an address
return string(b)
Expand All @@ -44,7 +40,7 @@ func genBigList(listSize int) {
return
}
seed := int64(-3405439173988651889)
rand.Seed(seed)
rnd.Seed(seed)

dupRate := 800
if listSize < dupRate {
Expand All @@ -56,7 +52,7 @@ func genBigList(listSize int) {

bigList = make([]*Order, 0, listSize)
for i := 0; i < listSize; i++ {
lo := newLimitOrder(false, uint64(rand.Int63n(90000000)), uint64(rand.Int63n(6))+1, order.StandingTiF, rand.Int63n(240)-120)
lo := newLimitOrder(false, uint64(rnd.Int63n(90000000)), uint64(rnd.Int63n(6))+1, order.StandingTiF, rnd.Int63n(240)-120)
lo.Address = newFakeAddr()
// duplicate some prices
if (i+1)%(listSize/dupRate) == 0 {
Expand All @@ -75,6 +71,14 @@ const (

func TestMain(m *testing.M) {
flag.Parse() // for -short
rnd.Seed(4) // some predetermined and reproducible order IDs
orders = []*Order{
newLimitOrder(false, 42000000, 2, order.StandingTiF, 0),
newLimitOrder(false, 10000, 2, order.StandingTiF, 0),
newLimitOrder(false, 42000000, 2, order.StandingTiF, -1000), // rate dup, different time
newLimitOrder(false, 123000000, 2, order.StandingTiF, 0),
newLimitOrder(false, 42000000, 1, order.StandingTiF, 0), // rate and time dup, different OrderID
}
if testing.Short() {
genBigList(shortListLen)
} else {
Expand Down Expand Up @@ -419,13 +423,13 @@ func TestMaxOrderPQ_TieRate(t *testing.T) {
func TestMaxOrderPQ_TieRateAndTime(t *testing.T) {
pq := NewMaxOrderPQ(4)

// 7f9200eedcf2fa868173cdfc2101ee4d71ec024c1c052589b3371442aaa26c2d
// 3671433862ea385f967377d836040cfa74bd66cf35ee1795cc48cab2a9576bc1
ok := pq.Insert(orders[0])
if !ok {
t.Errorf("Failed to insert order %v", orders[0])
}

// 2eb563f255b0a9484bbbee718b2cdce3a31bd5ea8649b579b3184a4bd60d1703 ** higher priority
// 1cc5fe0804be6b8112b71dd2d8d4a48177ee78a7f2c663e620c369d3211c86a1 ** higher priority
ok = pq.Insert(orders[4])
if !ok {
t.Errorf("Failed to insert order %v", orders[4])
Expand Down
7 changes: 2 additions & 5 deletions server/coinlock/coinlocker_test.go
@@ -1,6 +1,7 @@
package coinlock

import (
crand "crypto/rand"
"math/rand"
"testing"

Expand All @@ -10,7 +11,7 @@ import (

func randomBytes(len int) []byte {
bytes := make([]byte, len)
rand.Read(bytes)
crand.Read(bytes)
return bytes
}

Expand Down Expand Up @@ -50,8 +51,6 @@ func verifyLocked(cl CoinLockChecker, coins []CoinID, wantLocked bool, t *testin
}

func Test_swapLocker_LockOrderCoins(t *testing.T) {
rand.Seed(0)

w := &test.Writer{
Addr: "asdf",
Acct: test.NextAccount(),
Expand Down Expand Up @@ -146,8 +145,6 @@ func Test_bookLocker_LockCoins(t *testing.T) {
masterLock := NewMasterCoinLocker()
bookLock := masterLock.Book()

rand.Seed(0)

coinMap := make(map[order.OrderID][]CoinID)
var allCoins []CoinID
numOrders := 99
Expand Down
16 changes: 9 additions & 7 deletions server/market/integ/booker_matcher_test.go
Expand Up @@ -23,6 +23,8 @@ var acct0 = account.AccountID{
0x46, 0x34, 0xe9, 0x1c, 0xec, 0x25, 0xd5, 0x40, // 32 bytes
}

var rnd = rand.New(rand.NewSource(1))

const (
AssetDCR uint32 = iota
AssetBTC
Expand All @@ -39,7 +41,7 @@ func startLogger() {
}

func randomPreimage() (pe order.Preimage) {
rand.Read(pe[:])
rnd.Read(pe[:])
return
}

Expand Down Expand Up @@ -243,7 +245,7 @@ func TestMatchWithBook_limitsOnly(t *testing.T) {
// New matching engine.
me := matcher.New()

rand.Seed(0)
rnd.Seed(0)

badLotsizeOrder := newLimit(false, 05000000, 1, order.ImmediateTiF, 0)
badLotsizeOrder.Order.(*order.LimitOrder).Quantity /= 2
Expand Down Expand Up @@ -497,7 +499,7 @@ func TestMatchWithBook_limitsOnly_multipleQueued(t *testing.T) {
// New matching engine.
me := matcher.New()

rand.Seed(0)
rnd.Seed(0)

// epochQueue is heterogenous w.r.t. type
epochQueue := []*matcher.OrderRevealed{
Expand Down Expand Up @@ -731,7 +733,7 @@ func TestMatch_cancelOnly(t *testing.T) {
// New matching engine.
me := matcher.New()

rand.Seed(0)
rnd.Seed(0)

fakeOrder := newLimitOrder(false, 4550000, 1, order.ImmediateTiF, 0)
fakeOrder.ServerTime = time.Unix(1566497654, 0)
Expand Down Expand Up @@ -861,7 +863,7 @@ func TestMatch_marketSellsOnly(t *testing.T) {
// New matching engine.
me := matcher.New()

rand.Seed(0)
rnd.Seed(0)

badLotsizeOrder := newMarketSell(1, 0)
badLotsizeOrder.Order.(*order.MarketOrder).Quantity /= 2
Expand Down Expand Up @@ -1116,7 +1118,7 @@ func TestMatch_marketBuysOnly(t *testing.T) {
// New matching engine.
me := matcher.New()

rand.Seed(0)
rnd.Seed(0)

nSell := len(bookSellOrders)
//nBuy := len(bookBuyOrders)
Expand Down Expand Up @@ -1291,7 +1293,7 @@ func TestMatchWithBook_everything_multipleQueued(t *testing.T) {
// New matching engine.
me := matcher.New()

rand.Seed(12)
rnd.Seed(12)

nSell := len(bookSellOrders)
nBuy := len(bookBuyOrders)
Expand Down

0 comments on commit 15998d6

Please sign in to comment.