github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/p2p/ipld/write_test.go (about)

     1  package ipld
     2  
     3  import (
     4  	"context"
     5  	mrand "math/rand"
     6  	"testing"
     7  	"time"
     8  
     9  	mdutils "github.com/ipfs/go-merkledag/test"
    10  	"github.com/lazyledger/nmt"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	abci "github.com/lazyledger/lazyledger-core/abci/types"
    15  	"github.com/lazyledger/lazyledger-core/crypto/tmhash"
    16  	"github.com/lazyledger/lazyledger-core/ipfs"
    17  	"github.com/lazyledger/lazyledger-core/ipfs/plugin"
    18  	"github.com/lazyledger/lazyledger-core/libs/log"
    19  	tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types"
    20  	"github.com/lazyledger/lazyledger-core/types"
    21  	"github.com/lazyledger/lazyledger-core/types/consts"
    22  )
    23  
    24  func TestPutBlock(t *testing.T) {
    25  	logger := log.TestingLogger()
    26  	dag := mdutils.Mock()
    27  	croute := ipfs.MockRouting()
    28  
    29  	maxOriginalSquareSize := consts.MaxSquareSize / 2
    30  	maxShareCount := maxOriginalSquareSize * maxOriginalSquareSize
    31  
    32  	testCases := []struct {
    33  		name      string
    34  		blockData types.Data
    35  		expectErr bool
    36  		errString string
    37  	}{
    38  		{"no leaves", generateRandomMsgOnlyData(0), false, ""},
    39  		{"single leaf", generateRandomMsgOnlyData(1), false, ""},
    40  		{"16 leaves", generateRandomMsgOnlyData(16), false, ""},
    41  		{"max square size", generateRandomMsgOnlyData(maxShareCount), false, ""},
    42  	}
    43  	ctx := context.Background()
    44  	for _, tc := range testCases {
    45  		tc := tc
    46  
    47  		block := &types.Block{Data: tc.blockData}
    48  
    49  		t.Run(tc.name, func(t *testing.T) {
    50  			err := PutBlock(ctx, dag, block, croute, logger)
    51  			if tc.expectErr {
    52  				require.Error(t, err)
    53  				require.Contains(t, err.Error(), tc.errString)
    54  				return
    55  			}
    56  
    57  			require.NoError(t, err)
    58  
    59  			timeoutCtx, cancel := context.WithTimeout(ctx, time.Second)
    60  			defer cancel()
    61  
    62  			block.Hash()
    63  			for _, rowRoot := range block.DataAvailabilityHeader.RowsRoots.Bytes() {
    64  				// recreate the cids using only the computed roots
    65  				cid, err := plugin.CidFromNamespacedSha256(rowRoot)
    66  				if err != nil {
    67  					t.Error(err)
    68  				}
    69  
    70  				// retrieve the data from IPFS
    71  				_, err = dag.Get(timeoutCtx, cid)
    72  				if err != nil {
    73  					t.Errorf("Root not found: %s", cid.String())
    74  				}
    75  			}
    76  		})
    77  	}
    78  }
    79  
    80  type preprocessingApp struct {
    81  	abci.BaseApplication
    82  }
    83  
    84  func (app *preprocessingApp) PreprocessTxs(
    85  	req abci.RequestPreprocessTxs) abci.ResponsePreprocessTxs {
    86  	time.Sleep(time.Second * 2)
    87  	randTxs := generateRandTxs(64, 256)
    88  	randMsgs := generateRandNamespacedRawData(128, nmt.DefaultNamespaceIDLen, 256)
    89  	randMessages := toMessageSlice(randMsgs)
    90  	return abci.ResponsePreprocessTxs{
    91  		Txs:      append(req.Txs, randTxs...),
    92  		Messages: &tmproto.Messages{MessagesList: randMessages},
    93  	}
    94  }
    95  func generateRandTxs(num int, size int) [][]byte {
    96  	randMsgs := generateRandNamespacedRawData(num, nmt.DefaultNamespaceIDLen, size)
    97  	for _, msg := range randMsgs {
    98  		copy(msg[:nmt.DefaultNamespaceIDLen], consts.TxNamespaceID)
    99  	}
   100  	return randMsgs
   101  }
   102  
   103  func toMessageSlice(msgs [][]byte) []*tmproto.Message {
   104  	res := make([]*tmproto.Message, len(msgs))
   105  	for i := 0; i < len(msgs); i++ {
   106  		res[i] = &tmproto.Message{NamespaceId: msgs[i][:nmt.DefaultNamespaceIDLen], Data: msgs[i][nmt.DefaultNamespaceIDLen:]}
   107  	}
   108  	return res
   109  }
   110  
   111  func TestDataAvailabilityHeaderRewriteBug(t *testing.T) {
   112  	logger := log.TestingLogger()
   113  	dag := mdutils.Mock()
   114  	croute := ipfs.MockRouting()
   115  
   116  	txs := types.Txs{}
   117  	l := len(txs)
   118  	bzs := make([][]byte, l)
   119  	for i := 0; i < l; i++ {
   120  		bzs[i] = txs[i]
   121  	}
   122  	app := &preprocessingApp{}
   123  
   124  	// See state.CreateProposalBlock to understand why we do this here:
   125  	processedBlockTxs := app.PreprocessTxs(abci.RequestPreprocessTxs{Txs: bzs})
   126  	ppt := processedBlockTxs.GetTxs()
   127  
   128  	pbmessages := processedBlockTxs.GetMessages()
   129  
   130  	lp := len(ppt)
   131  	processedTxs := make(types.Txs, lp)
   132  	if lp > 0 {
   133  		for i := 0; i < l; i++ {
   134  			processedTxs[i] = ppt[i]
   135  		}
   136  	}
   137  
   138  	messages := types.MessagesFromProto(pbmessages)
   139  	lastID := makeBlockIDRandom()
   140  	h := int64(3)
   141  
   142  	voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
   143  	commit, err := types.MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
   144  	assert.NoError(t, err)
   145  	block := types.MakeBlock(1, processedTxs, nil, nil, messages, commit)
   146  	block.Hash()
   147  
   148  	hash1 := block.DataAvailabilityHeader.Hash()
   149  
   150  	ctx := context.TODO()
   151  	err = PutBlock(ctx, dag, block, croute, logger)
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	block.Hash()
   157  	hash2 := block.DataAvailabilityHeader.Hash()
   158  	assert.Equal(t, hash1, hash2)
   159  
   160  }
   161  
   162  func generateRandomMsgOnlyData(msgCount int) types.Data {
   163  	out := make([]types.Message, msgCount)
   164  	for i, msg := range generateRandNamespacedRawData(msgCount, consts.NamespaceSize, consts.MsgShareSize-2) {
   165  		out[i] = types.Message{NamespaceID: msg[:consts.NamespaceSize], Data: msg[consts.NamespaceSize:]}
   166  	}
   167  	return types.Data{
   168  		Messages: types.Messages{MessagesList: out},
   169  	}
   170  }
   171  
   172  func makeBlockIDRandom() types.BlockID {
   173  	var (
   174  		blockHash   = make([]byte, tmhash.Size)
   175  		partSetHash = make([]byte, tmhash.Size)
   176  	)
   177  	mrand.Read(blockHash)
   178  	mrand.Read(partSetHash)
   179  	return types.BlockID{
   180  		Hash: blockHash,
   181  		PartSetHeader: types.PartSetHeader{
   182  			Total: 123,
   183  			Hash:  partSetHash,
   184  		},
   185  	}
   186  }
   187  
   188  func randVoteSet(
   189  	height int64,
   190  	round int32,
   191  	signedMsgType tmproto.SignedMsgType,
   192  	numValidators int,
   193  	votingPower int64,
   194  ) (*types.VoteSet, *types.ValidatorSet, []types.PrivValidator) {
   195  	valSet, privValidators := types.RandValidatorSet(numValidators, votingPower)
   196  	return types.NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators
   197  }