github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/p2p/ipld/sample.go (about) 1 package ipld 2 3 import ( 4 crand "crypto/rand" 5 "math/big" 6 7 "github.com/ipfs/go-cid" 8 "github.com/lazyledger/nmt/namespace" 9 10 "github.com/lazyledger/lazyledger-core/ipfs/plugin" 11 "github.com/lazyledger/lazyledger-core/types" 12 ) 13 14 // Sample is a point in 2D space over square. 15 type Sample struct { 16 Row, Col uint32 17 } 18 19 // SampleSquare randomly picks *num* unique points from arbitrary *width* square 20 // and returns them as samples. 21 func SampleSquare(squareWidth uint32, num int) []Sample { 22 ss := newSquareSampler(squareWidth, num) 23 ss.sample(num) 24 return ss.samples() 25 } 26 27 // Leaf returns leaf info needed for retrieval using data provided with DAHeader. 28 func (s Sample) Leaf(dah *types.DataAvailabilityHeader) (cid.Cid, uint32, error) { 29 var ( 30 leaf uint32 31 root namespace.IntervalDigest 32 ) 33 34 // spread leaves retrieval from both Row and Column roots 35 if randUint32(2) == 0 { 36 root = dah.ColumnRoots[s.Col] 37 leaf = s.Row 38 } else { 39 root = dah.RowsRoots[s.Row] 40 leaf = s.Col 41 } 42 43 rootCid, err := plugin.CidFromNamespacedSha256(root.Bytes()) 44 if err != nil { 45 return cid.Undef, 0, err 46 } 47 48 return rootCid, leaf, nil 49 } 50 51 // Equals check whenever to samples are equal. 52 func (s Sample) Equals(to Sample) bool { 53 return s.Row == to.Row && s.Col == to.Col 54 } 55 56 type squareSampler struct { 57 squareWidth uint32 58 smpls map[Sample]struct{} 59 } 60 61 func newSquareSampler(squareWidth uint32, expectedSamples int) *squareSampler { 62 return &squareSampler{ 63 squareWidth: squareWidth, 64 smpls: make(map[Sample]struct{}, expectedSamples), 65 } 66 } 67 68 func (ss *squareSampler) sample(num int) { 69 if uint32(num) > ss.squareWidth*ss.squareWidth { 70 panic("number of samples must be less than square width") 71 } 72 73 done := 0 74 for done < num { 75 s := Sample{ 76 Row: randUint32(ss.squareWidth), 77 Col: randUint32(ss.squareWidth), 78 } 79 80 if _, ok := ss.smpls[s]; ok { 81 continue 82 } 83 84 done++ 85 ss.smpls[s] = struct{}{} 86 } 87 } 88 89 func (ss *squareSampler) samples() []Sample { 90 samples := make([]Sample, 0, len(ss.smpls)) 91 for s := range ss.smpls { 92 samples = append(samples, s) 93 } 94 return samples 95 } 96 97 func randUint32(max uint32) uint32 { 98 n, err := crand.Int(crand.Reader, big.NewInt(int64(max))) 99 if err != nil { 100 panic(err) // won't panic as rand.Reader is endless 101 } 102 103 return uint32(n.Int64()) 104 }