diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 86502cf83d8..3efd756d7e5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -32,7 +32,7 @@ jobs: if: runner.os == 'Linux' uses: golangci/golangci-lint-action@v6 with: - version: v1.59.1 + version: v1.61.0 args: --help - name: Lint diff --git a/erigon-lib/.golangci.yml b/erigon-lib/.golangci.yml index d66cd898232..7f4a485356d 100644 --- a/erigon-lib/.golangci.yml +++ b/erigon-lib/.golangci.yml @@ -22,6 +22,7 @@ linters: - testifylint #TODO: enable me - perfsprint #TODO: enable me - protogetter + - typecheck enable: - unconvert - predeclared @@ -111,6 +112,7 @@ issues: - unused - gocritic - perfsprint + - typecheck - path: hack\.go linters: - gosec diff --git a/erigon-lib/state/aggregator_bench_test.go b/erigon-lib/state/aggregator_bench_test.go index 894563f9eef..089884db80a 100644 --- a/erigon-lib/state/aggregator_bench_test.go +++ b/erigon-lib/state/aggregator_bench_test.go @@ -20,7 +20,6 @@ import ( "bytes" "context" "fmt" - "math/rand" "os" "path" "path/filepath" @@ -109,7 +108,7 @@ func BenchmarkAggregator_Processing(b *testing.B) { } func queueKeys(ctx context.Context, seed, ofSize uint64) <-chan []byte { - rnd := rand.New(rand.NewSource(int64(seed))) + rnd := newRnd(seed) keys := make(chan []byte, 1) go func() { for { @@ -127,10 +126,10 @@ func queueKeys(ctx context.Context, seed, ofSize uint64) <-chan []byte { } func Benchmark_BtreeIndex_Allocation(b *testing.B) { - rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + rnd := newRnd(uint64(time.Now().UnixNano())) for i := 0; i < b.N; i++ { now := time.Now() - count := rnd.Intn(1000000000) + count := rnd.IntN(1000000000) bt := newBtAlloc(uint64(count), uint64(1<<12), true, nil, nil) bt.traverseDfs() fmt.Printf("alloc %v\n", time.Since(now)) @@ -139,7 +138,7 @@ func Benchmark_BtreeIndex_Allocation(b *testing.B) { func Benchmark_BtreeIndex_Search(b *testing.B) { logger := log.New() - rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + rnd := newRnd(uint64(time.Now().UnixNano())) tmp := b.TempDir() defer os.RemoveAll(tmp) dataPath := "../../data/storage.256-288.kv" @@ -159,7 +158,7 @@ func Benchmark_BtreeIndex_Search(b *testing.B) { getter := seg.NewReader(kv.MakeGetter(), comp) for i := 0; i < b.N; i++ { - p := rnd.Intn(len(keys)) + p := rnd.IntN(len(keys)) cur, err := bt.Seek(getter, keys[p]) require.NoErrorf(b, err, "i=%d", i) require.EqualValues(b, keys[p], cur.Key()) @@ -193,12 +192,12 @@ func Benchmark_BTree_Seek(b *testing.B) { M := uint64(1024) compress := seg.CompressNone kv, bt, keys, _ := benchInitBtreeIndex(b, M, compress) - rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + rnd := newRnd(uint64(time.Now().UnixNano())) getter := seg.NewReader(kv.MakeGetter(), compress) b.Run("seek_only", func(b *testing.B) { for i := 0; i < b.N; i++ { - p := rnd.Intn(len(keys)) + p := rnd.IntN(len(keys)) cur, err := bt.Seek(getter, keys[p]) require.NoError(b, err) @@ -209,7 +208,7 @@ func Benchmark_BTree_Seek(b *testing.B) { b.Run("seek_then_next", func(b *testing.B) { for i := 0; i < b.N; i++ { - p := rnd.Intn(len(keys)) + p := rnd.IntN(len(keys)) cur, err := bt.Seek(getter, keys[p]) require.NoError(b, err) @@ -249,7 +248,7 @@ func Benchmark_Recsplit_Find_ExternalFile(b *testing.B) { b.Skip("requires existing KV index file at ../../data/storage.kv") } - rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + rnd := newRnd(uint64(time.Now().UnixNano())) tmp := b.TempDir() defer os.RemoveAll(tmp) @@ -269,7 +268,7 @@ func Benchmark_Recsplit_Find_ExternalFile(b *testing.B) { require.NoError(b, err) for i := 0; i < b.N; i++ { - p := rnd.Intn(len(keys)) + p := rnd.IntN(len(keys)) offset, _ := idxr.Lookup(keys[p]) getter.Reset(offset) diff --git a/erigon-lib/state/aggregator_fuzz_test.go b/erigon-lib/state/aggregator_fuzz_test.go index 37ab28898f0..103bc56a358 100644 --- a/erigon-lib/state/aggregator_fuzz_test.go +++ b/erigon-lib/state/aggregator_fuzz_test.go @@ -21,6 +21,9 @@ package state import ( "context" "encoding/binary" + "testing" + "time" + "github.com/c2h5oh/datasize" "github.com/erigontech/erigon-lib/common" "github.com/erigontech/erigon-lib/common/datadir" @@ -30,8 +33,6 @@ import ( "github.com/erigontech/erigon-lib/log/v3" "github.com/erigontech/erigon-lib/types" "github.com/holiman/uint256" - "testing" - "time" "github.com/stretchr/testify/require" ) diff --git a/erigon-lib/state/aggregator_test.go b/erigon-lib/state/aggregator_test.go index f99b5f36d87..5b50a93392a 100644 --- a/erigon-lib/state/aggregator_test.go +++ b/erigon-lib/state/aggregator_test.go @@ -22,7 +22,6 @@ import ( "encoding/binary" "encoding/hex" "fmt" - "github.com/erigontech/erigon-lib/commitment" "math" "math/rand" "os" @@ -33,6 +32,8 @@ import ( "testing" "time" + "github.com/erigontech/erigon-lib/commitment" + "github.com/erigontech/erigon-lib/common/background" "github.com/c2h5oh/datasize" @@ -109,7 +110,7 @@ func aggregatorV3_RestartOnDatadir(t *testing.T, rc runCfg) { defer domains.Close() var latestCommitTxNum uint64 - rnd := rand.New(rand.NewSource(time.Now().Unix())) + rnd := newRnd(0) someKey := []byte("somekey") txs := (aggStep / 2) * 19 @@ -249,7 +250,7 @@ func TestAggregatorV3_PruneSmallBatches(t *testing.T) { maxTx := aggStep * 5 t.Logf("step=%d tx_count=%d\n", aggStep, maxTx) - rnd := rand.New(rand.NewSource(0)) + rnd := newRnd(0) generateSharedDomainsUpdates(t, domains, maxTx, rnd, 20, 10, aggStep/2) @@ -429,7 +430,7 @@ func fillRawdbTxNumsIndexForSharedDomains(t *testing.T, rwTx kv.RwTx, maxTx, com } } -func generateSharedDomainsUpdates(t *testing.T, domains *SharedDomains, maxTxNum uint64, rnd *rand.Rand, keyMaxLen, keysCount, commitEvery uint64) map[string]struct{} { +func generateSharedDomainsUpdates(t *testing.T, domains *SharedDomains, maxTxNum uint64, rnd *rndGen, keyMaxLen, keysCount, commitEvery uint64) map[string]struct{} { t.Helper() usedKeys := make(map[string]struct{}, keysCount*maxTxNum) for txNum := uint64(1); txNum <= maxTxNum; txNum++ { @@ -445,14 +446,14 @@ func generateSharedDomainsUpdates(t *testing.T, domains *SharedDomains, maxTxNum return usedKeys } -func generateSharedDomainsUpdatesForTx(t *testing.T, domains *SharedDomains, txNum uint64, rnd *rand.Rand, prevKeys map[string]struct{}, keyMaxLen, keysCount uint64) map[string]struct{} { +func generateSharedDomainsUpdatesForTx(t *testing.T, domains *SharedDomains, txNum uint64, rnd *rndGen, prevKeys map[string]struct{}, keyMaxLen, keysCount uint64) map[string]struct{} { t.Helper() domains.SetTxNum(txNum) getKey := func() ([]byte, bool) { - r := rnd.Intn(100) + r := rnd.IntN(100) if r < 50 && len(prevKeys) > 0 { - ri := rnd.Intn(len(prevKeys)) + ri := rnd.IntN(len(prevKeys)) for k := range prevKeys { if ri == 0 { return []byte(k), true @@ -471,7 +472,7 @@ func generateSharedDomainsUpdatesForTx(t *testing.T, domains *SharedDomains, txN for j := uint64(0); j < keysCount; j++ { key, existed := getKey() - r := rnd.Intn(101) + r := rnd.IntN(101) switch { case r <= 33: buf := types.EncodeAccountBytesV3(txNum, uint256.NewInt(txNum*100_000), nil, 0) @@ -484,7 +485,7 @@ func generateSharedDomainsUpdatesForTx(t *testing.T, domains *SharedDomains, txN require.NoError(t, err) case r > 33 && r <= 66: - codeUpd := make([]byte, rnd.Intn(24576)) + codeUpd := make([]byte, rnd.IntN(24576)) _, err := rnd.Read(codeUpd) require.NoError(t, err) for limit := 1000; len(key) > length.Addr && limit > 0; limit-- { @@ -569,7 +570,7 @@ func TestAggregatorV3_RestartOnFiles(t *testing.T) { txs := aggStep * 5 t.Logf("step=%d tx_count=%d\n", aggStep, txs) - rnd := rand.New(rand.NewSource(0)) + rnd := newRnd(0) keys := make([][]byte, txs) for txNum := uint64(1); txNum <= txs; txNum++ { @@ -708,7 +709,7 @@ func TestAggregatorV3_ReplaceCommittedKeys(t *testing.T) { txs := (aggStep) * StepsInColdFile t.Logf("step=%d tx_count=%d", aggStep, txs) - rnd := rand.New(rand.NewSource(0)) + rnd := newRnd(0) keys := make([][]byte, txs/2) var prev1, prev2 []byte @@ -822,7 +823,7 @@ func pivotKeysFromKV(dataPath string) ([][]byte, error) { func generateKV(tb testing.TB, tmp string, keySize, valueSize, keyCount int, logger log.Logger, compressFlags seg.FileCompression) string { tb.Helper() - rnd := rand.New(rand.NewSource(0)) + rnd := newRnd(0) values := make([]byte, valueSize) dataPath := path.Join(tmp, fmt.Sprintf("%dk.kv", keyCount/1000)) @@ -842,7 +843,7 @@ func generateKV(tb testing.TB, tmp string, keySize, valueSize, keyCount int, log binary.BigEndian.PutUint64(key[keySize-8:], uint64(i)) require.NoError(tb, err) - n, err = rnd.Read(values[:rnd.Intn(valueSize)+1]) + n, err = rnd.Read(values[:rnd.IntN(valueSize)+1]) require.NoError(tb, err) err = collector.Collect(key, values[:n]) @@ -904,7 +905,7 @@ func testDbAndAggregatorv3(t *testing.T, aggStep uint64) (kv.RwDB, *Aggregator) func generateInputData(tb testing.TB, keySize, valueSize, keyCount int) ([][]byte, [][]byte) { tb.Helper() - rnd := rand.New(rand.NewSource(0)) + rnd := newRnd(0) values := make([][]byte, keyCount) keys := make([][]byte, keyCount) @@ -915,7 +916,7 @@ func generateInputData(tb testing.TB, keySize, valueSize, keyCount int) ([][]byt require.NoError(tb, err) keys[i] = common.Copy(bk[:n]) - n, err = rnd.Read(bv[:rnd.Intn(valueSize)+1]) + n, err = rnd.Read(bv[:rnd.IntN(valueSize)+1]) require.NoError(tb, err) values[i] = common.Copy(bv[:n]) diff --git a/erigon-lib/state/bps_tree.go b/erigon-lib/state/bps_tree.go index d039f8ef5dd..188d7723590 100644 --- a/erigon-lib/state/bps_tree.go +++ b/erigon-lib/state/bps_tree.go @@ -25,14 +25,13 @@ import ( "time" "unsafe" - "github.com/erigontech/erigon-lib/common/dbg" - "github.com/c2h5oh/datasize" - "github.com/erigontech/erigon-lib/seg" "github.com/erigontech/erigon-lib/common" + "github.com/erigontech/erigon-lib/common/dbg" "github.com/erigontech/erigon-lib/log/v3" "github.com/erigontech/erigon-lib/recsplit/eliasfano32" + "github.com/erigontech/erigon-lib/seg" ) // nolint diff --git a/erigon-lib/state/domain_shared_bench_test.go b/erigon-lib/state/domain_shared_bench_test.go index 927255bbaba..2c8700e1734 100644 --- a/erigon-lib/state/domain_shared_bench_test.go +++ b/erigon-lib/state/domain_shared_bench_test.go @@ -19,7 +19,6 @@ package state import ( "context" "encoding/binary" - "math/rand" "testing" "github.com/stretchr/testify/require" @@ -46,8 +45,7 @@ func Benchmark_SharedDomains_GetLatest(t *testing.B) { defer domains.Close() maxTx := stepSize * 258 - seed := int64(4500) - rnd := rand.New(rand.NewSource(seed)) + rnd := newRnd(4500) keys := make([][]byte, 8) for i := 0; i < len(keys); i++ { @@ -104,7 +102,7 @@ func Benchmark_SharedDomains_GetLatest(t *testing.B) { for ik := 0; ik < t.N; ik++ { for i := 0; i < len(keys); i++ { - ts := uint64(rnd.Intn(int(maxTx))) + ts := uint64(rnd.IntN(int(maxTx))) v, ok, err := ac2.HistorySeek(kv.AccountsHistory, keys[i], ts, rwTx) require.True(t, ok) diff --git a/erigon-lib/state/domain_shared_test.go b/erigon-lib/state/domain_shared_test.go index d9fcbd20201..17606175321 100644 --- a/erigon-lib/state/domain_shared_test.go +++ b/erigon-lib/state/domain_shared_test.go @@ -20,7 +20,6 @@ import ( "context" "encoding/binary" "fmt" - "math/rand" "testing" "time" @@ -53,7 +52,7 @@ func TestSharedDomain_CommitmentKeyReplacement(t *testing.T) { require.NoError(t, err) defer domains.Close() - rnd := rand.New(rand.NewSource(2342)) + rnd := newRnd(2342) maxTx := stepSize * 8 // 1. generate data @@ -134,7 +133,7 @@ func TestSharedDomain_Unwind(t *testing.T) { maxTx := stepSize hashes := make([][]byte, maxTx) count := 10 - rnd := rand.New(rand.NewSource(0)) + rnd := newRnd(0) ac.Close() err = rwTx.Commit() require.NoError(t, err) @@ -180,7 +179,7 @@ Loop: err = domains.Flush(ctx, rwTx) require.NoError(t, err) - unwindTo := uint64(commitStep * rnd.Intn(int(maxTx)/commitStep)) + unwindTo := uint64(commitStep * rnd.IntN(int(maxTx)/commitStep)) domains.currentChangesAccumulator = nil acu := agg.BeginFilesRo() diff --git a/erigon-lib/state/domain_test.go b/erigon-lib/state/domain_test.go index f8f0b8d0ee3..5f29a48b56e 100644 --- a/erigon-lib/state/domain_test.go +++ b/erigon-lib/state/domain_test.go @@ -24,7 +24,8 @@ import ( "fmt" "io/fs" "math" - "math/rand" + randOld "math/rand" + "math/rand/v2" "os" "path/filepath" "sort" @@ -51,6 +52,20 @@ import ( "github.com/erigontech/erigon-lib/types" ) +type rndGen struct { + *rand.Rand + oldGen *randOld.Rand +} + +func newRnd(seed uint64) *rndGen { + return &rndGen{ + Rand: rand.New(rand.NewChaCha8([32]byte{byte(seed)})), + oldGen: randOld.New(randOld.NewSource(int64(seed))), + } +} +func (r *rndGen) IntN(n int) int { return int(r.Uint64N(uint64(n))) } +func (r *rndGen) Read(p []byte) (n int, err error) { return r.oldGen.Read(p) } // seems `go1.22` doesn't have `Read` method on `math/v2` generator + func testDbAndDomain(t *testing.T, logger log.Logger) (kv.RwDB, *Domain) { t.Helper() return testDbAndDomainOfStep(t, 16, logger) @@ -1262,10 +1277,7 @@ func generateTestDataForDomainCommitment(tb testing.TB, keySize1, keySize2, tota tb.Helper() doms := make(map[string]map[string][]upd) - seed := 31 - //seed := time.Now().Unix() - defer tb.Logf("generated data with seed %d, keys %d", seed, keyLimit) - r := rand.New(rand.NewSource(0)) + r := newRnd(31) accs := make(map[string][]upd) stor := make(map[string][]upd) @@ -1293,11 +1305,7 @@ func generateTestData(tb testing.TB, keySize1, keySize2, totalTx, keyTxsLimit, k tb.Helper() data := make(map[string][]upd) - //seed := time.Now().Unix() - seed := 31 - defer tb.Logf("generated data with seed %d, keys %d", seed, keyLimit) - - r := rand.New(rand.NewSource(0)) + r := newRnd(31) if keyLimit == 1 { key1 := generateRandomKey(r, keySize1) data[key1] = generateUpdates(r, totalTx, keyTxsLimit) @@ -1313,24 +1321,24 @@ func generateTestData(tb testing.TB, keySize1, keySize2, totalTx, keyTxsLimit, k return data } -func generateRandomKey(r *rand.Rand, size uint64) string { +func generateRandomKey(r *rndGen, size uint64) string { return string(generateRandomKeyBytes(r, size)) } -func generateRandomKeyBytes(r *rand.Rand, size uint64) []byte { +func generateRandomKeyBytes(r *rndGen, size uint64) []byte { key := make([]byte, size) r.Read(key) return key } -func generateAccountUpdates(r *rand.Rand, totalTx, keyTxsLimit uint64) []upd { +func generateAccountUpdates(r *rndGen, totalTx, keyTxsLimit uint64) []upd { updates := make([]upd, 0) usedTxNums := make(map[uint64]bool) for i := uint64(0); i < keyTxsLimit; i++ { txNum := generateRandomTxNum(r, totalTx, usedTxNums) - jitter := r.Intn(10e7) + jitter := r.IntN(10e7) value := types.EncodeAccountBytesV3(i, uint256.NewInt(i*10e4+uint64(jitter)), nil, 0) updates = append(updates, upd{txNum: txNum, value: value}) @@ -1341,7 +1349,7 @@ func generateAccountUpdates(r *rand.Rand, totalTx, keyTxsLimit uint64) []upd { return updates } -func generateArbitraryValueUpdates(r *rand.Rand, totalTx, keyTxsLimit, maxSize uint64) []upd { +func generateArbitraryValueUpdates(r *rndGen, totalTx, keyTxsLimit, maxSize uint64) []upd { updates := make([]upd, 0) usedTxNums := make(map[uint64]bool) //maxStorageSize := 24 * (1 << 10) // limit on contract code @@ -1349,7 +1357,7 @@ func generateArbitraryValueUpdates(r *rand.Rand, totalTx, keyTxsLimit, maxSize u for i := uint64(0); i < keyTxsLimit; i++ { txNum := generateRandomTxNum(r, totalTx, usedTxNums) - value := make([]byte, r.Intn(int(maxSize))) + value := make([]byte, r.IntN(int(maxSize))) r.Read(value) updates = append(updates, upd{txNum: txNum, value: value}) @@ -1360,7 +1368,7 @@ func generateArbitraryValueUpdates(r *rand.Rand, totalTx, keyTxsLimit, maxSize u return updates } -func generateUpdates(r *rand.Rand, totalTx, keyTxsLimit uint64) []upd { +func generateUpdates(r *rndGen, totalTx, keyTxsLimit uint64) []upd { updates := make([]upd, 0) usedTxNums := make(map[uint64]bool) @@ -1377,10 +1385,10 @@ func generateUpdates(r *rand.Rand, totalTx, keyTxsLimit uint64) []upd { return updates } -func generateRandomTxNum(r *rand.Rand, maxTxNum uint64, usedTxNums map[uint64]bool) uint64 { - txNum := uint64(r.Intn(int(maxTxNum))) +func generateRandomTxNum(r *rndGen, maxTxNum uint64, usedTxNums map[uint64]bool) uint64 { + txNum := uint64(r.IntN(int(maxTxNum))) for usedTxNums[txNum] { - txNum = uint64(r.Intn(int(maxTxNum))) + txNum = uint64(r.IntN(int(maxTxNum))) } return txNum @@ -1461,8 +1469,6 @@ func TestDomain_CanPruneAfterAggregation(t *testing.T) { aggStep := uint64(25) db, d := testDbAndDomainOfStep(t, aggStep, log.New()) - defer db.Close() - defer d.Close() tx, err := db.BeginRw(context.Background()) require.NoError(t, err) diff --git a/erigon-lib/tools/golangci_lint.sh b/erigon-lib/tools/golangci_lint.sh index ada4234150d..4c812bc72b9 100755 --- a/erigon-lib/tools/golangci_lint.sh +++ b/erigon-lib/tools/golangci_lint.sh @@ -2,7 +2,7 @@ scriptDir=$(dirname "${BASH_SOURCE[0]}") scriptName=$(basename "${BASH_SOURCE[0]}") -version="v1.59.1" +version="v1.60.0" if [[ "$1" == "--install-deps" ]] then