github.com/okex/exchain@v1.8.0/libs/tendermint/state/execution_dds_test.go (about) 1 package state 2 3 import ( 4 "encoding/hex" 5 "reflect" 6 "testing" 7 "time" 8 9 "github.com/alicebob/miniredis/v2" 10 "github.com/okex/exchain/libs/iavl" 11 redis_cgi "github.com/okex/exchain/libs/tendermint/delta/redis-cgi" 12 "github.com/okex/exchain/libs/tendermint/libs/log" 13 "github.com/okex/exchain/libs/tendermint/types" 14 tmtime "github.com/okex/exchain/libs/tendermint/types/time" 15 dbm "github.com/okex/exchain/libs/tm-db" 16 "github.com/stretchr/testify/require" 17 "github.com/tendermint/go-amino" 18 ) 19 20 func getRedisClient(t *testing.T) *redis_cgi.RedisClient { 21 s := miniredis.RunT(t) 22 logger := log.TestingLogger() 23 ss := redis_cgi.NewRedisClient(s.Addr(), "", time.Minute, 0, logger) 24 return ss 25 } 26 27 func failRedisClient() *redis_cgi.RedisClient { 28 logger := log.TestingLogger() 29 ss := redis_cgi.NewRedisClient("127.0.0.1:6378", "", time.Minute, 0, logger) 30 return ss 31 } 32 33 func setupTest(t *testing.T) *DeltaContext { 34 dc := newDeltaContext(log.TestingLogger()) 35 dc.deltaBroker = getRedisClient(t) 36 return dc 37 } 38 39 func bytesEqual(b1, b2 []byte) bool { 40 return hex.EncodeToString(b1) == hex.EncodeToString(b2) 41 } 42 func deltaEqual(d1, d2 *types.Deltas) bool { 43 if d1 == nil && d2 == nil { 44 return true 45 } 46 if d1 == nil || d2 == nil { 47 return false 48 } 49 return d1.Height == d2.Height && 50 d1.From == d2.From && 51 d1.CompressType == d2.CompressType && 52 d1.CompressFlag == d2.CompressFlag && 53 bytesEqual(d1.ABCIRsp(), d2.ABCIRsp()) && 54 bytesEqual(d1.DeltasBytes(), d2.DeltasBytes()) && 55 bytesEqual(d1.WatchBytes(), d2.WatchBytes()) 56 } 57 58 func TestDeltaContext_prepareStateDelta(t *testing.T) { 59 dc := setupTest(t) 60 dc.downloadDelta = true 61 62 deltaInfos := make([]*DeltaInfo, 3) 63 for i := 0; i <= 2; i++ { 64 h := int64(i + 1) 65 deltaInfos[i] = &DeltaInfo{ 66 from: "0x01", 67 deltaLen: 1000, 68 deltaHeight: h, 69 abciResponses: &ABCIResponses{}, 70 treeDeltaMap: iavl.TreeDeltaMap{}, 71 } 72 dc.dataMap.insert(h, deltaInfos[i], h) 73 } 74 75 tests := []struct { 76 name string 77 height int64 78 wantInfo *DeltaInfo 79 }{ 80 {"normal case", 1, deltaInfos[0]}, 81 {"empty delta", 4, nil}, 82 {"already remove", 1, nil}, 83 {"higher height", 3, deltaInfos[2]}, 84 {"lower remove", 2, deltaInfos[1]}, 85 } 86 for _, tt := range tests { 87 t.Run(tt.name, func(t *testing.T) { 88 if gotInfo := dc.prepareStateDelta(tt.height); !reflect.DeepEqual(gotInfo, tt.wantInfo) { 89 t.Errorf("prepareStateDelta() = %v, want %v", gotInfo, tt.wantInfo) 90 } 91 }) 92 } 93 } 94 95 func TestDeltaContext_download(t *testing.T) { 96 dc := setupTest(t) 97 deltas := &types.Deltas{Height: 10, Payload: types.DeltaPayload{ABCIRsp: []byte("ABCIRsp"), DeltasBytes: []byte("DeltasBytes"), WatchBytes: []byte("WatchBytes")}} 98 dc.uploadRoutine(deltas, 0) 99 100 tests := []struct { 101 name string 102 height int64 103 wants *types.Deltas 104 }{ 105 {"normal case", 10, deltas}, 106 {"higher height", 11, nil}, 107 {"lower height", 9, nil}, 108 } 109 for _, tt := range tests { 110 t.Run(tt.name, func(t *testing.T) { 111 _, err, mrh := dc.deltaBroker.GetDeltas(tt.height) 112 got, got1, got2 := dc.download(tt.height) 113 if !reflect.DeepEqual(got, err) { 114 t.Errorf("download() got = %v, want %v", got, err) 115 } 116 if !deltaEqual(got1, tt.wants) { 117 t.Errorf("download() got = %v, want %v", got, deltas) 118 } 119 if got2 != mrh { 120 t.Errorf("download() got2 = %v, want %v", got2, mrh) 121 } 122 }) 123 } 124 } 125 126 func TestDeltaContext_upload(t *testing.T) { 127 dc := setupTest(t) 128 deltas := &types.Deltas{Payload: types.DeltaPayload{ABCIRsp: []byte("ABCIRsp"), DeltasBytes: []byte("DeltasBytes"), WatchBytes: []byte("WatchBytes")}} 129 okRedis := getRedisClient(t) 130 failRedis := failRedisClient() 131 132 tests := []struct { 133 name string 134 r *redis_cgi.RedisClient 135 deltas *types.Deltas 136 want bool 137 }{ 138 {"normal case", okRedis, deltas, true}, 139 {"nil delta", okRedis, nil, false}, 140 {"empty delta", okRedis, &types.Deltas{}, false}, 141 {"fail redis", failRedis, deltas, false}, 142 } 143 for _, tt := range tests { 144 t.Run(tt.name, func(t *testing.T) { 145 dc.deltaBroker = tt.r 146 if got := dc.upload(tt.deltas, 0, 0); got != tt.want { 147 t.Errorf("upload() = %v, want %v", got, tt.want) 148 } 149 }) 150 } 151 } 152 153 // -------------------------------------------------------------------------------------- 154 155 func produceBlock() ([]*types.Block, dbm.DB) { 156 state, stateDB, _ := makeState(2, 2) 157 prevHash := state.LastBlockID.Hash 158 prevParts := types.PartSetHeader{} 159 prevBlockID := types.BlockID{Hash: prevHash, PartsHeader: prevParts} 160 var ( 161 now = tmtime.Now() 162 commitSig0 = types.NewCommitSigForBlock( 163 []byte("Signature1"), 164 state.Validators.Validators[0].Address, 165 now) 166 commitSig1 = types.NewCommitSigForBlock( 167 []byte("Signature2"), 168 state.Validators.Validators[1].Address, 169 now) 170 absentSig = types.NewCommitSigAbsent() 171 ) 172 173 testCases := []struct { 174 desc string 175 lastCommitSigs []types.CommitSig 176 expectedAbsentValidators []int 177 }{ 178 {"none absent", []types.CommitSig{commitSig0, commitSig1}, []int{}}, 179 {"one absent", []types.CommitSig{commitSig0, absentSig}, []int{1}}, 180 {"multiple absent", []types.CommitSig{absentSig, absentSig}, []int{0, 1}}, 181 } 182 blocks := make([]*types.Block, len(testCases)) 183 for i, tc := range testCases { 184 lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs) 185 blocks[i], _ = state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address) 186 } 187 188 return blocks, stateDB 189 } 190 191 func produceAbciRsp() *ABCIResponses { 192 proxyApp := newTestApp() 193 proxyApp.Start() 194 defer proxyApp.Stop() 195 196 blocks, stateDB := produceBlock() 197 ctx := &executionTask{ 198 logger: log.TestingLogger(), 199 block: blocks[0], 200 db: stateDB, 201 proxyApp: proxyApp.Consensus(), 202 } 203 204 abciResponses, _ := execBlockOnProxyApp(ctx) 205 return abciResponses 206 } 207 208 func TestProduceDelta(t *testing.T) { 209 proxyApp := newTestApp() 210 err := proxyApp.Start() 211 require.Nil(t, err) 212 defer proxyApp.Stop() 213 214 blocks, stateDB := produceBlock() 215 for _, block := range blocks { 216 deltas, _, err := execCommitBlockDelta(proxyApp.Consensus(), block, log.TestingLogger(), stateDB) 217 require.Nil(t, err) 218 require.NotNil(t, deltas) 219 } 220 } 221 222 func BenchmarkMarshalJson(b *testing.B) { 223 abciResponses := produceAbciRsp() 224 225 b.ResetTimer() 226 for n := 0; n <= b.N; n++ { 227 types.Json.Marshal(abciResponses) 228 } 229 } 230 231 func BenchmarkMarshalAmino(b *testing.B) { 232 abciResponses := produceAbciRsp() 233 var cdc = amino.NewCodec() 234 235 b.ResetTimer() 236 for n := 0; n <= b.N; n++ { 237 cdc.MarshalBinaryBare(abciResponses) 238 } 239 } 240 241 func BenchmarkMarshalCustom(b *testing.B) { 242 abciResponses := produceAbciRsp() 243 244 b.ResetTimer() 245 for n := 0; n <= b.N; n++ { 246 abciResponses.MarshalToAmino(ModuleCodec) 247 } 248 } 249 250 func BenchmarkUnmarshalFromJson(b *testing.B) { 251 abciResponses := produceAbciRsp() 252 data, _ := types.Json.Marshal(abciResponses) 253 254 b.ReportAllocs() 255 b.ResetTimer() 256 for n := 0; n <= b.N; n++ { 257 ar := &ABCIResponses{} 258 types.Json.Unmarshal(data, ar) 259 } 260 } 261 func BenchmarkUnmarshalFromAmino(b *testing.B) { 262 abciResponses := produceAbciRsp() 263 var cdc = amino.NewCodec() 264 data, _ := cdc.MarshalBinaryBare(abciResponses) 265 266 b.ReportAllocs() 267 b.ResetTimer() 268 for n := 0; n <= b.N; n++ { 269 ar := &ABCIResponses{} 270 cdc.UnmarshalBinaryBare(data, ar) 271 } 272 } 273 func BenchmarkUnmarshalFromCustom(b *testing.B) { 274 abciResponses := produceAbciRsp() 275 data, _ := abciResponses.MarshalToAmino(cdc) 276 277 b.ReportAllocs() 278 b.ResetTimer() 279 for n := 0; n <= b.N; n++ { 280 ar := &ABCIResponses{} 281 ar.UnmarshalFromAmino(nil, data) 282 } 283 }