github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/random_generator_test.go (about) 1 package environment_test 2 3 import ( 4 "encoding/binary" 5 "math" 6 mrand "math/rand" 7 "testing" 8 9 "github.com/onflow/crypto/random" 10 "github.com/stretchr/testify/require" 11 12 "github.com/onflow/flow-go/fvm/environment" 13 "github.com/onflow/flow-go/fvm/environment/mock" 14 "github.com/onflow/flow-go/fvm/tracing" 15 "github.com/onflow/flow-go/utils/unittest" 16 ) 17 18 func TestRandomGenerator(t *testing.T) { 19 randomSourceHistoryProvider := &mock.EntropyProvider{} 20 randomSourceHistoryProvider.On("RandomSource").Return(unittest.RandomBytes(48), nil) 21 22 getRandoms := func(txId []byte, N int) []uint64 { 23 // seed the RG with the same block header 24 urg := environment.NewRandomGenerator( 25 tracing.NewTracerSpan(), 26 randomSourceHistoryProvider, 27 txId) 28 numbers := make([]uint64, N) 29 for i := 0; i < N; i++ { 30 var buffer [8]byte 31 err := urg.ReadRandom(buffer[:]) 32 require.NoError(t, err) 33 numbers[i] = binary.LittleEndian.Uint64(buffer[:]) 34 } 35 return numbers 36 } 37 38 // basic randomness test to check outputs are "uniformly" spread over the 39 // output space 40 t.Run("randomness test", func(t *testing.T) { 41 for i := 0; i < 10; i++ { 42 txId := unittest.TransactionFixture().ID() 43 urg := environment.NewRandomGenerator( 44 tracing.NewTracerSpan(), 45 randomSourceHistoryProvider, 46 txId[:]) 47 48 // make sure n is a power of 2 so that there is no bias in the last class 49 // n is a random power of 2 (from 2 to 2^10) 50 n := 1 << (1 + mrand.Intn(10)) 51 classWidth := (math.MaxUint64 / uint64(n)) + 1 52 random.BasicDistributionTest(t, uint64(n), uint64(classWidth), func() (uint64, error) { 53 var buffer [8]byte 54 err := urg.ReadRandom(buffer[:]) 55 if err != nil { 56 return 0, err 57 } 58 return binary.LittleEndian.Uint64(buffer[:]), nil 59 }) 60 } 61 }) 62 63 // tests that has deterministic outputs. 64 t.Run("PRG-based Random", func(t *testing.T) { 65 for i := 0; i < 10; i++ { 66 txId := unittest.TransactionFixture().ID() 67 N := 100 68 r1 := getRandoms(txId[:], N) 69 r2 := getRandoms(txId[:], N) 70 require.Equal(t, r1, r2) 71 } 72 }) 73 74 t.Run("transaction specific randomness", func(t *testing.T) { 75 txns := [][]uint64{} 76 for i := 0; i < 10; i++ { 77 txId := unittest.TransactionFixture().ID() 78 N := 2 79 txns = append(txns, getRandoms(txId[:], N)) 80 } 81 82 for i, txn := range txns { 83 for _, otherTxn := range txns[i+1:] { 84 require.NotEqual(t, txn, otherTxn) 85 } 86 } 87 }) 88 }