Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: fuzz share commitments #1749

Merged
merged 8 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ tools-stamp
__debug_bin
profile.out
testing/e2e/networks/*/
square/testdata
2 changes: 1 addition & 1 deletion pkg/proof/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
func TestNewTxInclusionProof(t *testing.T) {
blockTxs := testfactory.GenerateRandomTxs(50, 500).ToSliceOfBytes()
encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
blockTxs = append(blockTxs, blobfactory.RandBlobTxs(encCfg.TxConfig.TxEncoder(), 50, 500).ToSliceOfBytes()...)
blockTxs = append(blockTxs, blobfactory.RandBlobTxs(encCfg.TxConfig.TxEncoder(), 50, 1, 500).ToSliceOfBytes()...)
require.Len(t, blockTxs, 100)

type test struct {
Expand Down
8 changes: 8 additions & 0 deletions pkg/square/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@ func (b *Builder) GetWrappedPFB(txIndex int) (*coretypes.IndexWrapper, error) {
return b.pfbs[txIndex-len(b.txs)], nil
}

func (b *Builder) NumPFBs() int {
return len(b.pfbs)
}

func (b *Builder) NumTxs() int {
return len(b.txs) + len(b.pfbs)
}

func (b *Builder) canFit(shareNum int) bool {
return b.currentSize+shareNum <= b.maxCapacity
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/square/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,21 @@ func TestBuilderSquareSizeEstimation(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
txs := generateMixedTxs(tt.normalTxs, tt.pfbCount, tt.pfbSize)
txs := generateMixedTxs(tt.normalTxs, tt.pfbCount, 1, tt.pfbSize)
square, _, err := square.Build(txs, appconsts.DefaultMaxSquareSize)
require.NoError(t, err)
require.EqualValues(t, tt.expectedSquareSize, square.Size())
})
}
}

func generateMixedTxs(normalTxCount, pfbCount, pfbSize int) [][]byte {
return shuffle(generateOrderedTxs(normalTxCount, pfbCount, pfbSize))
func generateMixedTxs(normalTxCount, pfbCount, blobsPerPfb, blobSize int) [][]byte {
return shuffle(generateOrderedTxs(normalTxCount, pfbCount, blobsPerPfb, blobSize))
}

func generateOrderedTxs(normalTxCount, pfbCount, pfbSize int) [][]byte {
func generateOrderedTxs(normalTxCount, pfbCount, blobsPerPfb, blobSize int) [][]byte {
encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
pfbTxs := blobfactory.RandBlobTxs(encCfg.TxConfig.TxEncoder(), pfbCount, pfbSize)
pfbTxs := blobfactory.RandBlobTxs(encCfg.TxConfig.TxEncoder(), pfbCount, blobsPerPfb, blobSize)
normieTxs := blobfactory.GenerateManyRawSendTxs(encCfg.TxConfig, normalTxCount)
txs := append(append(
make([]coretypes.Tx, 0, len(pfbTxs)+len(normieTxs)),
Expand Down
17 changes: 15 additions & 2 deletions pkg/square/square_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
func BenchmarkSquareConstruct(b *testing.B) {
for _, txCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("txCount=%d", txCount), func(b *testing.B) {
txs := generateOrderedTxs(txCount/2, txCount/2, 1024)
txs := generateOrderedTxs(txCount/2, txCount/2, 1, 1024)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := square.Construct(txs, appconsts.DefaultMaxSquareSize)
require.NoError(b, err)
Expand All @@ -24,7 +25,19 @@ func BenchmarkSquareConstruct(b *testing.B) {
func BenchmarkSquareBuild(b *testing.B) {
for _, txCount := range []int{10, 100, 1000, 10000} {
b.Run(fmt.Sprintf("txCount=%d", txCount), func(b *testing.B) {
txs := generateMixedTxs(txCount/2, txCount/2, 1024)
txs := generateMixedTxs(txCount/2, txCount/2, 1, 1024)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := square.Build(txs, appconsts.DefaultMaxSquareSize)
require.NoError(b, err)
}
})
}
const txCount = 10
for _, blobSize := range []int{10, 100, 1000, 10000} {
b.Run(fmt.Sprintf("blobSize=%d", blobSize), func(b *testing.B) {
txs := generateMixedTxs(0, txCount, 1, blobSize)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := square.Build(txs, appconsts.DefaultMaxSquareSize)
require.NoError(b, err)
Expand Down
72 changes: 72 additions & 0 deletions pkg/square/square_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package square_test

import (
"testing"

"github.com/celestiaorg/celestia-app/app"
"github.com/celestiaorg/celestia-app/app/encoding"
"github.com/celestiaorg/celestia-app/pkg/appconsts"
"github.com/celestiaorg/celestia-app/pkg/da"
"github.com/celestiaorg/celestia-app/pkg/inclusion"
"github.com/celestiaorg/celestia-app/pkg/shares"
"github.com/celestiaorg/celestia-app/pkg/square"
blob "github.com/celestiaorg/celestia-app/x/blob/types"
"github.com/celestiaorg/rsmt2d"
"github.com/stretchr/testify/require"
)

// FuzzSquare uses fuzzing to test the following:
// - That neither `Construct` or `Reconstruct` panics
// - That `Construct` never errors
// - That `Reconstruct` never errors from the input of `Construct`'s output
// - That both `Construct` and `Reconstruct` return the same square
// - That the square can be extended and a data availability header can be generated
// - That each share commitment in each PFB can be used to verify the inclusion of the blob it corresponds to.
func FuzzSquare(f *testing.F) {
var (
normalTxCount uint = 12
pfbCount uint = 91
blobsPerPfb uint = 2
blobSize uint = 812
)
f.Add(normalTxCount, pfbCount, blobsPerPfb, blobSize)
f.Fuzz(func(t *testing.T, normalTxCount, pfbCount, blobsPerPfb, blobSize uint) {
// ignore invalid values
if pfbCount > 0 && (blobSize == 0 || blobsPerPfb == 0) {
t.Skip()
}
txs := generateMixedTxs(int(normalTxCount), int(pfbCount), int(blobsPerPfb), int(blobSize))
s, orderedTxs, err := square.Build(txs, appconsts.DefaultMaxSquareSize)
require.NoError(t, err)
s2, err := square.Construct(orderedTxs, appconsts.DefaultMaxSquareSize)
require.NoError(t, err)
require.True(t, s.Equals(s2))

cacher := inclusion.NewSubtreeCacher(uint64(s.Size()))
eds, err := rsmt2d.ComputeExtendedDataSquare(shares.ToBytes(s), appconsts.DefaultCodec(), cacher.Constructor)
require.NoError(t, err)
dah := da.NewDataAvailabilityHeader(eds)

decoder := encoding.MakeConfig(app.ModuleEncodingRegisters...).TxConfig.TxDecoder()

builder, err := square.NewBuilder(appconsts.DefaultMaxSquareSize, orderedTxs...)
require.NoError(t, err)
totalPfbs := builder.NumPFBs()
totalNormalTxs := builder.NumTxs() - totalPfbs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional] an exported function on the builder for normal txs: builder.NumNormalTxs()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll wait for the need to arise first

for pfbIndex := 0; pfbIndex < totalPfbs; pfbIndex++ {
wpfb, err := builder.GetWrappedPFB(pfbIndex + totalNormalTxs)
require.NoError(t, err)
tx, err := decoder(wpfb.Tx)
require.NoError(t, err)

pfb, ok := tx.GetMsgs()[0].(*blob.MsgPayForBlobs)
require.True(t, ok)

for blobIndex, shareIndex := range wpfb.ShareIndexes {
commitment, err := inclusion.GetCommitment(cacher, dah, int(shareIndex), shares.SparseSharesNeeded(pfb.BlobSizes[blobIndex]))
require.NoError(t, err)
require.Equal(t, pfb.ShareCommitments[blobIndex], commitment)
}
}
})
}
35 changes: 2 additions & 33 deletions pkg/square/square_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,10 @@ import (
coretypes "github.com/tendermint/tendermint/types"
)

// FuzzSquareConstruction uses fuzzing to test the following:
// - That neither `Construct` or `Reconstruct` panics
// - That `Construct` never errors
// - That `Reconstruct` never errors from the input of `Construct`'s output
// - That both `Construct` and `Reconstruct` return the same square
// - That the square can be extended and a data availability header can be generated
func FuzzSquareBuildAndConstruction(f *testing.F) {
var (
normalTxCount uint = 123
pfbCount uint = 217
pfbSize uint = 8
)
f.Add(normalTxCount, pfbCount, pfbSize)
f.Fuzz(func(t *testing.T, normalTxCount uint, pfbCount uint, pfbSize uint) {
// ignore invalid values
if pfbCount > 0 && pfbSize == 0 {
t.Skip()
}
txs := generateMixedTxs(int(normalTxCount), int(pfbCount), int(pfbSize))
s, newTxs, err := square.Build(txs, appconsts.DefaultMaxSquareSize)
require.NoError(t, err)
s2, err := square.Construct(newTxs, appconsts.DefaultMaxSquareSize)
require.NoError(t, err)
require.True(t, s.Equals(s2))

eds, err := da.ExtendShares(shares.ToBytes(s))
require.NoError(t, err)
_ = da.NewDataAvailabilityHeader(eds)
})
}

func TestSquareConstruction(t *testing.T) {
encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
sendTxs := blobfactory.GenerateManyRawSendTxs(encCfg.TxConfig, 10)
pfbTxs := blobfactory.RandBlobTxs(encCfg.TxConfig.TxEncoder(), 10, 100)
pfbTxs := blobfactory.RandBlobTxs(encCfg.TxConfig.TxEncoder(), 10, 1, 1024)
t.Run("normal transactions after PFB trasactions", func(t *testing.T) {
txs := append(sendTxs[:5], append(pfbTxs, sendTxs[5:]...)...)
_, err := square.Construct(coretypes.Txs(txs).ToSliceOfBytes(), appconsts.DefaultMaxSquareSize)
Expand Down Expand Up @@ -368,7 +337,7 @@ func TestSquareBlobShareRange(t *testing.T) {

func TestSquareShareCommitments(t *testing.T) {
const numTxs = 10
txs := generateOrderedTxs(numTxs, numTxs, 5)
txs := generateOrderedTxs(numTxs, numTxs, 3, 800)
builder, err := square.NewBuilder(appconsts.DefaultMaxSquareSize, txs...)
require.NoError(t, err)

Expand Down
4 changes: 2 additions & 2 deletions test/util/blobfactory/payforblob_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func RandBlobTxsWithAccounts(
return txs
}

func RandBlobTxs(enc sdk.TxEncoder, count, size int) coretypes.Txs {
func RandBlobTxs(enc sdk.TxEncoder, count, blobsPerTx, size int) coretypes.Txs {
const acc = "signer"
kr := testfactory.GenerateKeyring(acc)
signer := blobtypes.NewKeyringSigner(kr, acc, "chainid")
Expand All @@ -235,7 +235,7 @@ func RandBlobTxs(enc sdk.TxEncoder, count, size int) coretypes.Txs {

txs := make([]coretypes.Tx, count)
for i := 0; i < count; i++ {
msg, blobs := RandMsgPayForBlobsWithSigner(addr.String(), size, 1)
msg, blobs := RandMsgPayForBlobsWithSigner(addr.String(), size, blobsPerTx)
builder := signer.NewTxBuilder(opts...)
stx, err := signer.BuildSignedTx(builder, msg)
if err != nil {
Expand Down