github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/abci/example/dummyapp/app/dummyapp.go (about) 1 // Package dummy extends the kvstore.Application to include random data. 2 // The random data is generated via the PreprocessTxs abci method. 3 // 4 // The name is inspired by: 5 // https://github.com/lazyledger/lazyledger-prototype/blob/2aeca6f55ad389b9d68034a0a7038f80a8d2982e/app_dummy.go#L7 6 package dummy 7 8 import ( 9 "bytes" 10 "math/rand" 11 "sort" 12 "time" 13 14 "github.com/lazyledger/lazyledger-core/abci/example/kvstore" 15 "github.com/lazyledger/lazyledger-core/abci/types" 16 tmproto "github.com/lazyledger/lazyledger-core/proto/tendermint/types" 17 "github.com/lazyledger/lazyledger-core/types/consts" 18 ) 19 20 type Application struct { 21 *kvstore.Application 22 23 // PreprocessTxs will create random messages according to these numbers: 24 randTxs uint32 25 txSize uint32 26 msgSize uint32 27 randMsgs uint32 28 sleep time.Duration 29 } 30 31 type Option func(app *Application) 32 33 // RandMessagesOnPreprocess will indicate to generate a given number of 34 // random messages and transactions on PreprocessTxs. 35 func RandMessagesOnPreprocess(numTx, txSize, numMsgs, msgSize uint32) Option { 36 return func(app *Application) { 37 app.randTxs = numTx 38 app.txSize = txSize 39 app.randMsgs = numMsgs 40 app.msgSize = msgSize 41 } 42 } 43 44 // SleepDuration simulates latency (e.g. incurred by execution or other computation) 45 // during PreprocessTxs. 46 func SleepDuration(sleep time.Duration) Option { 47 return func(app *Application) { 48 app.sleep = sleep 49 } 50 } 51 52 func NewApplication(opts ...Option) *Application { 53 app := &Application{Application: kvstore.NewApplication()} 54 for _, opt := range opts { 55 opt(app) 56 } 57 58 return app 59 } 60 61 func (app *Application) PreprocessTxs(req types.RequestPreprocessTxs) types.ResponsePreprocessTxs { 62 time.Sleep(app.sleep) 63 if app.randTxs > 0 || app.randMsgs > 0 { 64 randMsgs := generateRandNamespacedRawData(app.randMsgs, consts.NamespaceSize, app.msgSize) 65 randMessages := toMessageSlice(randMsgs) 66 // yeah, we misuse same function as above to generate Txs 67 // as they will still be app.txSize large ¯\_(ツ)_/¯ 68 randTxs := generateRandNamespacedRawData(app.randTxs, app.txSize, 0) 69 70 return types.ResponsePreprocessTxs{ 71 Txs: append(append( 72 make([][]byte, len(req.Txs)+len(randTxs)), 73 req.Txs...), randTxs...), 74 Messages: &tmproto.Messages{MessagesList: randMessages}, 75 } 76 } 77 return types.ResponsePreprocessTxs{Txs: req.Txs} 78 } 79 80 func toMessageSlice(msgs [][]byte) []*tmproto.Message { 81 res := make([]*tmproto.Message, len(msgs)) 82 for i := 0; i < len(msgs); i++ { 83 res[i] = &tmproto.Message{NamespaceId: msgs[i][:consts.NamespaceSize], Data: msgs[i][consts.NamespaceSize:]} 84 } 85 return res 86 } 87 88 // nolint:gosec // G404: Use of weak random number generator 89 func generateRandNamespacedRawData(total, nidSize, leafSize uint32) [][]byte { 90 data := make([][]byte, total) 91 for i := uint32(0); i < total; i++ { 92 nid := make([]byte, nidSize) 93 rand.Read(nid) 94 data[i] = nid 95 } 96 sortByteArrays(data) 97 for i := uint32(0); i < total; i++ { 98 d := make([]byte, leafSize) 99 rand.Read(d) 100 data[i] = append(data[i], d...) 101 } 102 103 return data 104 } 105 106 func sortByteArrays(src [][]byte) { 107 sort.Slice(src, func(i, j int) bool { return bytes.Compare(src[i], src[j]) < 0 }) 108 }