From 1ef39887091dcc3c3cbe078d630dca8d50c5f3ad Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Tue, 2 Jul 2024 16:27:07 +0200 Subject: [PATCH] chore: internalize unneeded go apis (#92) This PR does an initial pass of the `share` repo and internalizes things like test methods or the `Builder` struct that should not be public. --------- Co-authored-by: Rootul P --- README.md | 1 - inclusion/blob_share_commitment_rules.go | 27 ++++- inclusion/blob_share_commitment_rules_test.go | 47 +++++++- inclusion/commitment.go | 2 +- share/compact_shares_test.go | 61 +++++++++-- share/padding.go | 2 +- share/powers_of_two.go | 44 -------- share/powers_of_two_test.go | 101 ------------------ share/share_builder.go | 44 ++++---- share/share_builder_test.go | 14 +-- share/share_sequence_test.go | 2 +- share/split_compact_shares.go | 8 +- share/split_sparse_shares.go | 4 +- share/utils.go | 52 --------- share/utils_test.go | 2 +- square/builder.go | 8 +- square/square.go | 12 ++- square/square_test.go | 2 +- 18 files changed, 177 insertions(+), 256 deletions(-) delete mode 100644 share/powers_of_two.go delete mode 100644 share/powers_of_two_test.go diff --git a/README.md b/README.md index d4dee2d..6d64067 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ Package | Description ----------|--------------------------------------------------------------------------------------------------------------------- inclusion | Package inclusion contains functions to generate the blob share commitment from a given blob. -merkle | Package merkle computes a deterministic minimal height Merkle tree hash. share | Package share contains the Share data structure. square | Package square implements the logic to construct the original data square based on a list of transactions. diff --git a/inclusion/blob_share_commitment_rules.go b/inclusion/blob_share_commitment_rules.go index c568a38..f51bae7 100644 --- a/inclusion/blob_share_commitment_rules.go +++ b/inclusion/blob_share_commitment_rules.go @@ -1,9 +1,9 @@ package inclusion import ( + "fmt" "math" - "github.com/celestiaorg/go-square/share" "golang.org/x/exp/constraints" ) @@ -48,10 +48,31 @@ func RoundUpByMultipleOf(cursor, v int) int { return ((cursor / v) + 1) * v } +// RoundUpPowerOfTwo returns the next power of two greater than or equal to input. +func RoundUpPowerOfTwo[I constraints.Integer](input I) I { + var result I = 1 + for result < input { + result <<= 1 + } + return result +} + +// RoundDownPowerOfTwo returns the next power of two less than or equal to input. +func RoundDownPowerOfTwo[I constraints.Integer](input I) (I, error) { + if input <= 0 { + return 0, fmt.Errorf("input %v must be positive", input) + } + roundedUp := RoundUpPowerOfTwo(input) + if roundedUp == input { + return roundedUp, nil + } + return roundedUp / 2, nil +} + // BlobMinSquareSize returns the minimum square size that can contain shareCount // number of shares. func BlobMinSquareSize(shareCount int) int { - return share.RoundUpPowerOfTwo(int(math.Ceil(math.Sqrt(float64(shareCount))))) + return RoundUpPowerOfTwo(int(math.Ceil(math.Sqrt(float64(shareCount))))) } // SubTreeWidth returns the maximum number of leaves per subtree in the share @@ -69,7 +90,7 @@ func SubTreeWidth(shareCount, subtreeRootThreshold int) int { // use a power of two equal to or larger than the multiple of the subtree // root threshold - s = share.RoundUpPowerOfTwo(s) + s = RoundUpPowerOfTwo(s) // use the minimum of the subtree width and the min square size, this // gurarantees that a valid value is returned diff --git a/inclusion/blob_share_commitment_rules_test.go b/inclusion/blob_share_commitment_rules_test.go index f431f87..efb3708 100644 --- a/inclusion/blob_share_commitment_rules_test.go +++ b/inclusion/blob_share_commitment_rules_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/celestiaorg/go-square/inclusion" - "github.com/celestiaorg/go-square/share" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const ( @@ -133,7 +133,7 @@ func TestNextShareIndex(t *testing.T) { name: "at threshold", cursor: 11, blobLen: defaultSubtreeRootThreshold, - squareSize: share.RoundUpPowerOfTwo(defaultSubtreeRootThreshold), + squareSize: inclusion.RoundUpPowerOfTwo(defaultSubtreeRootThreshold), expectedIndex: 11, }, { @@ -257,6 +257,28 @@ func TestRoundUpByMultipleOf(t *testing.T) { } } +func TestRoundUpPowerOfTwo(t *testing.T) { + type testCase struct { + input int + want int + } + testCases := []testCase{ + {input: -1, want: 1}, + {input: 0, want: 1}, + {input: 1, want: 1}, + {input: 2, want: 2}, + {input: 4, want: 4}, + {input: 5, want: 8}, + {input: 8, want: 8}, + {input: 11, want: 16}, + {input: 511, want: 512}, + } + for _, tc := range testCases { + got := inclusion.RoundUpPowerOfTwo(tc.input) + assert.Equal(t, tc.want, got) + } +} + func TestBlobMinSquareSize(t *testing.T) { type testCase struct { shareCount int @@ -366,3 +388,24 @@ func TestSubTreeWidth(t *testing.T) { }) } } + +func TestRoundDownPowerOfTwo(t *testing.T) { + type testCase struct { + input int + want int + } + testCases := []testCase{ + {input: 1, want: 1}, + {input: 2, want: 2}, + {input: 4, want: 4}, + {input: 5, want: 4}, + {input: 8, want: 8}, + {input: 11, want: 8}, + {input: 511, want: 256}, + } + for _, tc := range testCases { + got, err := inclusion.RoundDownPowerOfTwo(tc.input) + require.NoError(t, err) + assert.Equal(t, tc.want, got) + } +} diff --git a/inclusion/commitment.go b/inclusion/commitment.go index 22a5105..ec3297b 100644 --- a/inclusion/commitment.go +++ b/inclusion/commitment.go @@ -95,7 +95,7 @@ func MerkleMountainRangeSizes(totalSize, maxTreeSize uint64) ([]uint64, error) { treeSizes = append(treeSizes, maxTreeSize) totalSize -= maxTreeSize case totalSize < maxTreeSize: - treeSize, err := sh.RoundDownPowerOfTwo(totalSize) + treeSize, err := RoundDownPowerOfTwo(totalSize) if err != nil { return treeSizes, err } diff --git a/share/compact_shares_test.go b/share/compact_shares_test.go index 321debc..294f68f 100644 --- a/share/compact_shares_test.go +++ b/share/compact_shares_test.go @@ -1,9 +1,11 @@ package share import ( + "bytes" "context" "crypto/sha256" "fmt" + "math/rand" "testing" "time" @@ -15,7 +17,7 @@ func TestCompactShareSplitter(t *testing.T) { // note that this test is mainly for debugging purposes, the main round trip // tests occur in TestMerge and Test_processCompactShares css := NewCompactShareSplitter(TxNamespace, ShareVersionZero) - txs := GenerateRandomTxs(33, 200) + txs := generateRandomTxs(33, 200) for _, tx := range txs { err := css.WriteTx(tx) require.NoError(t, err) @@ -73,7 +75,7 @@ func Test_processCompactShares(t *testing.T) { // run the tests with identically sized txs t.Run(fmt.Sprintf("%s idendically sized", tc.name), func(t *testing.T) { - txs := GenerateRandomTxs(tc.txCount, tc.txSize) + txs := generateRandomTxs(tc.txCount, tc.txSize) shares, _, _, err := SplitTxs(txs) require.NoError(t, err) @@ -91,7 +93,7 @@ func Test_processCompactShares(t *testing.T) { // run the same tests using randomly sized txs with caps of tc.txSize t.Run(fmt.Sprintf("%s randomly sized", tc.name), func(t *testing.T) { - txs := GenerateRandomlySizedTxs(tc.txCount, tc.txSize) + txs := generateRandomlySizedTxs(tc.txCount, tc.txSize) txShares, _, _, err := SplitTxs(txs) require.NoError(t, err) @@ -109,7 +111,7 @@ func Test_processCompactShares(t *testing.T) { } func TestAllSplit(t *testing.T) { - txs := GenerateRandomlySizedTxs(1000, 150) + txs := generateRandomlySizedTxs(1000, 150) txShares, _, _, err := SplitTxs(txs) require.NoError(t, err) resTxs, err := ParseTxs(txShares) @@ -118,21 +120,46 @@ func TestAllSplit(t *testing.T) { } func TestParseRandomOutOfContextShares(t *testing.T) { - txs := GenerateRandomlySizedTxs(1000, 150) + txs := generateRandomlySizedTxs(1000, 150) txShares, _, _, err := SplitTxs(txs) require.NoError(t, err) for i := 0; i < 1000; i++ { - start, length := GetRandomSubSlice(len(txShares)) + start, length := getRandomSubSlice(len(txShares)) randomRange := NewRange(start, start+length) resTxs, err := ParseTxs(txShares[randomRange.Start:randomRange.End]) require.NoError(t, err) - assert.True(t, CheckSubArray(txs, resTxs)) + assert.True(t, checkSubArray(txs, resTxs)) } } +// getRandomSubSlice returns two integers representing a randomly sized range in the interval [0, size] +func getRandomSubSlice(size int) (start int, length int) { + length = rand.Intn(size + 1) + start = rand.Intn(size - length + 1) + return start, length +} + +// checkSubArray returns whether subTxList is a subarray of txList +func checkSubArray(txList [][]byte, subTxList [][]byte) bool { + for i := 0; i <= len(txList)-len(subTxList); i++ { + j := 0 + for j = 0; j < len(subTxList); j++ { + tx := txList[i+j] + subTx := subTxList[j] + if !bytes.Equal(tx, subTx) { + break + } + } + if j == len(subTxList) { + return true + } + } + return false +} + func TestParseOutOfContextSharesUsingShareRanges(t *testing.T) { - txs := GenerateRandomlySizedTxs(1000, 150) + txs := generateRandomlySizedTxs(1000, 150) txShares, _, shareRanges, err := SplitTxs(txs) require.NoError(t, err) @@ -152,7 +179,7 @@ func TestParseOutOfContextSharesUsingShareRanges(t *testing.T) { func TestCompactShareContainsInfoByte(t *testing.T) { css := NewCompactShareSplitter(TxNamespace, ShareVersionZero) - txs := GenerateRandomTxs(1, ContinuationCompactShareContentSize/4) + txs := generateRandomTxs(1, ContinuationCompactShareContentSize/4) for _, tx := range txs { err := css.WriteTx(tx) @@ -174,7 +201,7 @@ func TestCompactShareContainsInfoByte(t *testing.T) { func TestContiguousCompactShareContainsInfoByte(t *testing.T) { css := NewCompactShareSplitter(TxNamespace, ShareVersionZero) - txs := GenerateRandomTxs(1, ContinuationCompactShareContentSize*4) + txs := generateRandomTxs(1, ContinuationCompactShareContentSize*4) for _, tx := range txs { err := css.WriteTx(tx) @@ -200,7 +227,7 @@ func Test_parseCompactSharesErrors(t *testing.T) { shares []Share } - txs := GenerateRandomTxs(2, ContinuationCompactShareContentSize*4) + txs := generateRandomTxs(2, ContinuationCompactShareContentSize*4) txShares, _, _, err := SplitTxs(txs) require.NoError(t, err) rawShares := ToBytes(txShares) @@ -229,3 +256,15 @@ func Test_parseCompactSharesErrors(t *testing.T) { }) } } + +func generateRandomlySizedTxs(count, maxSize int) [][]byte { + txs := make([][]byte, count) + for i := 0; i < count; i++ { + size := rand.Intn(maxSize) + if size == 0 { + size = 1 + } + txs[i] = generateRandomTxs(1, size)[0] + } + return txs +} diff --git a/share/padding.go b/share/padding.go index 2a02e28..9d0c623 100644 --- a/share/padding.go +++ b/share/padding.go @@ -10,7 +10,7 @@ import ( // provided should be the namespace and shareVersion of the blob that precedes // this padding in the data square. func NamespacePaddingShare(ns Namespace, shareVersion uint8) (Share, error) { - b, err := NewBuilder(ns, shareVersion, true) + b, err := newBuilder(ns, shareVersion, true) if err != nil { return Share{}, err } diff --git a/share/powers_of_two.go b/share/powers_of_two.go deleted file mode 100644 index 8ee5919..0000000 --- a/share/powers_of_two.go +++ /dev/null @@ -1,44 +0,0 @@ -package share - -import ( - "fmt" - - "golang.org/x/exp/constraints" -) - -// RoundUpPowerOfTwo returns the next power of two greater than or equal to input. -func RoundUpPowerOfTwo[I constraints.Integer](input I) I { - var result I = 1 - for result < input { - result <<= 1 - } - return result -} - -// RoundDownPowerOfTwo returns the next power of two less than or equal to input. -func RoundDownPowerOfTwo[I constraints.Integer](input I) (I, error) { - if input <= 0 { - return 0, fmt.Errorf("input %v must be positive", input) - } - roundedUp := RoundUpPowerOfTwo(input) - if roundedUp == input { - return roundedUp, nil - } - return roundedUp / 2, nil -} - -// RoundUpPowerOfTwoStrict returns the next power of two that is strictly greater than input. -func RoundUpPowerOfTwoStrict[I constraints.Integer](input I) I { - result := RoundUpPowerOfTwo(input) - - // round the result up to the next power of two if is equal to the input - if result == input { - return result * 2 - } - return result -} - -// IsPowerOfTwo returns true if input is a power of two. -func IsPowerOfTwo[I constraints.Integer](input I) bool { - return input&(input-1) == 0 && input != 0 -} diff --git a/share/powers_of_two_test.go b/share/powers_of_two_test.go deleted file mode 100644 index ed7b2eb..0000000 --- a/share/powers_of_two_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package share - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestRoundUpPowerOfTwo(t *testing.T) { - type testCase struct { - input int - want int - } - testCases := []testCase{ - {input: -1, want: 1}, - {input: 0, want: 1}, - {input: 1, want: 1}, - {input: 2, want: 2}, - {input: 4, want: 4}, - {input: 5, want: 8}, - {input: 8, want: 8}, - {input: 11, want: 16}, - {input: 511, want: 512}, - } - for _, tc := range testCases { - got := RoundUpPowerOfTwo(tc.input) - assert.Equal(t, tc.want, got) - } -} - -func TestRoundDownPowerOfTwo(t *testing.T) { - type testCase struct { - input int - want int - } - testCases := []testCase{ - {input: 1, want: 1}, - {input: 2, want: 2}, - {input: 4, want: 4}, - {input: 5, want: 4}, - {input: 8, want: 8}, - {input: 11, want: 8}, - {input: 511, want: 256}, - } - for _, tc := range testCases { - got, err := RoundDownPowerOfTwo(tc.input) - require.NoError(t, err) - assert.Equal(t, tc.want, got) - } -} - -func TestRoundUpPowerOfTwoStrict(t *testing.T) { - type testCase struct { - input int - want int - } - testCases := []testCase{ - {input: -1, want: 1}, - {input: 0, want: 1}, - {input: 1, want: 2}, - {input: 2, want: 4}, - {input: 4, want: 8}, - {input: 5, want: 8}, - {input: 8, want: 16}, - {input: 11, want: 16}, - {input: 511, want: 512}, - } - for _, tc := range testCases { - got := RoundUpPowerOfTwoStrict(tc.input) - assert.Equal(t, tc.want, got) - } -} - -func TestIsPowerOfTwoU(t *testing.T) { - type test struct { - input uint64 - want bool - } - tests := []test{ - // powers of two - {input: 1, want: true}, - {input: 2, want: true}, - {input: 4, want: true}, - {input: 8, want: true}, - {input: 16, want: true}, - {input: 32, want: true}, - {input: 64, want: true}, - {input: 128, want: true}, - {input: 256, want: true}, - // not powers of two - {input: 0, want: false}, - {input: 3, want: false}, - {input: 12, want: false}, - {input: 79, want: false}, - } - for _, tt := range tests { - got := IsPowerOfTwo(tt.input) - assert.Equal(t, tt.want, got) - } -} diff --git a/share/share_builder.go b/share/share_builder.go index 146826a..65463b9 100644 --- a/share/share_builder.go +++ b/share/share_builder.go @@ -5,7 +5,7 @@ import ( "errors" ) -type Builder struct { +type builder struct { namespace Namespace shareVersion uint8 isFirstShare bool @@ -13,15 +13,15 @@ type Builder struct { rawShareData []byte } -func NewEmptyBuilder() *Builder { - return &Builder{ +func newEmptyBuilder() *builder { + return &builder{ rawShareData: make([]byte, 0, ShareSize), } } -// NewBuilder returns a new share builder. -func NewBuilder(ns Namespace, shareVersion uint8, isFirstShare bool) (*Builder, error) { - b := Builder{ +// newBuilder returns a new share builder. +func newBuilder(ns Namespace, shareVersion uint8, isFirstShare bool) (*builder, error) { + b := builder{ namespace: ns, shareVersion: shareVersion, isFirstShare: isFirstShare, @@ -34,23 +34,23 @@ func NewBuilder(ns Namespace, shareVersion uint8, isFirstShare bool) (*Builder, } // init initializes the share builder by populating rawShareData. -func (b *Builder) init() error { +func (b *builder) init() error { if b.isCompactShare { return b.prepareCompactShare() } return b.prepareSparseShare() } -func (b *Builder) AvailableBytes() int { +func (b *builder) AvailableBytes() int { return ShareSize - len(b.rawShareData) } -func (b *Builder) ImportRawShare(rawBytes []byte) *Builder { +func (b *builder) ImportRawShare(rawBytes []byte) *builder { b.rawShareData = rawBytes return b } -func (b *Builder) AddData(rawData []byte) (rawDataLeftOver []byte) { +func (b *builder) AddData(rawData []byte) (rawDataLeftOver []byte) { // find the len left in the pending share pendingLeft := ShareSize - len(b.rawShareData) @@ -71,12 +71,12 @@ func (b *Builder) AddData(rawData []byte) (rawDataLeftOver []byte) { return rawData[pendingLeft:] } -func (b *Builder) Build() (*Share, error) { +func (b *builder) Build() (*Share, error) { return NewShare(b.rawShareData) } // IsEmptyShare returns true if no data has been written to the share -func (b *Builder) IsEmptyShare() bool { +func (b *builder) IsEmptyShare() bool { expectedLen := NamespaceSize + ShareInfoBytes if b.isCompactShare { expectedLen += ShareReservedBytes @@ -87,13 +87,13 @@ func (b *Builder) IsEmptyShare() bool { return len(b.rawShareData) == expectedLen } -func (b *Builder) ZeroPadIfNecessary() (bytesOfPadding int) { +func (b *builder) ZeroPadIfNecessary() (bytesOfPadding int) { b.rawShareData, bytesOfPadding = zeroPadIfNecessary(b.rawShareData, ShareSize) return bytesOfPadding } // isEmptyReservedBytes returns true if the reserved bytes are empty. -func (b *Builder) isEmptyReservedBytes() (bool, error) { +func (b *builder) isEmptyReservedBytes() (bool, error) { indexOfReservedBytes := b.indexOfReservedBytes() reservedBytes, err := ParseReservedBytes(b.rawShareData[indexOfReservedBytes : indexOfReservedBytes+ShareReservedBytes]) if err != nil { @@ -103,7 +103,7 @@ func (b *Builder) isEmptyReservedBytes() (bool, error) { } // indexOfReservedBytes returns the index of the reserved bytes in the share. -func (b *Builder) indexOfReservedBytes() int { +func (b *builder) indexOfReservedBytes() int { if b.isFirstShare { // if the share is the first share, the reserved bytes follow the namespace, info byte, and sequence length return NamespaceSize + ShareInfoBytes + SequenceLenBytes @@ -113,7 +113,7 @@ func (b *Builder) indexOfReservedBytes() int { } // indexOfInfoBytes returns the index of the InfoBytes. -func (b *Builder) indexOfInfoBytes() int { +func (b *builder) indexOfInfoBytes() int { // the info byte is immediately after the namespace return NamespaceSize } @@ -121,7 +121,7 @@ func (b *Builder) indexOfInfoBytes() int { // MaybeWriteReservedBytes will be a no-op if the reserved bytes // have already been populated. If the reserved bytes are empty, it will write // the location of the next unit of data to the reserved bytes. -func (b *Builder) MaybeWriteReservedBytes() error { +func (b *builder) MaybeWriteReservedBytes() error { if !b.isCompactShare { return errors.New("this is not a compact share") } @@ -149,7 +149,7 @@ func (b *Builder) MaybeWriteReservedBytes() error { } // WriteSequenceLen writes the sequence length to the first share. -func (b *Builder) WriteSequenceLen(sequenceLen uint32) error { +func (b *builder) WriteSequenceLen(sequenceLen uint32) error { if b == nil { return errors.New("the builder object is not initialized (is nil)") } @@ -167,7 +167,7 @@ func (b *Builder) WriteSequenceLen(sequenceLen uint32) error { } // WriteSigner writes the signer's information to the share. -func (b *Builder) WriteSigner(signer []byte) { +func (b *builder) WriteSigner(signer []byte) { // only write the signer if it is the first share and the share version is 1 if b == nil || !b.isFirstShare || b.shareVersion != ShareVersionOne { return @@ -178,7 +178,7 @@ func (b *Builder) WriteSigner(signer []byte) { } // FlipSequenceStart flips the sequence start indicator of the share provided -func (b *Builder) FlipSequenceStart() { +func (b *builder) FlipSequenceStart() { infoByteIndex := b.indexOfInfoBytes() // the sequence start indicator is the last bit of the info byte so flip the @@ -186,7 +186,7 @@ func (b *Builder) FlipSequenceStart() { b.rawShareData[infoByteIndex] ^= 0x01 } -func (b *Builder) prepareCompactShare() error { +func (b *builder) prepareCompactShare() error { shareData := make([]byte, 0, ShareSize) infoByte, err := NewInfoByte(b.shareVersion, b.isFirstShare) if err != nil { @@ -209,7 +209,7 @@ func (b *Builder) prepareCompactShare() error { return nil } -func (b *Builder) prepareSparseShare() error { +func (b *builder) prepareSparseShare() error { shareData := make([]byte, 0, ShareSize) infoByte, err := NewInfoByte(b.shareVersion, b.isFirstShare) if err != nil { diff --git a/share/share_builder_test.go b/share/share_builder_test.go index 803cd72..b7959f8 100644 --- a/share/share_builder_test.go +++ b/share/share_builder_test.go @@ -12,7 +12,7 @@ import ( func TestShareBuilderIsEmptyShare(t *testing.T) { type testCase struct { name string - builder *Builder + builder *builder data []byte // input data want bool } @@ -80,7 +80,7 @@ func TestShareBuilderIsEmptyShare(t *testing.T) { func TestShareBuilderWriteSequenceLen(t *testing.T) { type testCase struct { name string - builder *Builder + builder *builder wantLen uint32 wantErr bool } @@ -119,7 +119,7 @@ func TestShareBuilderWriteSequenceLen(t *testing.T) { }, { name: "nil builder", - builder: &Builder{}, + builder: &builder{}, wantLen: 10, wantErr: true, }, @@ -145,7 +145,7 @@ func TestShareBuilderWriteSequenceLen(t *testing.T) { func TestShareBuilderAddData(t *testing.T) { type testCase struct { name string - builder *Builder + builder *builder data []byte // input data want []byte } @@ -287,7 +287,7 @@ func TestShareBuilderImportRawData(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - b := NewEmptyBuilder().ImportRawShare(tc.shareBytes) + b := newEmptyBuilder().ImportRawShare(tc.shareBytes) b.ZeroPadIfNecessary() builtShare, err := b.Build() if tc.wantErr { @@ -305,8 +305,8 @@ func TestShareBuilderImportRawData(t *testing.T) { } // mustNewBuilder returns a new builder with the given parameters. It fails the test if an error is encountered. -func mustNewBuilder(t *testing.T, ns Namespace, shareVersion uint8, isFirstShare bool) *Builder { - b, err := NewBuilder(ns, shareVersion, isFirstShare) +func mustNewBuilder(t *testing.T, ns Namespace, shareVersion uint8, isFirstShare bool) *builder { + b, err := newBuilder(ns, shareVersion, isFirstShare) require.NoError(t, err) return b } diff --git a/share/share_sequence_test.go b/share/share_sequence_test.go index 0629305..7279bc8 100644 --- a/share/share_sequence_test.go +++ b/share/share_sequence_test.go @@ -214,7 +214,7 @@ func Test_validSequenceLen(t *testing.T) { func generateValidSequence(t *testing.T) Sequence { css := NewCompactShareSplitter(TxNamespace, ShareVersionZero) - txs := GenerateRandomTxs(5, 200) + txs := generateRandomTxs(5, 200) for _, tx := range txs { err := css.WriteTx(tx) require.NoError(t, err) diff --git a/share/split_compact_shares.go b/share/split_compact_shares.go index aed0198..f182ff9 100644 --- a/share/split_compact_shares.go +++ b/share/split_compact_shares.go @@ -12,7 +12,7 @@ import ( type CompactShareSplitter struct { shares []Share // pendingShare Share - shareBuilder *Builder + shareBuilder *builder namespace Namespace done bool shareVersion uint8 @@ -26,7 +26,7 @@ type CompactShareSplitter struct { // NewCompactShareSplitter returns a CompactShareSplitter using the provided // namespace and shareVersion. func NewCompactShareSplitter(ns Namespace, shareVersion uint8) *CompactShareSplitter { - sb, err := NewBuilder(ns, shareVersion, true) + sb, err := newBuilder(ns, shareVersion, true) if err != nil { panic(err) } @@ -102,7 +102,7 @@ func (css *CompactShareSplitter) stackPending() error { css.shares = append(css.shares, *pendingShare) // Now we need to create a new builder - css.shareBuilder, err = NewBuilder(css.namespace, css.shareVersion, false) + css.shareBuilder, err = newBuilder(css.namespace, css.shareVersion, false) return err } @@ -160,7 +160,7 @@ func (css *CompactShareSplitter) writeSequenceLen(sequenceLen uint32) error { } // We may find a more efficient way to write seqLen - b, err := NewBuilder(css.namespace, css.shareVersion, true) + b, err := newBuilder(css.namespace, css.shareVersion, true) if err != nil { return err } diff --git a/share/split_sparse_shares.go b/share/split_sparse_shares.go index e7e257e..2778012 100644 --- a/share/split_sparse_shares.go +++ b/share/split_sparse_shares.go @@ -28,7 +28,7 @@ func (sss *SparseShareSplitter) Write(blob *Blob) error { rawData := blob.Data() blobNamespace := blob.Namespace() - b, err := NewBuilder(blobNamespace, blob.ShareVersion(), true) + b, err := newBuilder(blobNamespace, blob.ShareVersion(), true) if err != nil { return err } @@ -53,7 +53,7 @@ func (sss *SparseShareSplitter) Write(blob *Blob) error { } sss.shares = append(sss.shares, *share) - b, err = NewBuilder(blobNamespace, blob.ShareVersion(), false) + b, err = newBuilder(blobNamespace, blob.ShareVersion(), false) if err != nil { return err } diff --git a/share/utils.go b/share/utils.go index 1b9c52d..4bdb4f5 100644 --- a/share/utils.go +++ b/share/utils.go @@ -2,9 +2,7 @@ package share import ( "bytes" - crand "crypto/rand" "encoding/binary" - "math/rand" ) // DelimLen calculates the length of the delimiter for a given unit size @@ -91,53 +89,3 @@ func AvailableBytesFromSparseShares(n int) int { } return (n-1)*ContinuationSparseShareContentSize + FirstSparseShareContentSize } - -func GenerateRandomTxs(count, size int) [][]byte { - txs := make([][]byte, count) - for i := 0; i < count; i++ { - tx := make([]byte, size) - _, err := crand.Read(tx) - if err != nil { - panic(err) - } - txs[i] = tx - } - return txs -} - -func GenerateRandomlySizedTxs(count, maxSize int) [][]byte { - txs := make([][]byte, count) - for i := 0; i < count; i++ { - size := rand.Intn(maxSize) - if size == 0 { - size = 1 - } - txs[i] = GenerateRandomTxs(1, size)[0] - } - return txs -} - -// GetRandomSubSlice returns two integers representing a randomly sized range in the interval [0, size] -func GetRandomSubSlice(size int) (start int, length int) { - length = rand.Intn(size + 1) - start = rand.Intn(size - length + 1) - return start, length -} - -// CheckSubArray returns whether subTxList is a subarray of txList -func CheckSubArray(txList [][]byte, subTxList [][]byte) bool { - for i := 0; i <= len(txList)-len(subTxList); i++ { - j := 0 - for j = 0; j < len(subTxList); j++ { - tx := txList[i+j] - subTx := subTxList[j] - if !bytes.Equal(tx, subTx) { - break - } - } - if j == len(subTxList) { - return true - } - } - return false -} diff --git a/share/utils_test.go b/share/utils_test.go index fae12c5..2ee1120 100644 --- a/share/utils_test.go +++ b/share/utils_test.go @@ -38,7 +38,7 @@ func Test_zeroPadIfNecessary(t *testing.T) { func TestParseDelimiter(t *testing.T) { for i := uint64(0); i < 100; i++ { - tx := GenerateRandomTxs(1, int(i))[0] + tx := generateRandomTxs(1, int(i))[0] input, err := MarshalDelimitedTx(tx) if err != nil { panic(err) diff --git a/square/builder.go b/square/builder.go index 9d45fcb..190c4c0 100644 --- a/square/builder.go +++ b/square/builder.go @@ -8,6 +8,7 @@ import ( "github.com/celestiaorg/go-square/inclusion" "github.com/celestiaorg/go-square/share" + "golang.org/x/exp/constraints" "google.golang.org/protobuf/proto" ) @@ -34,7 +35,7 @@ func NewBuilder(maxSquareSize int, subtreeRootThreshold int, txs ...[]byte) (*Bu if maxSquareSize <= 0 { return nil, errors.New("max square size must be strictly positive") } - if !share.IsPowerOfTwo(maxSquareSize) { + if !IsPowerOfTwo(maxSquareSize) { return nil, errors.New("max square size must be a power of two") } builder := &Builder{ @@ -431,3 +432,8 @@ func worstCaseShareIndexes(blobs int) []uint32 { } return shareIndexes } + +// IsPowerOfTwo returns true if input is a power of two. +func IsPowerOfTwo[I constraints.Integer](input I) bool { + return input&(input-1) == 0 && input != 0 +} diff --git a/square/square.go b/square/square.go index 4fe5f35..292082a 100644 --- a/square/square.go +++ b/square/square.go @@ -8,6 +8,7 @@ import ( "math" "github.com/celestiaorg/go-square/share" + "golang.org/x/exp/constraints" ) // Build takes an arbitrary long list of (prioritized) transactions and builds a square that is never @@ -181,7 +182,16 @@ func (s Square) Size() int { // avoid breaking the api. In future versions there will not be a copy of this // code here. func Size(len int) int { - return share.RoundUpPowerOfTwo(int(math.Ceil(math.Sqrt(float64(len))))) + return RoundUpPowerOfTwo(int(math.Ceil(math.Sqrt(float64(len))))) +} + +// RoundUpPowerOfTwo returns the next power of two greater than or equal to input. +func RoundUpPowerOfTwo[I constraints.Integer](input I) I { + var result I = 1 + for result < input { + result <<= 1 + } + return result } // Equals returns true if two squares are equal diff --git a/square/square_test.go b/square/square_test.go index fab34b1..6e5ceb0 100644 --- a/square/square_test.go +++ b/square/square_test.go @@ -203,6 +203,6 @@ func TestSize(t *testing.T) { for i, tt := range tests { res := square.Size(tt.input) assert.Equal(t, tt.expect, res, i) - assert.True(t, share.IsPowerOfTwo(res)) + assert.True(t, square.IsPowerOfTwo(res)) } }