-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #270 from lazyledger/hlib/validate-avaiability
- Loading branch information
Showing
8 changed files
with
310 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package ipld | ||
|
||
import ( | ||
crand "crypto/rand" | ||
"math/big" | ||
|
||
"github.com/ipfs/go-cid" | ||
"github.com/lazyledger/nmt/namespace" | ||
|
||
"github.com/lazyledger/lazyledger-core/p2p/ipld/plugin/nodes" | ||
"github.com/lazyledger/lazyledger-core/types" | ||
) | ||
|
||
// Sample is a point in 2D space over square. | ||
type Sample struct { | ||
Row, Col uint32 | ||
|
||
// src defines the source for sampling, either from column(true) or row(false) root | ||
src bool | ||
} | ||
|
||
// SampleSquare randomly picks *num* unique points from arbitrary *width* square | ||
// and returns them as samples. | ||
func SampleSquare(squareWidth uint32, num int) []Sample { | ||
ss := newSquareSampler(squareWidth, num) | ||
ss.sample(num) | ||
return ss.samples() | ||
} | ||
|
||
// Leaf returns leaf info needed for retrieval using data provided with DAHeader. | ||
func (s Sample) Leaf(dah *types.DataAvailabilityHeader) (cid.Cid, uint32, error) { | ||
var ( | ||
leaf uint32 | ||
root namespace.IntervalDigest | ||
) | ||
|
||
// spread leaves retrieval from both Row and Column roots | ||
if s.src { | ||
root = dah.ColumnRoots[s.Col] | ||
leaf = s.Row | ||
} else { | ||
root = dah.RowsRoots[s.Row] | ||
leaf = s.Col | ||
} | ||
|
||
rootCid, err := nodes.CidFromNamespacedSha256(root.Bytes()) | ||
if err != nil { | ||
return cid.Undef, 0, err | ||
} | ||
|
||
return rootCid, leaf, nil | ||
} | ||
|
||
// Equals check whenever to samples are equal. | ||
func (s Sample) Equals(to Sample) bool { | ||
return s.Row == to.Row && s.Col == to.Col | ||
} | ||
|
||
type squareSampler struct { | ||
squareWidth uint32 | ||
smpls map[Sample]struct{} | ||
} | ||
|
||
func newSquareSampler(squareWidth uint32, expectedSamples int) *squareSampler { | ||
return &squareSampler{ | ||
squareWidth: squareWidth, | ||
smpls: make(map[Sample]struct{}, expectedSamples), | ||
} | ||
} | ||
|
||
func (ss *squareSampler) sample(num int) { | ||
if uint32(num) > ss.squareWidth*ss.squareWidth { | ||
panic("number of samples must be less than square width") | ||
} | ||
|
||
done := 0 | ||
for done < num { | ||
s := Sample{ | ||
Row: randUint32(ss.squareWidth), | ||
Col: randUint32(ss.squareWidth), | ||
src: randUint32(2) == 0, | ||
} | ||
|
||
if _, ok := ss.smpls[s]; ok { | ||
continue | ||
} | ||
|
||
done++ | ||
ss.smpls[s] = struct{}{} | ||
} | ||
} | ||
|
||
func (ss *squareSampler) samples() []Sample { | ||
samples := make([]Sample, 0, len(ss.smpls)) | ||
for s := range ss.smpls { | ||
samples = append(samples, s) | ||
} | ||
return samples | ||
} | ||
|
||
func randUint32(max uint32) uint32 { | ||
n, err := crand.Int(crand.Reader, big.NewInt(int64(max))) | ||
if err != nil { | ||
panic(err) // won't panic as rand.Reader is endless | ||
} | ||
|
||
return uint32(n.Int64()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package ipld | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestSampleSquare(t *testing.T) { | ||
tests := []struct { | ||
width uint32 | ||
samples int | ||
}{ | ||
{width: 10, samples: 5}, | ||
{width: 500, samples: 90}, | ||
} | ||
|
||
for _, tt := range tests { | ||
ss := SampleSquare(tt.width, tt.samples) | ||
assert.Len(t, ss, tt.samples) | ||
// check points are within width | ||
for _, s := range ss { | ||
assert.Less(t, s.Row, tt.width) | ||
assert.Less(t, s.Col, tt.width) | ||
} | ||
// checks samples are not equal | ||
for i, s1 := range ss { | ||
for j, s2 := range ss { | ||
if i != j { | ||
assert.False(t, s1.Equals(s2)) | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.