From 0504b9d66e69b4ebb8b1f7036e59e2caf3b3ef04 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Fri, 16 Apr 2021 23:52:40 +0200 Subject: [PATCH 01/27] Remove unused Time and Int16 --- libs/rand/random.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index e51e0259b7..2ab5e1e00e 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -78,10 +78,6 @@ func Uint() uint { return grand.Uint() } -func Int16() int16 { - return grand.Int16() -} - func Int32() int32 { return grand.Int32() } @@ -122,10 +118,6 @@ func Float64() float64 { return grand.Float64() } -func Time() time.Time { - return grand.Time() -} - func Bytes(n int) []byte { return grand.Bytes(n) } @@ -197,10 +189,6 @@ func (r *Rand) Uint() uint { return uint(i) } -func (r *Rand) Int16() int16 { - return int16(r.Uint32() & (1<<16 - 1)) -} - func (r *Rand) Int32() int32 { return int32(r.Uint32()) } From fb749032f6c81d0223f476a143f64b416b6d46a2 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 00:02:15 +0200 Subject: [PATCH 02/27] remove Uint which was just a cast and remove some tmrand calls on the way --- libs/rand/random.go | 4 ---- libs/rand/random_test.go | 1 - types/validator_set_test.go | 27 ++++++++++++++------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index 2ab5e1e00e..812d567082 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -74,10 +74,6 @@ func Uint64() uint64 { return grand.Uint64() } -func Uint() uint { - return grand.Uint() -} - func Int32() int32 { return grand.Int32() } diff --git a/libs/rand/random_test.go b/libs/rand/random_test.go index e669f250fa..3153c968a9 100644 --- a/libs/rand/random_test.go +++ b/libs/rand/random_test.go @@ -63,7 +63,6 @@ func testThemAll() string { blob, _ := json.Marshal(perm) fmt.Fprintf(out, "perm: %s\n", blob) fmt.Fprintf(out, "randInt: %d\n", Int()) - fmt.Fprintf(out, "randUint: %d\n", Uint()) fmt.Fprintf(out, "randIntn: %d\n", Intn(97)) fmt.Fprintf(out, "randInt31: %d\n", Int31()) fmt.Fprintf(out, "randInt32: %d\n", Int32()) diff --git a/types/validator_set_test.go b/types/validator_set_test.go index fca43b75da..f3ae9f565d 100644 --- a/types/validator_set_test.go +++ b/types/validator_set_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "math" + "math/rand" "sort" "strings" "testing" @@ -351,10 +352,10 @@ func TestProposerSelection3(t *testing.T) { // times is usually 1 times := int32(1) - mod := (tmrand.Int() % 5) + 1 - if tmrand.Int()%mod > 0 { + mod := (rand.Int() % 5) + 1 + if rand.Int()%mod > 0 { // sometimes its up to 5 - times = (tmrand.Int31() % 4) + 1 + times = (rand.Int31() % 4) + 1 } vset.IncrementProposerPriority(times) @@ -375,8 +376,8 @@ func randPubKey() crypto.PubKey { func randValidator(totalVotingPower int64) *Validator { // this modulo limits the ProposerPriority/VotingPower to stay in the // bounds of MaxTotalVotingPower minus the already existing voting power: - val := NewValidator(randPubKey(), int64(tmrand.Uint64()%uint64(MaxTotalVotingPower-totalVotingPower))) - val.ProposerPriority = tmrand.Int64() % (MaxTotalVotingPower - totalVotingPower) + val := NewValidator(randPubKey(), int64(rand.Uint64()%uint64(MaxTotalVotingPower-totalVotingPower))) + val.ProposerPriority = rand.Int63() % (MaxTotalVotingPower - totalVotingPower) return val } @@ -882,7 +883,7 @@ func permutation(valList []testVal) []testVal { return nil } permList := make([]testVal, len(valList)) - perm := tmrand.Perm(len(valList)) + perm := rand.Perm(len(valList)) for i, v := range perm { permList[v] = valList[i] } @@ -1284,14 +1285,14 @@ func randTestVSetCfg(t *testing.T, nBase, nAddMax int) testVSetCfg { const maxPower = 1000 var nOld, nDel, nChanged, nAdd int - nOld = int(tmrand.Uint()%uint(nBase)) + 1 + nOld = int(uint(rand.Int())%uint(nBase)) + 1 if nBase-nOld > 0 { - nDel = int(tmrand.Uint() % uint(nBase-nOld)) + nDel = int(uint(rand.Int()) % uint(nBase-nOld)) } nChanged = nBase - nOld - nDel if nAddMax > 0 { - nAdd = tmrand.Int()%nAddMax + 1 + nAdd = rand.Int()%nAddMax + 1 } cfg := testVSetCfg{} @@ -1303,12 +1304,12 @@ func randTestVSetCfg(t *testing.T, nBase, nAddMax int) testVSetCfg { cfg.expectedVals = make([]testVal, nBase-nDel+nAdd) for i := 0; i < nBase; i++ { - cfg.startVals[i] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)} + cfg.startVals[i] = testVal{fmt.Sprintf("v%d", i), int64(uint(rand.Int())%maxPower + 1)} if i < nOld { cfg.expectedVals[i] = cfg.startVals[i] } if i >= nOld && i < nOld+nChanged { - cfg.updatedVals[i-nOld] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)} + cfg.updatedVals[i-nOld] = testVal{fmt.Sprintf("v%d", i), int64(uint(rand.Int())%maxPower + 1)} cfg.expectedVals[i] = cfg.updatedVals[i-nOld] } if i >= nOld+nChanged { @@ -1317,7 +1318,7 @@ func randTestVSetCfg(t *testing.T, nBase, nAddMax int) testVSetCfg { } for i := nBase; i < nBase+nAdd; i++ { - cfg.addedVals[i-nBase] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)} + cfg.addedVals[i-nBase] = testVal{fmt.Sprintf("v%d", i), int64(uint(rand.Int())%maxPower + 1)} cfg.expectedVals[i-nDel] = cfg.addedVals[i-nBase] } @@ -1398,7 +1399,7 @@ func TestValSetUpdatePriorityOrderTests(t *testing.T) { func verifyValSetUpdatePriorityOrder(t *testing.T, valSet *ValidatorSet, cfg testVSetCfg, nMaxElections int32) { // Run election up to nMaxElections times, sort validators by priorities - valSet.IncrementProposerPriority(tmrand.Int31()%nMaxElections + 1) + valSet.IncrementProposerPriority(rand.Int31()%nMaxElections + 1) // apply the changes, get the updated validators, sort by priorities applyChangesToValSet(t, nil, valSet, cfg.addedVals, cfg.updatedVals, cfg.deletedVals) From 1b498f87baa945dbdd746b7b0bf0ea7da1d4fc77 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 00:07:50 +0200 Subject: [PATCH 03/27] remove Uint16 --- abci/example/kvstore/helpers.go | 4 +++- libs/rand/random.go | 4 ---- types/evidence_test.go | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/abci/example/kvstore/helpers.go b/abci/example/kvstore/helpers.go index 61df7b8398..bb4bb205d6 100644 --- a/abci/example/kvstore/helpers.go +++ b/abci/example/kvstore/helpers.go @@ -1,6 +1,8 @@ package kvstore import ( + mrand "math/rand" + "github.com/lazyledger/lazyledger-core/abci/types" tmrand "github.com/lazyledger/lazyledger-core/libs/rand" ) @@ -9,7 +11,7 @@ import ( // from the input value func RandVal(i int) types.ValidatorUpdate { pubkey := tmrand.Bytes(32) - power := tmrand.Uint16() + 1 + power := mrand.Uint32() & (1<<16 - 1) v := types.UpdateValidator(pubkey, int64(power), "") return v } diff --git a/libs/rand/random.go b/libs/rand/random.go index 812d567082..76515ad9e9 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -62,10 +62,6 @@ func Str(length int) string { return grand.Str(length) } -func Uint16() uint16 { - return grand.Uint16() -} - func Uint32() uint32 { return grand.Uint32() } diff --git a/types/evidence_test.go b/types/evidence_test.go index dd3fccb65d..8f64ca8934 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -2,6 +2,7 @@ package types import ( "math" + mrand "math/rand" "testing" "time" @@ -246,7 +247,7 @@ func makeHeaderRandom() *Header { return &Header{ Version: tmversion.Consensus{Block: version.BlockProtocol, App: 1}, ChainID: tmrand.Str(12), - Height: int64(tmrand.Uint16()) + 1, + Height: int64(mrand.Uint32()&(1<<16-1)) + 1, Time: time.Now(), LastBlockID: makeBlockIDRandom(), LastCommitHash: crypto.CRandBytes(tmhash.Size), From b099de41cfe5f27916c7e5cae12c655590d068a2 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 00:09:40 +0200 Subject: [PATCH 04/27] remove Bool --- libs/rand/random.go | 11 ----------- p2p/conn/secret_connection_test.go | 3 ++- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index 76515ad9e9..c04dc9c972 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -98,10 +98,6 @@ func Int63n(n int64) int64 { return grand.Int63n(n) } -func Bool() bool { - return grand.Bool() -} - func Float32() float32 { return grand.Float32() } @@ -263,13 +259,6 @@ func (r *Rand) Intn(n int) int { return i } -// Bool returns a uniformly random boolean -func (r *Rand) Bool() bool { - // See https://github.com/golang/go/issues/23804#issuecomment-365370418 - // for reasoning behind computing like this - return r.Int63()%2 == 0 -} - // Perm returns a pseudo-random permutation of n integers in [0, n). func (r *Rand) Perm(n int) []int { r.Lock() diff --git a/p2p/conn/secret_connection_test.go b/p2p/conn/secret_connection_test.go index a4045185e6..984a50d197 100644 --- a/p2p/conn/secret_connection_test.go +++ b/p2p/conn/secret_connection_test.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "log" + mrand "math/rand" "os" "path/filepath" "strconv" @@ -313,7 +314,7 @@ func createGoldenTestVectors(t *testing.T) string { randSecret := new([32]byte) copy((*randSecret)[:], randSecretVector) data += hex.EncodeToString((*randSecret)[:]) + "," - locIsLeast := tmrand.Bool() + locIsLeast := mrand.Int63()%2 == 0 data += strconv.FormatBool(locIsLeast) + "," recvSecret, sendSecret := deriveSecrets(randSecret, locIsLeast) data += hex.EncodeToString((*recvSecret)[:]) + "," From 781f6c8dc9be1aeeb0392aca7927f09aaf6e63ef Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 00:14:02 +0200 Subject: [PATCH 05/27] remove Time on Rand as well --- libs/rand/random.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index c04dc9c972..04c71a1c86 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -3,7 +3,6 @@ package rand import ( crand "crypto/rand" mrand "math/rand" - "time" tmsync "github.com/lazyledger/lazyledger-core/libs/sync" ) @@ -234,22 +233,6 @@ func (r *Rand) Float64() float64 { return f64 } -func (r *Rand) Time() time.Time { - return time.Unix(int64(r.Uint64()), 0) -} - -// Bytes returns n random bytes generated from the internal -// prng. -func (r *Rand) Bytes(n int) []byte { - // cRandBytes isn't guaranteed to be fast so instead - // use random bytes generated from the internal PRNG - bs := make([]byte, n) - for i := 0; i < len(bs); i++ { - bs[i] = byte(r.Int() & 0xFF) - } - return bs -} - // Intn returns, as an int, a uniform pseudo-random number in the range [0, n). // It panics if n <= 0. func (r *Rand) Intn(n int) int { From 59c145c124f7489ba4e3ab7a65d1d677a0bbbfa0 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 00:14:38 +0200 Subject: [PATCH 06/27] Use math/rand for Bytes() --- libs/rand/random.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index 04c71a1c86..0d3a7a3c97 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -106,7 +106,11 @@ func Float64() float64 { } func Bytes(n int) []byte { - return grand.Bytes(n) + bs := make([]byte, n) + for i := 0; i < len(bs); i++ { + bs[i] = byte(mrand.Int() & 0xFF) + } + return bs } func Intn(n int) int { From 9af911eae8d791db10d0bc09247960d8cc310f22 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 00:16:07 +0200 Subject: [PATCH 07/27] remove Float32 --- libs/rand/random.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index 0d3a7a3c97..f4b4dc4acc 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -97,10 +97,6 @@ func Int63n(n int64) int64 { return grand.Int63n(n) } -func Float32() float32 { - return grand.Float32() -} - func Float64() float64 { return grand.Float64() } @@ -223,13 +219,6 @@ func (r *Rand) Int63n(n int64) int64 { return i63n } -func (r *Rand) Float32() float32 { - r.Lock() - f32 := r.rand.Float32() - r.Unlock() - return f32 -} - func (r *Rand) Float64() float64 { r.Lock() f64 := r.rand.Float64() From 9b8bd0f3d5d4ffc534af7b7159d5f60d88af3ad2 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 01:42:43 +0200 Subject: [PATCH 08/27] Cleanup the remaining places --- abci/tests/server/client.go | 3 +- blockchain/v0/pool_test.go | 5 +- consensus/wal_generator.go | 6 +- libs/bits/bit_array.go | 22 ++- libs/clist/clist_test.go | 9 +- libs/rand/random.go | 242 +++-------------------------- libs/rand/random_test.go | 70 --------- libs/tempfile/tempfile_test.go | 5 +- libs/test/mutate.go | 8 +- p2p/conn/secret_connection_test.go | 8 +- p2p/pex/addrbook.go | 7 +- p2p/pex/addrbook_test.go | 15 +- p2p/pex/pex_reactor.go | 9 +- p2p/switch.go | 8 +- p2p/test_util.go | 9 +- rpc/jsonrpc/client/ws_client.go | 4 +- rpc/jsonrpc/jsonrpc_test.go | 7 +- state/state_test.go | 9 +- types/block_test.go | 12 +- types/event_bus_test.go | 9 +- types/tx_test.go | 3 +- types/validator.go | 4 +- 22 files changed, 113 insertions(+), 361 deletions(-) diff --git a/abci/tests/server/client.go b/abci/tests/server/client.go index db386d8d63..86df77eed2 100644 --- a/abci/tests/server/client.go +++ b/abci/tests/server/client.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + mrand "math/rand" abcicli "github.com/lazyledger/lazyledger-core/abci/client" "github.com/lazyledger/lazyledger-core/abci/types" @@ -18,7 +19,7 @@ func InitChain(client abcicli.Client) error { vals := make([]types.ValidatorUpdate, total) for i := 0; i < total; i++ { pubkey := tmrand.Bytes(33) - power := tmrand.Int() + power := mrand.Int() vals[i] = types.UpdateValidator(pubkey, int64(power), "") } _, err := client.InitChainSync(ctx, types.RequestInitChain{ diff --git a/blockchain/v0/pool_test.go b/blockchain/v0/pool_test.go index a79c9409dd..f50f8c6fb0 100644 --- a/blockchain/v0/pool_test.go +++ b/blockchain/v0/pool_test.go @@ -2,6 +2,7 @@ package v0 import ( "fmt" + mrand "math/rand" "testing" "time" @@ -45,7 +46,7 @@ func (p testPeer) simulateInput(input inputData) { input.pool.AddBlock(input.request.PeerID, block, 123) // TODO: uncommenting this creates a race which is detected by: // https://github.com/golang/go/blob/2bd767b1022dd3254bcec469f0ee164024726486/src/testing/testing.go#L854-L856 - // see: https://github.comlazyledger/lazyledger-cor/issues/3390#issue-418379890 + // see: https://github.com/tendermint/tendermint/issues/3390#issue-418379890 // input.t.Logf("Added block from peer %v (height: %v)", input.request.PeerID, input.request.Height) } @@ -67,7 +68,7 @@ func makePeers(numPeers int, minHeight, maxHeight int64) testPeers { peers := make(testPeers, numPeers) for i := 0; i < numPeers; i++ { peerID := p2p.ID(tmrand.Str(12)) - height := minHeight + tmrand.Int63n(maxHeight-minHeight) + height := minHeight + mrand.Int63n(maxHeight-minHeight) base := minHeight + int64(i) if base > height { base = height diff --git a/consensus/wal_generator.go b/consensus/wal_generator.go index 6ecbb2401d..1bae5e3d55 100644 --- a/consensus/wal_generator.go +++ b/consensus/wal_generator.go @@ -5,6 +5,7 @@ import ( "bytes" "fmt" "io" + mrand "math/rand" "path/filepath" "testing" "time" @@ -30,6 +31,7 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) { config := getConfig(t) app := kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), "wal_generator")) + t.Cleanup(func() { require.NoError(t, app.Close()) }) logger := log.TestingLogger().With("wal_generator", "wal_generator") logger.Info("generating WAL (last height msg excluded)", "numBlocks", numBlocks) @@ -88,7 +90,7 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) { consensusState := NewState(config.Consensus, state.Copy(), blockExec, blockStore, mempool, evpool) consensusState.SetLogger(logger) consensusState.SetEventBus(eventBus) - if privValidator != nil { + if privValidator != nil && privValidator != (*privval.FilePV)(nil) { consensusState.SetPrivValidator(privValidator) } // END OF COPY PASTE @@ -137,7 +139,7 @@ func WALWithNBlocks(t *testing.T, numBlocks int) (data []byte, err error) { func randPort() int { // returns between base and base + spread base, spread := 20000, 20000 - return base + tmrand.Intn(spread) + return base + mrand.Intn(spread) } func makeAddrs() (string, string, string) { diff --git a/libs/bits/bit_array.go b/libs/bits/bit_array.go index bfc298de96..c6ed4af1bf 100644 --- a/libs/bits/bit_array.go +++ b/libs/bits/bit_array.go @@ -5,12 +5,12 @@ import ( "errors" "fmt" "math" + mrand "math/rand" "regexp" "strings" "sync" tmmath "github.com/lazyledger/lazyledger-core/libs/math" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" tmprotobits "github.com/lazyledger/lazyledger-core/proto/tendermint/libs/bits" ) @@ -256,7 +256,7 @@ func (bA *BitArray) PickRandom() (int, bool) { return 0, false } - return trueIndices[tmrand.Intn(len(trueIndices))], true + return trueIndices[mrand.Intn(len(trueIndices))], true } func (bA *BitArray) getTrueIndices() []int { @@ -422,21 +422,21 @@ func (bA *BitArray) UnmarshalJSON(bz []byte) error { // ToProto converts BitArray to protobuf. It returns nil if BitArray is // nil/empty. -// -// XXX: It does not copy the array. func (bA *BitArray) ToProto() *tmprotobits.BitArray { if bA == nil || (len(bA.Elems) == 0 && bA.Bits == 0) { // empty return nil } - return &tmprotobits.BitArray{Bits: int64(bA.Bits), Elems: bA.Elems} + bA.mtx.Lock() + defer bA.mtx.Unlock() + + bc := bA.copy() + return &tmprotobits.BitArray{Bits: int64(bc.Bits), Elems: bc.Elems} } // FromProto sets BitArray to the given protoBitArray. It returns an error if // protoBitArray is invalid. -// -// XXX: It does not copy the array. func (bA *BitArray) FromProto(protoBitArray *tmprotobits.BitArray) error { if protoBitArray == nil { return nil @@ -454,8 +454,14 @@ func (bA *BitArray) FromProto(protoBitArray *tmprotobits.BitArray) error { return fmt.Errorf("invalid number of Elems: got %d, but exp %d", got, exp) } + bA.mtx.Lock() + defer bA.mtx.Unlock() + + ec := make([]uint64, len(protoBitArray.Elems)) + copy(ec, protoBitArray.Elems) + bA.Bits = int(protoBitArray.Bits) - bA.Elems = protoBitArray.Elems + bA.Elems = ec return nil } diff --git a/libs/clist/clist_test.go b/libs/clist/clist_test.go index 5a1ac0753b..aa5142a382 100644 --- a/libs/clist/clist_test.go +++ b/libs/clist/clist_test.go @@ -2,14 +2,13 @@ package clist import ( "fmt" + mrand "math/rand" "runtime" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" - - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" ) func TestPanicOnMaxLength(t *testing.T) { @@ -148,7 +147,7 @@ func _TestGCRandom(t *testing.T) { els = append(els, el) } - for _, i := range tmrand.Perm(numElements) { + for _, i := range mrand.Perm(numElements) { el := els[i] l.Remove(el) _ = el.Next() @@ -206,7 +205,7 @@ func TestScanRightDeleteRandom(t *testing.T) { // Remove an element, push back an element. for i := 0; i < numTimes; i++ { // Pick an element to remove - rmElIdx := tmrand.Intn(len(els)) + rmElIdx := mrand.Intn(len(els)) rmEl := els[rmElIdx] // Remove it @@ -260,7 +259,7 @@ func TestWaitChan(t *testing.T) { for i := 1; i < 100; i++ { l.PushBack(i) pushed++ - time.Sleep(time.Duration(tmrand.Intn(25)) * time.Millisecond) + time.Sleep(time.Duration(mrand.Intn(25)) * time.Millisecond) } // apply a deterministic pause so the counter has time to catch up time.Sleep(25 * time.Millisecond) diff --git a/libs/rand/random.go b/libs/rand/random.go index f4b4dc4acc..e1d51e6c45 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -2,140 +2,37 @@ package rand import ( crand "crypto/rand" + "encoding/binary" mrand "math/rand" - - tmsync "github.com/lazyledger/lazyledger-core/libs/sync" ) const ( strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters ) -// Rand is a prng, that is seeded with OS randomness. -// The OS randomness is obtained from crypto/rand, however none of the provided -// methods are suitable for cryptographic usage. -// They all utilize math/rand's prng internally. +// NewRand returns a prng, that is seeded with OS randomness. +// The OS randomness is obtained from crypto/rand, however, like with any math/rand.Rand +// object none of the provided methods are suitable for cryptographic usage. // -// All of the methods here are suitable for concurrent use. -// This is achieved by using a mutex lock on all of the provided methods. -type Rand struct { - tmsync.Mutex - rand *mrand.Rand -} - -var grand *Rand - -func init() { - grand = NewRand() - grand.init() -} - -func NewRand() *Rand { - rand := &Rand{} - rand.init() - return rand -} - -func (r *Rand) init() { - bz := cRandBytes(8) - var seed uint64 - for i := 0; i < 8; i++ { - seed |= uint64(bz[i]) - seed <<= 8 - } - r.reset(int64(seed)) -} - -func (r *Rand) reset(seed int64) { - r.rand = mrand.New(mrand.NewSource(seed)) // nolint:gosec // G404: Use of weak random number generator -} - -//---------------------------------------- -// Global functions - -func Seed(seed int64) { - grand.Seed(seed) +// As this returns a math/rand.Rand instance all methods on +// that object are suitable for concurrent use. +func NewRand() *mrand.Rand { + var seed int64 + binary.Read(crand.Reader, binary.BigEndian, &seed) + return mrand.New(mrand.NewSource(seed)) } +// Str constructs a random alphanumeric string of given length +// from a freshly instantiated prng. func Str(length int) string { - return grand.Str(length) -} - -func Uint32() uint32 { - return grand.Uint32() -} - -func Uint64() uint64 { - return grand.Uint64() -} - -func Int32() int32 { - return grand.Int32() -} - -func Int64() int64 { - return grand.Int64() -} - -func Int() int { - return grand.Int() -} - -func Int31() int32 { - return grand.Int31() -} - -func Int31n(n int32) int32 { - return grand.Int31n(n) -} - -func Int63() int64 { - return grand.Int63() -} - -func Int63n(n int64) int64 { - return grand.Int63n(n) -} - -func Float64() float64 { - return grand.Float64() -} - -func Bytes(n int) []byte { - bs := make([]byte, n) - for i := 0; i < len(bs); i++ { - bs[i] = byte(mrand.Int() & 0xFF) - } - return bs -} - -func Intn(n int) int { - return grand.Intn(n) -} - -func Perm(n int) []int { - return grand.Perm(n) -} - -//---------------------------------------- -// Rand methods - -func (r *Rand) Seed(seed int64) { - r.Lock() - r.reset(seed) - r.Unlock() -} - -// Str constructs a random alphanumeric string of given length. -func (r *Rand) Str(length int) string { + rand := NewRand() if length <= 0 { return "" } - chars := []byte{} -MAIN_LOOP: + chars := make([]byte, 0, length) for { - val := r.Int63() + val := rand.Int63() for i := 0; i < 10; i++ { v := int(val & 0x3f) // rightmost 6 bits if v >= 62 { // only 62 characters in strChars @@ -144,113 +41,20 @@ MAIN_LOOP: } else { chars = append(chars, strChars[v]) if len(chars) == length { - break MAIN_LOOP + return string(chars) } val >>= 6 } } } - - return string(chars) -} - -func (r *Rand) Uint16() uint16 { - return uint16(r.Uint32() & (1<<16 - 1)) -} - -func (r *Rand) Uint32() uint32 { - r.Lock() - u32 := r.rand.Uint32() - r.Unlock() - return u32 -} - -func (r *Rand) Uint64() uint64 { - return uint64(r.Uint32())<<32 + uint64(r.Uint32()) -} - -func (r *Rand) Uint() uint { - r.Lock() - i := r.rand.Int() - r.Unlock() - return uint(i) -} - -func (r *Rand) Int32() int32 { - return int32(r.Uint32()) -} - -func (r *Rand) Int64() int64 { - return int64(r.Uint64()) } -func (r *Rand) Int() int { - r.Lock() - i := r.rand.Int() - r.Unlock() - return i -} - -func (r *Rand) Int31() int32 { - r.Lock() - i31 := r.rand.Int31() - r.Unlock() - return i31 -} - -func (r *Rand) Int31n(n int32) int32 { - r.Lock() - i31n := r.rand.Int31n(n) - r.Unlock() - return i31n -} - -func (r *Rand) Int63() int64 { - r.Lock() - i63 := r.rand.Int63() - r.Unlock() - return i63 -} - -func (r *Rand) Int63n(n int64) int64 { - r.Lock() - i63n := r.rand.Int63n(n) - r.Unlock() - return i63n -} - -func (r *Rand) Float64() float64 { - r.Lock() - f64 := r.rand.Float64() - r.Unlock() - return f64 -} - -// Intn returns, as an int, a uniform pseudo-random number in the range [0, n). -// It panics if n <= 0. -func (r *Rand) Intn(n int) int { - r.Lock() - i := r.rand.Intn(n) - r.Unlock() - return i -} - -// Perm returns a pseudo-random permutation of n integers in [0, n). -func (r *Rand) Perm(n int) []int { - r.Lock() - perm := r.rand.Perm(n) - r.Unlock() - return perm -} - -// NOTE: This relies on the os's random number generator. -// For real security, we should salt that with some seed. -// See github.com/lazyledger/lazyledger-core/crypto for a more secure reader. -func cRandBytes(numBytes int) []byte { - b := make([]byte, numBytes) - _, err := crand.Read(b) - if err != nil { - panic(err) +// Bytes returns n random bytes generated from a freshly instantiated prng. +func Bytes(n int) []byte { + rand := NewRand() + bs := make([]byte, n) + for i := 0; i < len(bs); i++ { + bs[i] = byte(rand.Int() & 0xFF) } - return b + return bs } diff --git a/libs/rand/random_test.go b/libs/rand/random_test.go index 3153c968a9..6dfb6b4413 100644 --- a/libs/rand/random_test.go +++ b/libs/rand/random_test.go @@ -1,13 +1,7 @@ package rand import ( - "bytes" - "encoding/json" - "fmt" - mrand "math/rand" - "sync" "testing" - "time" "github.com/stretchr/testify/assert" ) @@ -24,70 +18,6 @@ func TestRandBytes(t *testing.T) { assert.Equal(t, l, len(b)) } -func TestRandIntn(t *testing.T) { - n := 243 - for i := 0; i < 100; i++ { - x := Intn(n) - assert.True(t, x < n) - } -} - -// Test to make sure that we never call math.rand(). -// We do this by ensuring that outputs are deterministic. -func TestDeterminism(t *testing.T) { - var firstOutput string - - // Set math/rand's seed for the sake of debugging this test. - // (It isn't strictly necessary). - mrand.Seed(1) - - for i := 0; i < 100; i++ { - output := testThemAll() - if i == 0 { - firstOutput = output - } else if firstOutput != output { - t.Errorf("run #%d's output was different from first run.\nfirst: %v\nlast: %v", - i, firstOutput, output) - } - } -} - -func testThemAll() string { - - // Such determinism. - grand.reset(1) - - // Use it. - out := new(bytes.Buffer) - perm := Perm(10) - blob, _ := json.Marshal(perm) - fmt.Fprintf(out, "perm: %s\n", blob) - fmt.Fprintf(out, "randInt: %d\n", Int()) - fmt.Fprintf(out, "randIntn: %d\n", Intn(97)) - fmt.Fprintf(out, "randInt31: %d\n", Int31()) - fmt.Fprintf(out, "randInt32: %d\n", Int32()) - fmt.Fprintf(out, "randInt63: %d\n", Int63()) - fmt.Fprintf(out, "randInt64: %d\n", Int64()) - fmt.Fprintf(out, "randUint32: %d\n", Uint32()) - fmt.Fprintf(out, "randUint64: %d\n", Uint64()) - return out.String() -} - -func TestRngConcurrencySafety(t *testing.T) { - var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() - - _ = Uint64() - <-time.After(time.Millisecond * time.Duration(Intn(100))) - _ = Perm(3) - }() - } - wg.Wait() -} - func BenchmarkRandBytes10B(b *testing.B) { benchmarkRandBytes(b, 10) } diff --git a/libs/tempfile/tempfile_test.go b/libs/tempfile/tempfile_test.go index 747eef52df..7b020461c9 100644 --- a/libs/tempfile/tempfile_test.go +++ b/libs/tempfile/tempfile_test.go @@ -6,6 +6,7 @@ import ( "bytes" "fmt" "io/ioutil" + mrand "math/rand" "os" testing "testing" @@ -16,8 +17,8 @@ import ( func TestWriteFileAtomic(t *testing.T) { var ( - data = []byte(tmrand.Str(tmrand.Intn(2048))) - old = tmrand.Bytes(tmrand.Intn(2048)) + data = []byte(tmrand.Str(mrand.Intn(2048))) + old = tmrand.Bytes(mrand.Intn(2048)) perm os.FileMode = 0600 ) diff --git a/libs/test/mutate.go b/libs/test/mutate.go index 294e425bfa..9d2b6e821c 100644 --- a/libs/test/mutate.go +++ b/libs/test/mutate.go @@ -1,7 +1,7 @@ package test import ( - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" + mrand "math/rand" ) // Contract: !bytes.Equal(input, output) && len(input) >= len(output) @@ -17,11 +17,11 @@ func MutateByteSlice(bytez []byte) []byte { bytez = mBytez // Try a random mutation - switch tmrand.Int() % 2 { + switch mrand.Int() % 2 { case 0: // Mutate a single byte - bytez[tmrand.Int()%len(bytez)] += byte(tmrand.Int()%255 + 1) + bytez[mrand.Int()%len(bytez)] += byte(mrand.Int()%255 + 1) case 1: // Remove an arbitrary byte - pos := tmrand.Int() % len(bytez) + pos := mrand.Int() % len(bytez) bytez = append(bytez[:pos], bytez[pos+1:]...) } return bytez diff --git a/p2p/conn/secret_connection_test.go b/p2p/conn/secret_connection_test.go index 984a50d197..8154591d3d 100644 --- a/p2p/conn/secret_connection_test.go +++ b/p2p/conn/secret_connection_test.go @@ -115,8 +115,8 @@ func TestSecretConnectionReadWrite(t *testing.T) { // Pre-generate the things to write (for foo & bar) for i := 0; i < 100; i++ { - fooWrites = append(fooWrites, tmrand.Str((tmrand.Int()%(dataMaxSize*5))+1)) - barWrites = append(barWrites, tmrand.Str((tmrand.Int()%(dataMaxSize*5))+1)) + fooWrites = append(fooWrites, tmrand.Str((mrand.Int()%(dataMaxSize*5))+1)) + barWrites = append(barWrites, tmrand.Str((mrand.Int()%(dataMaxSize*5))+1)) } // A helper that will run with (fooConn, fooWrites, fooReads) and vice versa @@ -414,7 +414,7 @@ func BenchmarkWriteSecretConnection(b *testing.B) { b.StartTimer() for i := 0; i < b.N; i++ { - idx := tmrand.Intn(len(fooWriteBytes)) + idx := mrand.Intn(len(fooWriteBytes)) _, err := fooSecConn.Write(fooWriteBytes[idx]) if err != nil { b.Errorf("failed to write to fooSecConn: %v", err) @@ -448,7 +448,7 @@ func BenchmarkReadSecretConnection(b *testing.B) { } go func() { for i := 0; i < b.N; i++ { - idx := tmrand.Intn(len(fooWriteBytes)) + idx := mrand.Intn(len(fooWriteBytes)) _, err := fooSecConn.Write(fooWriteBytes[idx]) if err != nil { b.Errorf("failed to write to fooSecConn: %v, %v,%v", err, i, b.N) diff --git a/p2p/pex/addrbook.go b/p2p/pex/addrbook.go index 10101a9060..452698d7a0 100644 --- a/p2p/pex/addrbook.go +++ b/p2p/pex/addrbook.go @@ -9,7 +9,7 @@ import ( "encoding/binary" "fmt" "math" - "math/rand" + mrand "math/rand" "net" "sync" "time" @@ -89,7 +89,7 @@ type addrBook struct { // accessed concurrently mtx tmsync.Mutex - rand *tmrand.Rand + rand *mrand.Rand ourAddrs map[string]struct{} privateIDs map[p2p.ID]struct{} addrLookup map[p2p.ID]*knownAddress // new & old @@ -417,7 +417,7 @@ func (a *addrBook) GetSelection() []*p2p.NetAddress { // `numAddresses' since we are throwing the rest. for i := 0; i < numAddresses; i++ { // pick a number between current index and the end - j := tmrand.Intn(len(allAddr)-i) + i + j := mrand.Intn(len(allAddr)-i) + i allAddr[i], allAddr[j] = allAddr[j], allAddr[i] } @@ -717,6 +717,7 @@ func (a *addrBook) randomPickAddresses(bucketType byte, num int) []*p2p.NetAddre } selection := make([]*p2p.NetAddress, 0, num) chosenSet := make(map[string]bool, num) + rand := tmrand.NewRand() rand.Shuffle(total, func(i, j int) { addresses[i], addresses[j] = addresses[j], addresses[i] }) diff --git a/p2p/pex/addrbook_test.go b/p2p/pex/addrbook_test.go index 0c772039ac..1c0804b00e 100644 --- a/p2p/pex/addrbook_test.go +++ b/p2p/pex/addrbook_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "math" + mrand "math/rand" "net" "os" "testing" @@ -187,12 +188,12 @@ func randNetAddressPairs(t *testing.T, n int) []netAddressPair { func randIPv4Address(t *testing.T) *p2p.NetAddress { for { ip := fmt.Sprintf("%v.%v.%v.%v", - tmrand.Intn(254)+1, - tmrand.Intn(255), - tmrand.Intn(255), - tmrand.Intn(255), + mrand.Intn(254)+1, + mrand.Intn(255), + mrand.Intn(255), + mrand.Intn(255), ) - port := tmrand.Intn(65535-1) + 1 + port := mrand.Intn(65535-1) + 1 id := p2p.ID(hex.EncodeToString(tmrand.Bytes(p2p.IDByteLength))) idAddr := p2p.IDAddressString(id, fmt.Sprintf("%v:%v", ip, port)) addr, err := p2p.NewNetAddressString(idAddr) @@ -554,7 +555,7 @@ func TestMultipleAddrBookAddressSelection(t *testing.T) { ranges := [...][]int{{33, 100}, {100, 175}} bookSizes := make([]int, 0, len(ranges)) for _, r := range ranges { - bookSizes = append(bookSizes, tmrand.Intn(r[1]-r[0])+r[0]) + bookSizes = append(bookSizes, mrand.Intn(r[1]-r[0])+r[0]) } t.Logf("Testing address selection for the following book sizes %v\n", bookSizes) for _, bookSize := range bookSizes { @@ -741,7 +742,7 @@ func countOldAndNewAddrsInSelection(addrs []*p2p.NetAddress, book *addrBook) (nO return } -// Analyse the layout of the selection specified by 'addrs' +// Analyze the layout of the selection specified by 'addrs' // Returns: // - seqLens - the lengths of the sequences of addresses of same type // - seqTypes - the types of sequences in selection diff --git a/p2p/pex/pex_reactor.go b/p2p/pex/pex_reactor.go index 8a0bb40557..ab28b4fdeb 100644 --- a/p2p/pex/pex_reactor.go +++ b/p2p/pex/pex_reactor.go @@ -523,7 +523,8 @@ func (r *Reactor) ensurePeers() { peers := r.Switch.Peers().List() peersCount := len(peers) if peersCount > 0 { - peer := peers[tmrand.Int()%peersCount] + rand := tmrand.NewRand() + peer := peers[rand.Int()%peersCount] r.Logger.Info("We need more addresses. Sending pexRequest to random peer", "peer", peer) r.RequestAddrs(peer) } @@ -556,7 +557,8 @@ func (r *Reactor) dialPeer(addr *p2p.NetAddress) error { // exponential backoff if it's not our first attempt to dial given address if attempts > 0 { - jitter := time.Duration(tmrand.Float64() * float64(time.Second)) // 1s == (1e9 ns) + rand := tmrand.NewRand() + jitter := time.Duration(rand.Float64() * float64(time.Second)) // 1s == (1e9 ns) backoffDuration := jitter + ((1 << uint(attempts)) * time.Second) backoffDuration = r.maxBackoffDurationForPeer(addr, backoffDuration) sinceLastDialed := time.Since(lastDialed) @@ -622,7 +624,8 @@ func (r *Reactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, err e // randomly dial seeds until we connect to one or exhaust them func (r *Reactor) dialSeeds() { - perm := tmrand.Perm(len(r.seedAddrs)) + rand := tmrand.NewRand() + perm := rand.Perm(len(r.seedAddrs)) // perm := r.Switch.rng.Perm(lSeeds) for _, i := range perm { // dial a random seed diff --git a/p2p/switch.go b/p2p/switch.go index fa84925aff..a22cb182b9 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -3,12 +3,14 @@ package p2p import ( "fmt" "math" + mrand "math/rand" + "net" "sync" "time" "github.com/lazyledger/lazyledger-core/config" "github.com/lazyledger/lazyledger-core/libs/cmap" - "github.com/lazyledger/lazyledger-core/libs/rand" + tmrand "github.com/lazyledger/lazyledger-core/libs/rand" "github.com/lazyledger/lazyledger-core/libs/service" "github.com/lazyledger/lazyledger-core/p2p/conn" ) @@ -87,7 +89,7 @@ type Switch struct { filterTimeout time.Duration peerFilters []PeerFilterFunc - rng *rand.Rand // seed for randomizing dial times and orders + rng *mrand.Rand // seed for randomizing dial times and orders metrics *Metrics } @@ -123,7 +125,7 @@ func NewSwitch( } // Ensure we have a completely undeterministic PRNG. - sw.rng = rand.NewRand() + sw.rng = tmrand.NewRand() sw.BaseService = *service.NewBaseService(nil, "P2P Switch", sw) diff --git a/p2p/test_util.go b/p2p/test_util.go index 50f4710152..293e00fa57 100644 --- a/p2p/test_util.go +++ b/p2p/test_util.go @@ -2,6 +2,7 @@ package p2p import ( "fmt" + mrand "math/rand" "net" "time" @@ -51,10 +52,10 @@ func CreateRoutableAddr() (addr string, netAddr *NetAddress) { var err error addr = fmt.Sprintf("%X@%v.%v.%v.%v:26656", tmrand.Bytes(20), - tmrand.Int()%256, - tmrand.Int()%256, - tmrand.Int()%256, - tmrand.Int()%256) + mrand.Int()%256, + mrand.Int()%256, + mrand.Int()%256, + mrand.Int()%256) netAddr, err = NewNetAddressString(addr) if err != nil { panic(err) diff --git a/rpc/jsonrpc/client/ws_client.go b/rpc/jsonrpc/client/ws_client.go index 9225a53fb2..ca9c6fdcb9 100644 --- a/rpc/jsonrpc/client/ws_client.go +++ b/rpc/jsonrpc/client/ws_client.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + mrand "math/rand" "net" "net/http" "sync" @@ -12,7 +13,6 @@ import ( "github.com/gorilla/websocket" metrics "github.com/rcrowley/go-metrics" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" "github.com/lazyledger/lazyledger-core/libs/service" tmsync "github.com/lazyledger/lazyledger-core/libs/sync" types "github.com/lazyledger/lazyledger-core/rpc/jsonrpc/types" @@ -287,7 +287,7 @@ func (c *WSClient) reconnect() error { }() for { - jitter := time.Duration(tmrand.Float64() * float64(time.Second)) // 1s == (1e9 ns) + jitter := time.Duration(mrand.Float64() * float64(time.Second)) // 1s == (1e9 ns) backoffDuration := jitter + ((1 << uint(attempt)) * time.Second) c.Logger.Info("reconnecting", "attempt", attempt+1, "backoff_duration", backoffDuration) diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index 9137d75f66..7879bd833a 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -6,6 +6,7 @@ import ( crand "crypto/rand" "encoding/json" "fmt" + mrand "math/rand" "net/http" "os" "os/exec" @@ -18,8 +19,6 @@ import ( tmbytes "github.com/lazyledger/lazyledger-core/libs/bytes" "github.com/lazyledger/lazyledger-core/libs/log" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" - client "github.com/lazyledger/lazyledger-core/rpc/jsonrpc/client" server "github.com/lazyledger/lazyledger-core/rpc/jsonrpc/server" types "github.com/lazyledger/lazyledger-core/rpc/jsonrpc/types" @@ -215,7 +214,7 @@ func testWithHTTPClient(t *testing.T, cl client.HTTPClient) { require.Nil(t, err) assert.Equal(t, got3, val3) - val4 := tmrand.Intn(10000) + val4 := mrand.Intn(10000) got4, err := echoIntViaHTTP(cl, val4) require.Nil(t, err) assert.Equal(t, got4, val4) @@ -400,7 +399,7 @@ func TestWSClientPingPong(t *testing.T) { } func randBytes(t *testing.T) []byte { - n := tmrand.Intn(10) + 2 + n := mrand.Intn(10) + 2 buf := make([]byte, n) _, err := crand.Read(buf) require.Nil(t, err) diff --git a/state/state_test.go b/state/state_test.go index d78ec1ef34..1ce40fa88e 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "math/big" + mrand "math/rand" "os" "testing" @@ -355,18 +356,18 @@ func TestProposerFrequency(t *testing.T) { maxPower := 1000 nTestCases := 5 for i := 0; i < nTestCases; i++ { - N := tmrand.Int()%maxVals + 1 + N := mrand.Int()%maxVals + 1 vals := make([]*types.Validator, N) totalVotePower := int64(0) for j := 0; j < N; j++ { // make sure votePower > 0 - votePower := int64(tmrand.Int()%maxPower) + 1 + votePower := int64(mrand.Int()%maxPower) + 1 totalVotePower += votePower privVal := types.NewMockPV() pubKey, err := privVal.GetPubKey() require.NoError(t, err) val := types.NewValidator(pubKey, votePower) - val.ProposerPriority = tmrand.Int64() + val.ProposerPriority = mrand.Int63() vals[j] = val } valSet := types.NewValidatorSet(vals) @@ -383,7 +384,7 @@ func genValSetWithPowers(powers []int64) *types.ValidatorSet { for i := 0; i < size; i++ { totalVotePower += powers[i] val := types.NewValidator(ed25519.GenPrivKey().PubKey(), powers[i]) - val.ProposerPriority = tmrand.Int64() + val.ProposerPriority = mrand.Int63() vals[i] = val } valSet := types.NewValidatorSet(vals) diff --git a/types/block_test.go b/types/block_test.go index 47ca19419b..9c25874033 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -7,7 +7,7 @@ import ( "context" "encoding/hex" "math" - "math/rand" + mrand "math/rand" "os" "reflect" "sort" @@ -194,8 +194,8 @@ func makeBlockIDRandom() BlockID { blockHash = make([]byte, tmhash.Size) partSetHash = make([]byte, tmhash.Size) ) - rand.Read(blockHash) - rand.Read(partSetHash) + rand.Read(blockHash) //nolint: errcheck // ignore errcheck for read + rand.Read(partSetHash) //nolint: errcheck // ignore errcheck for read return BlockID{blockHash, PartSetHeader{123, partSetHash}} } @@ -661,7 +661,7 @@ func TestBlockIDValidateBasic(t *testing.T) { } func TestBlockProtoBuf(t *testing.T) { - h := tmrand.Int63() + h := mrand.Int63() c1 := randCommit(time.Now()) b1 := MakeBlock(h, []Tx{Tx([]byte{1})}, []Evidence{}, nil, Messages{}, &Commit{Signatures: []CommitSig{}}) b1.ProposerAddress = tmrand.Bytes(crypto.AddressSize) @@ -698,7 +698,7 @@ func TestBlockProtoBuf(t *testing.T) { if tc.expPass2 { require.NoError(t, err, tc.msg) require.EqualValues(t, tc.b1.Header, block.Header, tc.msg) - // require.EqualValues(t, tc.b1.Data, block.Data, tc.msg) + require.EqualValues(t, tc.b1.Data, block.Data, tc.msg) require.EqualValues(t, tc.b1.Evidence.Evidence, block.Evidence.Evidence, tc.msg) require.EqualValues(t, *tc.b1.LastCommit, *block.LastCommit, tc.msg) } else { @@ -769,7 +769,7 @@ func TestEvidenceDataProtoBuf(t *testing.T) { func makeRandHeader() Header { chainID := "test" t := time.Now() - height := tmrand.Int63() + height := mrand.Int63() randBytes := tmrand.Bytes(tmhash.Size) randAddress := tmrand.Bytes(crypto.AddressSize) h := Header{ diff --git a/types/event_bus_test.go b/types/event_bus_test.go index 499f3e06e4..f05c828b56 100644 --- a/types/event_bus_test.go +++ b/types/event_bus_test.go @@ -3,7 +3,7 @@ package types import ( "context" "fmt" - "math/rand" + mrand "math/rand" "testing" "time" @@ -13,7 +13,6 @@ import ( abci "github.com/lazyledger/lazyledger-core/abci/types" tmpubsub "github.com/lazyledger/lazyledger-core/libs/pubsub" tmquery "github.com/lazyledger/lazyledger-core/libs/pubsub/query" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" ) func TestEventBusPublishEventTx(t *testing.T) { @@ -410,7 +409,7 @@ func BenchmarkEventBus(b *testing.B) { func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *testing.B) { // for random* functions - rand.Seed(time.Now().Unix()) + mrand.Seed(time.Now().Unix()) eventBus := NewEventBusWithBufferCapacity(0) // set buffer capacity to 0 so we are not testing cache err := eventBus.Start() @@ -476,7 +475,7 @@ var events = []string{ EventVote} func randEvent() string { - return events[tmrand.Intn(len(events))] + return events[mrand.Intn(len(events))] } var queries = []tmpubsub.Query{ @@ -494,5 +493,5 @@ var queries = []tmpubsub.Query{ EventQueryVote} func randQuery() tmpubsub.Query { - return queries[tmrand.Intn(len(queries))] + return queries[mrand.Intn(len(queries))] } diff --git a/types/tx_test.go b/types/tx_test.go index 37596022c3..91d81b64d4 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -2,6 +2,7 @@ package types import ( "bytes" + mrand "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -21,7 +22,7 @@ func makeTxs(cnt, size int) Txs { } func randInt(low, high int) int { - off := tmrand.Int() % (high - low) + off := mrand.Int() % (high - low) return low + off } diff --git a/types/validator.go b/types/validator.go index 0a343d1e04..e0cbc3440d 100644 --- a/types/validator.go +++ b/types/validator.go @@ -4,11 +4,11 @@ import ( "bytes" "errors" "fmt" + mrand "math/rand" "strings" "github.com/lazyledger/lazyledger-core/crypto" ce "github.com/lazyledger/lazyledger-core/crypto/encoding" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types" ) @@ -182,7 +182,7 @@ func RandValidator(randPower bool, minPower int64) (*Validator, PrivValidator) { privVal := NewMockPV() votePower := minPower if randPower { - votePower += int64(tmrand.Uint32()) + votePower += int64(mrand.Uint32()) } pubKey, err := privVal.GetPubKey() if err != nil { From 48333149bb6c53eeb264b10ad9cbf089f23e0d89 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 02:42:57 +0200 Subject: [PATCH 09/27] Review feedback: add clarifying comment Co-authored-by: Dev Ojha --- abci/example/kvstore/helpers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/abci/example/kvstore/helpers.go b/abci/example/kvstore/helpers.go index bb4bb205d6..9b65ad92db 100644 --- a/abci/example/kvstore/helpers.go +++ b/abci/example/kvstore/helpers.go @@ -11,6 +11,7 @@ import ( // from the input value func RandVal(i int) types.ValidatorUpdate { pubkey := tmrand.Bytes(32) + // Random value between [0, 2^16 - 1] power := mrand.Uint32() & (1<<16 - 1) v := types.UpdateValidator(pubkey, int64(power), "") return v From 66e4710c964cc334e230757c02f7a9bd558f1353 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:03:42 +0200 Subject: [PATCH 10/27] Add clarifying comment that NewRand isn't safe for concurrent use --- libs/rand/random.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index e1d51e6c45..48a4f9b2eb 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -14,25 +14,26 @@ const ( // The OS randomness is obtained from crypto/rand, however, like with any math/rand.Rand // object none of the provided methods are suitable for cryptographic usage. // -// As this returns a math/rand.Rand instance all methods on -// that object are suitable for concurrent use. +// Note that the returned instance of math/rand's Rand is not +// suitable for concurrent use by multiple goroutines. +// +// For concurrent use, call Reseed to reseed math/rand's default source and +// use math/rand's top-level convenience functions instead. func NewRand() *mrand.Rand { - var seed int64 - binary.Read(crand.Reader, binary.BigEndian, &seed) + seed := crandSeed() return mrand.New(mrand.NewSource(seed)) } // Str constructs a random alphanumeric string of given length // from a freshly instantiated prng. func Str(length int) string { - rand := NewRand() if length <= 0 { return "" } chars := make([]byte, 0, length) for { - val := rand.Int63() + val := mrand.Int63() for i := 0; i < 10; i++ { v := int(val & 0x3f) // rightmost 6 bits if v >= 62 { // only 62 characters in strChars @@ -51,10 +52,15 @@ func Str(length int) string { // Bytes returns n random bytes generated from a freshly instantiated prng. func Bytes(n int) []byte { - rand := NewRand() bs := make([]byte, n) for i := 0; i < len(bs); i++ { - bs[i] = byte(rand.Int() & 0xFF) + bs[i] = byte(mrand.Int() & 0xFF) } return bs } + +func crandSeed() int64 { + var seed int64 + binary.Read(crand.Reader, binary.BigEndian, &seed) + return seed +} From e6c824e4c46400da2231b119fcddb6e7297194fb Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:05:18 +0200 Subject: [PATCH 11/27] Add Reseed method as a convenient way to reseed math/rand's default Source --- libs/rand/random.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libs/rand/random.go b/libs/rand/random.go index 48a4f9b2eb..b82ac50d20 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -10,6 +10,10 @@ const ( strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters ) +func init() { + Reseed() +} + // NewRand returns a prng, that is seeded with OS randomness. // The OS randomness is obtained from crypto/rand, however, like with any math/rand.Rand // object none of the provided methods are suitable for cryptographic usage. @@ -24,6 +28,18 @@ func NewRand() *mrand.Rand { return mrand.New(mrand.NewSource(seed)) } +// Reseed conveniently re-seeds the default Source of math/rand with +// randomness obtained from crypto/rand. +// +// Note that this does not make math/rand suitable for cryptographic usage. +// +// Use math/rand's top-level convenience functions remain suitable +// for concurrent use by multiple goroutines. +func Reseed() { + seed := crandSeed() + mrand.Seed(seed) +} + // Str constructs a random alphanumeric string of given length // from a freshly instantiated prng. func Str(length int) string { From ee49c68359b25bdee590142a610fe2143b43f8a0 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:07:25 +0200 Subject: [PATCH 12/27] Use math/rand's thread-safe Source in pex instead --- p2p/pex/addrbook.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/p2p/pex/addrbook.go b/p2p/pex/addrbook.go index 452698d7a0..6c7cd97e68 100644 --- a/p2p/pex/addrbook.go +++ b/p2p/pex/addrbook.go @@ -89,7 +89,6 @@ type addrBook struct { // accessed concurrently mtx tmsync.Mutex - rand *mrand.Rand ourAddrs map[string]struct{} privateIDs map[p2p.ID]struct{} addrLookup map[p2p.ID]*knownAddress // new & old @@ -118,7 +117,6 @@ func newHashKey() []byte { // Use Start to begin processing asynchronous address updates. func NewAddrBook(filePath string, routabilityStrict bool) AddrBook { am := &addrBook{ - rand: tmrand.NewRand(), ourAddrs: make(map[string]struct{}), privateIDs: make(map[p2p.ID]struct{}), addrLookup: make(map[p2p.ID]*knownAddress), @@ -292,7 +290,7 @@ func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress { // pick a random peer from a random bucket var bucket map[string]*knownAddress - pickFromOldBucket := (newCorrelation+oldCorrelation)*a.rand.Float64() < oldCorrelation + pickFromOldBucket := (newCorrelation+oldCorrelation)*mrand.Float64() < oldCorrelation if (pickFromOldBucket && a.nOld == 0) || (!pickFromOldBucket && a.nNew == 0) { return nil @@ -300,13 +298,13 @@ func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress { // loop until we pick a random non-empty bucket for len(bucket) == 0 { if pickFromOldBucket { - bucket = a.bucketsOld[a.rand.Intn(len(a.bucketsOld))] + bucket = a.bucketsOld[mrand.Intn(len(a.bucketsOld))] } else { - bucket = a.bucketsNew[a.rand.Intn(len(a.bucketsNew))] + bucket = a.bucketsNew[mrand.Intn(len(a.bucketsNew))] } } // pick a random index and loop over the map to return that index - randIndex := a.rand.Intn(len(bucket)) + randIndex := mrand.Intn(len(bucket)) for _, ka := range bucket { if randIndex == 0 { return ka.Addr @@ -681,7 +679,7 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error { } // The more entries we have, the less likely we are to add more. factor := int32(2 * len(ka.Buckets)) - if a.rand.Int31n(factor) != 0 { + if mrand.Int31n(factor) != 0 { return nil } } else { From 63823dfe7baa50190e5219080baeac7a782f8062 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:07:43 +0200 Subject: [PATCH 13/27] Reseed math/rand's source for p2p.Switch --- p2p/switch.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/p2p/switch.go b/p2p/switch.go index a22cb182b9..263aecedc2 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -89,8 +89,6 @@ type Switch struct { filterTimeout time.Duration peerFilters []PeerFilterFunc - rng *mrand.Rand // seed for randomizing dial times and orders - metrics *Metrics } @@ -124,8 +122,8 @@ func NewSwitch( unconditionalPeerIDs: make(map[ID]struct{}), } - // Ensure we have a completely undeterministic PRNG. - sw.rng = tmrand.NewRand() + // Ensure we have a completely PRNG is reseeded. + tmrand.Reseed() sw.BaseService = *service.NewBaseService(nil, "P2P Switch", sw) @@ -505,7 +503,7 @@ func (sw *Switch) dialPeersAsync(netAddrs []*NetAddress) { } // permute the list, dial them in random order. - perm := sw.rng.Perm(len(netAddrs)) + perm := mrand.Perm(len(netAddrs)) for i := 0; i < len(perm); i++ { go func(i int) { j := perm[i] @@ -548,7 +546,7 @@ func (sw *Switch) DialPeerWithAddress(addr *NetAddress) error { // sleep for interval plus some random amount of ms on [0, dialRandomizerIntervalMilliseconds] func (sw *Switch) randomSleep(interval time.Duration) { - r := time.Duration(sw.rng.Int63n(dialRandomizerIntervalMilliseconds)) * time.Millisecond + r := time.Duration(mrand.Int63n(dialRandomizerIntervalMilliseconds)) * time.Millisecond time.Sleep(r + interval) } From 01bae2752cc8921de3cd2df211a452e2f1730eb9 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:42:31 +0200 Subject: [PATCH 14/27] make it explicit that the usages of math/rand and tmrand are intentionally not cryptographically secure: // nolint:gosec // G404: Use of weak random number generator --- libs/bits/bit_array.go | 7 +++++-- libs/rand/random.go | 3 +++ libs/test/mutate.go | 1 + p2p/switch.go | 1 + rpc/jsonrpc/client/ws_client.go | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/bits/bit_array.go b/libs/bits/bit_array.go index c6ed4af1bf..6724595276 100644 --- a/libs/bits/bit_array.go +++ b/libs/bits/bit_array.go @@ -11,6 +11,7 @@ import ( "sync" tmmath "github.com/lazyledger/lazyledger-core/libs/math" + tmrand "github.com/lazyledger/lazyledger-core/libs/rand" tmprotobits "github.com/lazyledger/lazyledger-core/proto/tendermint/libs/bits" ) @@ -24,6 +25,8 @@ type BitArray struct { // NewBitArray returns a new bit array. // It returns nil if the number of bits is zero. func NewBitArray(bits int) *BitArray { + // Reseed non-deterministically. + tmrand.Reseed() if bits <= 0 { return nil } @@ -242,7 +245,7 @@ func (bA *BitArray) IsFull() bool { // PickRandom returns a random index for a set bit in the bit array. // If there is no such value, it returns 0, false. -// It uses the global randomness in `random.go` to get this index. +// It uses math/rand's global randomness Source to get this index. func (bA *BitArray) PickRandom() (int, bool) { if bA == nil { return 0, false @@ -255,7 +258,7 @@ func (bA *BitArray) PickRandom() (int, bool) { if len(trueIndices) == 0 { // no bits set to true return 0, false } - + // nolint:gosec // G404: Use of weak random number generator return trueIndices[mrand.Intn(len(trueIndices))], true } diff --git a/libs/rand/random.go b/libs/rand/random.go index b82ac50d20..a28577873f 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -25,6 +25,7 @@ func init() { // use math/rand's top-level convenience functions instead. func NewRand() *mrand.Rand { seed := crandSeed() + // nolint:gosec // G404: Use of weak random number generator return mrand.New(mrand.NewSource(seed)) } @@ -49,6 +50,7 @@ func Str(length int) string { chars := make([]byte, 0, length) for { + // nolint:gosec // G404: Use of weak random number generator val := mrand.Int63() for i := 0; i < 10; i++ { v := int(val & 0x3f) // rightmost 6 bits @@ -70,6 +72,7 @@ func Str(length int) string { func Bytes(n int) []byte { bs := make([]byte, n) for i := 0; i < len(bs); i++ { + // nolint:gosec // G404: Use of weak random number generator bs[i] = byte(mrand.Int() & 0xFF) } return bs diff --git a/libs/test/mutate.go b/libs/test/mutate.go index 9d2b6e821c..94920cad5a 100644 --- a/libs/test/mutate.go +++ b/libs/test/mutate.go @@ -1,3 +1,4 @@ +// nolint:gosec // G404: Use of weak random number generator package test import ( diff --git a/p2p/switch.go b/p2p/switch.go index 263aecedc2..b0537d229f 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -546,6 +546,7 @@ func (sw *Switch) DialPeerWithAddress(addr *NetAddress) error { // sleep for interval plus some random amount of ms on [0, dialRandomizerIntervalMilliseconds] func (sw *Switch) randomSleep(interval time.Duration) { + // nolint:gosec // G404: Use of weak random number generator r := time.Duration(mrand.Int63n(dialRandomizerIntervalMilliseconds)) * time.Millisecond time.Sleep(r + interval) } diff --git a/rpc/jsonrpc/client/ws_client.go b/rpc/jsonrpc/client/ws_client.go index ca9c6fdcb9..348091c1b0 100644 --- a/rpc/jsonrpc/client/ws_client.go +++ b/rpc/jsonrpc/client/ws_client.go @@ -287,6 +287,7 @@ func (c *WSClient) reconnect() error { }() for { + // nolint:gosec // G404: Use of weak random number generator jitter := time.Duration(mrand.Float64() * float64(time.Second)) // 1s == (1e9 ns) backoffDuration := jitter + ((1 << uint(attempt)) * time.Second) From 8922c218a60449c31ea31c4f5ed5a5c68ed1d62a Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:49:32 +0200 Subject: [PATCH 15/27] add a few missed nolints --- p2p/pex/addrbook.go | 2 ++ p2p/test_util.go | 1 + 2 files changed, 3 insertions(+) diff --git a/p2p/pex/addrbook.go b/p2p/pex/addrbook.go index 6c7cd97e68..5bde9f1e81 100644 --- a/p2p/pex/addrbook.go +++ b/p2p/pex/addrbook.go @@ -266,6 +266,7 @@ func (a *addrBook) Empty() bool { // and determines how biased we are to pick an address from a new bucket. // PickAddress returns nil if the AddrBook is empty or if we try to pick // from an empty bucket. +// nolint:gosec // G404: Use of weak random number generator func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress { a.mtx.Lock() defer a.mtx.Unlock() @@ -385,6 +386,7 @@ func (a *addrBook) ReinstateBadPeers() { // GetSelection implements AddrBook. // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols. // Must never return a nil address. +// nolint:gosec // G404: Use of weak random number generator func (a *addrBook) GetSelection() []*p2p.NetAddress { a.mtx.Lock() defer a.mtx.Unlock() diff --git a/p2p/test_util.go b/p2p/test_util.go index 293e00fa57..1a6b5488c2 100644 --- a/p2p/test_util.go +++ b/p2p/test_util.go @@ -47,6 +47,7 @@ func CreateRandomPeer(outbound bool) Peer { return p } +// nolint:gosec // G404: Use of weak random number generator func CreateRoutableAddr() (addr string, netAddr *NetAddress) { for { var err error From b5b94b744ad1ed58c22cba75825e78fe97585a27 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:52:27 +0200 Subject: [PATCH 16/27] panic in the almost impossible case that we don't have enough entropy to read from OS randomness at this point --- libs/rand/random.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index a28577873f..55e88718eb 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -3,6 +3,7 @@ package rand import ( crand "crypto/rand" "encoding/binary" + "fmt" mrand "math/rand" ) @@ -80,6 +81,9 @@ func Bytes(n int) []byte { func crandSeed() int64 { var seed int64 - binary.Read(crand.Reader, binary.BigEndian, &seed) + err := binary.Read(crand.Reader, binary.BigEndian, &seed) + if err != nil { + panic(fmt.Sprintf("could nor read random seed from crypto/rand: %v", err)) + } return seed } From c14146e5e5b2d2b0192a3f1d9d3b5e0a6ecbc76e Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:55:39 +0200 Subject: [PATCH 17/27] remaining lints --- abci/example/kvstore/helpers.go | 2 +- abci/tests/server/client.go | 1 + consensus/wal_generator.go | 1 + types/validator.go | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/abci/example/kvstore/helpers.go b/abci/example/kvstore/helpers.go index 9b65ad92db..a9731aab17 100644 --- a/abci/example/kvstore/helpers.go +++ b/abci/example/kvstore/helpers.go @@ -12,7 +12,7 @@ import ( func RandVal(i int) types.ValidatorUpdate { pubkey := tmrand.Bytes(32) // Random value between [0, 2^16 - 1] - power := mrand.Uint32() & (1<<16 - 1) + power := mrand.Uint32() & (1<<16 - 1) // nolint:gosec // G404: Use of weak random number generator v := types.UpdateValidator(pubkey, int64(power), "") return v } diff --git a/abci/tests/server/client.go b/abci/tests/server/client.go index 86df77eed2..b650617dca 100644 --- a/abci/tests/server/client.go +++ b/abci/tests/server/client.go @@ -18,6 +18,7 @@ func InitChain(client abcicli.Client) error { total := 10 vals := make([]types.ValidatorUpdate, total) for i := 0; i < total; i++ { + // nolint:gosec // G404: Use of weak random number generator pubkey := tmrand.Bytes(33) power := mrand.Int() vals[i] = types.UpdateValidator(pubkey, int64(power), "") diff --git a/consensus/wal_generator.go b/consensus/wal_generator.go index 1bae5e3d55..6a0375deb4 100644 --- a/consensus/wal_generator.go +++ b/consensus/wal_generator.go @@ -139,6 +139,7 @@ func WALWithNBlocks(t *testing.T, numBlocks int) (data []byte, err error) { func randPort() int { // returns between base and base + spread base, spread := 20000, 20000 + // nolint:gosec // G404: Use of weak random number generator return base + mrand.Intn(spread) } diff --git a/types/validator.go b/types/validator.go index e0cbc3440d..76aecabeab 100644 --- a/types/validator.go +++ b/types/validator.go @@ -182,6 +182,7 @@ func RandValidator(randPower bool, minPower int64) (*Validator, PrivValidator) { privVal := NewMockPV() votePower := minPower if randPower { + // nolint:gosec // G404: Use of weak random number generator votePower += int64(mrand.Uint32()) } pubKey, err := privVal.GetPubKey() From 7495931ec01fed051396ac86aedccae5fbbafac2 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 13:59:51 +0200 Subject: [PATCH 18/27] actually appease the linter --- abci/tests/server/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abci/tests/server/client.go b/abci/tests/server/client.go index b650617dca..dd638229b7 100644 --- a/abci/tests/server/client.go +++ b/abci/tests/server/client.go @@ -18,8 +18,8 @@ func InitChain(client abcicli.Client) error { total := 10 vals := make([]types.ValidatorUpdate, total) for i := 0; i < total; i++ { - // nolint:gosec // G404: Use of weak random number generator pubkey := tmrand.Bytes(33) + // nolint:gosec // G404: Use of weak random number generator power := mrand.Int() vals[i] = types.UpdateValidator(pubkey, int64(power), "") } From 8c0aeb3cc0bf682e38d6f5c3003eee845a1785a6 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 14:05:32 +0200 Subject: [PATCH 19/27] actually appease the linter 2.0 --- p2p/pex/addrbook.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p2p/pex/addrbook.go b/p2p/pex/addrbook.go index 5bde9f1e81..1c3a835dfb 100644 --- a/p2p/pex/addrbook.go +++ b/p2p/pex/addrbook.go @@ -386,7 +386,6 @@ func (a *addrBook) ReinstateBadPeers() { // GetSelection implements AddrBook. // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols. // Must never return a nil address. -// nolint:gosec // G404: Use of weak random number generator func (a *addrBook) GetSelection() []*p2p.NetAddress { a.mtx.Lock() defer a.mtx.Unlock() @@ -417,6 +416,7 @@ func (a *addrBook) GetSelection() []*p2p.NetAddress { // `numAddresses' since we are throwing the rest. for i := 0; i < numAddresses; i++ { // pick a number between current index and the end + // nolint:gosec // G404: Use of weak random number generator j := mrand.Intn(len(allAddr)-i) + i allAddr[i], allAddr[j] = allAddr[j], allAddr[i] } @@ -681,6 +681,7 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error { } // The more entries we have, the less likely we are to add more. factor := int32(2 * len(ka.Buckets)) + // nolint:gosec // G404: Use of weak random number generator if mrand.Int31n(factor) != 0 { return nil } From 36b44fb1296adb79b31f553747332c2c1d9b70ca Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 22:17:29 +0200 Subject: [PATCH 20/27] fix merge glitches --- consensus/wal_generator.go | 2 -- p2p/switch.go | 1 - 2 files changed, 3 deletions(-) diff --git a/consensus/wal_generator.go b/consensus/wal_generator.go index 6a0375deb4..c56f02635f 100644 --- a/consensus/wal_generator.go +++ b/consensus/wal_generator.go @@ -14,7 +14,6 @@ import ( cfg "github.com/lazyledger/lazyledger-core/config" "github.com/lazyledger/lazyledger-core/libs/db/memdb" "github.com/lazyledger/lazyledger-core/libs/log" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" "github.com/lazyledger/lazyledger-core/privval" "github.com/lazyledger/lazyledger-core/proxy" sm "github.com/lazyledger/lazyledger-core/state" @@ -31,7 +30,6 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) { config := getConfig(t) app := kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), "wal_generator")) - t.Cleanup(func() { require.NoError(t, app.Close()) }) logger := log.TestingLogger().With("wal_generator", "wal_generator") logger.Info("generating WAL (last height msg excluded)", "numBlocks", numBlocks) diff --git a/p2p/switch.go b/p2p/switch.go index b0537d229f..ad22e21380 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -4,7 +4,6 @@ import ( "fmt" "math" mrand "math/rand" - "net" "sync" "time" From d604163ab371797a9e87bad668df0876655af424 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 22:35:06 +0200 Subject: [PATCH 21/27] fix test & lint glichtes (while merging) --- libs/bits/bit_array.go | 18 ++++++------------ state/state_test.go | 1 - test/maverick/consensus/wal_generator.go | 4 ++-- types/block_test.go | 8 ++++---- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/libs/bits/bit_array.go b/libs/bits/bit_array.go index 6724595276..99a19ff561 100644 --- a/libs/bits/bit_array.go +++ b/libs/bits/bit_array.go @@ -425,21 +425,21 @@ func (bA *BitArray) UnmarshalJSON(bz []byte) error { // ToProto converts BitArray to protobuf. It returns nil if BitArray is // nil/empty. +// +// XXX: It does not copy the array. func (bA *BitArray) ToProto() *tmprotobits.BitArray { if bA == nil || (len(bA.Elems) == 0 && bA.Bits == 0) { // empty return nil } - bA.mtx.Lock() - defer bA.mtx.Unlock() - - bc := bA.copy() - return &tmprotobits.BitArray{Bits: int64(bc.Bits), Elems: bc.Elems} + return &tmprotobits.BitArray{Bits: int64(bA.Bits), Elems: bA.Elems} } // FromProto sets BitArray to the given protoBitArray. It returns an error if // protoBitArray is invalid. +// +// XXX: It does not copy the array. func (bA *BitArray) FromProto(protoBitArray *tmprotobits.BitArray) error { if protoBitArray == nil { return nil @@ -457,14 +457,8 @@ func (bA *BitArray) FromProto(protoBitArray *tmprotobits.BitArray) error { return fmt.Errorf("invalid number of Elems: got %d, but exp %d", got, exp) } - bA.mtx.Lock() - defer bA.mtx.Unlock() - - ec := make([]uint64, len(protoBitArray.Elems)) - copy(ec, protoBitArray.Elems) - bA.Bits = int(protoBitArray.Bits) - bA.Elems = ec + bA.Elems = protoBitArray.Elems return nil } diff --git a/state/state_test.go b/state/state_test.go index 1ce40fa88e..e86cef28db 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -18,7 +18,6 @@ import ( cryptoenc "github.com/lazyledger/lazyledger-core/crypto/encoding" dbm "github.com/lazyledger/lazyledger-core/libs/db" "github.com/lazyledger/lazyledger-core/libs/db/badgerdb" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" tmstate "github.com/lazyledger/lazyledger-core/proto/tendermint/state" tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types" sm "github.com/lazyledger/lazyledger-core/state" diff --git a/test/maverick/consensus/wal_generator.go b/test/maverick/consensus/wal_generator.go index 40e50f0468..dea63de552 100644 --- a/test/maverick/consensus/wal_generator.go +++ b/test/maverick/consensus/wal_generator.go @@ -5,6 +5,7 @@ import ( "bytes" "fmt" "io" + mrand "math/rand" "path/filepath" "testing" "time" @@ -13,7 +14,6 @@ import ( cfg "github.com/lazyledger/lazyledger-core/config" "github.com/lazyledger/lazyledger-core/libs/db/memdb" "github.com/lazyledger/lazyledger-core/libs/log" - tmrand "github.com/lazyledger/lazyledger-core/libs/rand" "github.com/lazyledger/lazyledger-core/privval" "github.com/lazyledger/lazyledger-core/proxy" sm "github.com/lazyledger/lazyledger-core/state" @@ -140,7 +140,7 @@ func WALWithNBlocks(t *testing.T, numBlocks int) (data []byte, err error) { func randPort() int { // returns between base and base + spread base, spread := 20000, 20000 - return base + tmrand.Intn(spread) + return base + mrand.Intn(spread) // nolint:gosec // G404: Use of weak random number generator } func makeAddrs() (string, string, string) { diff --git a/types/block_test.go b/types/block_test.go index 9c25874033..0b7ab7f6a6 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -194,8 +194,8 @@ func makeBlockIDRandom() BlockID { blockHash = make([]byte, tmhash.Size) partSetHash = make([]byte, tmhash.Size) ) - rand.Read(blockHash) //nolint: errcheck // ignore errcheck for read - rand.Read(partSetHash) //nolint: errcheck // ignore errcheck for read + mrand.Read(blockHash) + mrand.Read(partSetHash) return BlockID{blockHash, PartSetHeader{123, partSetHash}} } @@ -1411,7 +1411,7 @@ func generateRandNamespacedRawData(total int, nidSize int, leafSize int) [][]byt data := make([][]byte, total) for i := 0; i < total; i++ { nid := make([]byte, nidSize) - _, err := rand.Read(nid) + _, err := mrand.Read(nid) if err != nil { panic(err) } @@ -1421,7 +1421,7 @@ func generateRandNamespacedRawData(total int, nidSize int, leafSize int) [][]byt sortByteArrays(data) for i := 0; i < total; i++ { d := make([]byte, leafSize) - _, err := rand.Read(d) + _, err := mrand.Read(d) if err != nil { panic(err) } From 07676320761278c69c1385d9e6d80ea0464d52cb Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 22:55:14 +0200 Subject: [PATCH 22/27] fix another test --- types/block_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/block_test.go b/types/block_test.go index 0b7ab7f6a6..c1aacd889d 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -671,6 +671,8 @@ func TestBlockProtoBuf(t *testing.T) { evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain") b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}} + // update internal byteSize field s.t. the expected b2.Evidence matches with the decoded one: + _ = b2.Evidence.ByteSize() b2.EvidenceHash = b2.Evidence.Hash() b3 := MakeBlock(h, []Tx{}, []Evidence{}, nil, Messages{}, c1) From e81881c6e11449e569dcb4444b5367aaafc197f9 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Sat, 17 Apr 2021 23:10:58 +0200 Subject: [PATCH 23/27] relax timeouts here too --- test/e2e/runner/perturb.go | 2 +- test/e2e/runner/start.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/runner/perturb.go b/test/e2e/runner/perturb.go index d7a4897732..344f15c5b1 100644 --- a/test/e2e/runner/perturb.go +++ b/test/e2e/runner/perturb.go @@ -66,7 +66,7 @@ func PerturbNode(node *e2e.Node, perturbation e2e.Perturbation) (*rpctypes.Resul return nil, fmt.Errorf("unexpected perturbation %q", perturbation) } - status, err := waitForNode(node, 0, 10*time.Second) + status, err := waitForNode(node, 0, 20*time.Second) if err != nil { return nil, err } diff --git a/test/e2e/runner/start.go b/test/e2e/runner/start.go index c2af2af311..957b90aaf8 100644 --- a/test/e2e/runner/start.go +++ b/test/e2e/runner/start.go @@ -75,7 +75,7 @@ func Start(testnet *e2e.Testnet) error { if err := execCompose(testnet.Dir, "up", "-d", node.Name); err != nil { return err } - status, err := waitForNode(node, node.StartAt, 1*time.Minute) + status, err := waitForNode(node, node.StartAt, 3*time.Minute) if err != nil { return err } From a910e47be319ed8838e2e078a8e12b140e01105a Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Mon, 19 Apr 2021 12:31:12 +0200 Subject: [PATCH 24/27] Update p2p/switch.go Co-authored-by: Callum Waters --- p2p/switch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/switch.go b/p2p/switch.go index ad22e21380..89cac2245d 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -121,7 +121,7 @@ func NewSwitch( unconditionalPeerIDs: make(map[ID]struct{}), } - // Ensure we have a completely PRNG is reseeded. + // Ensure PRNG is reseeded. tmrand.Reseed() sw.BaseService = *service.NewBaseService(nil, "P2P Switch", sw) From 035711c7685ecce692d5676412b8c0db7182e2de Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Mon, 19 Apr 2021 14:50:46 +0200 Subject: [PATCH 25/27] Apply review feedback: use mrand.Uint32() + 1 for height use mrand.Uint32() + 1 for height --- types/evidence_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/evidence_test.go b/types/evidence_test.go index 8f64ca8934..c5afcb80fe 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -247,7 +247,7 @@ func makeHeaderRandom() *Header { return &Header{ Version: tmversion.Consensus{Block: version.BlockProtocol, App: 1}, ChainID: tmrand.Str(12), - Height: int64(mrand.Uint32()&(1<<16-1)) + 1, + Height: int64(mrand.Uint32()+ 1), Time: time.Now(), LastBlockID: makeBlockIDRandom(), LastCommitHash: crypto.CRandBytes(tmhash.Size), From edc9cb3720de955710ab904b8e4c5b15845a3e53 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Mon, 19 Apr 2021 15:10:23 +0200 Subject: [PATCH 26/27] go fmt --- types/evidence_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/evidence_test.go b/types/evidence_test.go index c5afcb80fe..82de753a63 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -247,7 +247,7 @@ func makeHeaderRandom() *Header { return &Header{ Version: tmversion.Consensus{Block: version.BlockProtocol, App: 1}, ChainID: tmrand.Str(12), - Height: int64(mrand.Uint32()+ 1), + Height: int64(mrand.Uint32() + 1), Time: time.Now(), LastBlockID: makeBlockIDRandom(), LastCommitHash: crypto.CRandBytes(tmhash.Size), From e70c207541d1efe3d4ef4b9b3ab5deee954db074 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Mon, 19 Apr 2021 16:58:11 +0200 Subject: [PATCH 27/27] Update comment to reflect current state of Bytes/Str functions --- libs/rand/random.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/rand/random.go b/libs/rand/random.go index 55e88718eb..ee400e1958 100644 --- a/libs/rand/random.go +++ b/libs/rand/random.go @@ -43,7 +43,7 @@ func Reseed() { } // Str constructs a random alphanumeric string of given length -// from a freshly instantiated prng. +// from math/rand's global default Source. func Str(length int) string { if length <= 0 { return "" @@ -69,7 +69,7 @@ func Str(length int) string { } } -// Bytes returns n random bytes generated from a freshly instantiated prng. +// Bytes returns n random bytes generated from math/rand's global default Source. func Bytes(n int) []byte { bs := make([]byte, n) for i := 0; i < len(bs); i++ {