github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/context_test.go (about) 1 package types_test 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/require" 9 10 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 11 dbm "github.com/fibonacci-chain/fbc/libs/tm-db" 12 13 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 14 15 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1" 16 17 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store" 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 19 ) 20 21 type MockLogger struct { 22 logs *[]string 23 } 24 25 func NewMockLogger() MockLogger { 26 logs := make([]string, 0) 27 return MockLogger{ 28 &logs, 29 } 30 } 31 32 func (l MockLogger) Debug(msg string, kvs ...interface{}) { 33 *l.logs = append(*l.logs, msg) 34 } 35 36 func (l MockLogger) Info(msg string, kvs ...interface{}) { 37 *l.logs = append(*l.logs, msg) 38 } 39 40 func (l MockLogger) Error(msg string, kvs ...interface{}) { 41 *l.logs = append(*l.logs, msg) 42 } 43 44 func (l MockLogger) With(kvs ...interface{}) log.Logger { 45 panic("not implemented") 46 } 47 48 func defaultContext(key types.StoreKey) types.Context { 49 db := dbm.NewMemDB() 50 cms := store.NewCommitMultiStore(db) 51 cms.MountStoreWithDB(key, types.StoreTypeIAVL, db) 52 cms.LoadLatestVersion() 53 ctx := types.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) 54 return ctx 55 } 56 57 func TestCacheContext(t *testing.T) { 58 key := types.NewKVStoreKey(t.Name()) 59 k1 := []byte("hello") 60 v1 := []byte("world") 61 k2 := []byte("key") 62 v2 := []byte("value") 63 64 ctx := defaultContext(key) 65 store := ctx.KVStore(key) 66 store.Set(k1, v1) 67 require.Equal(t, v1, store.Get(k1)) 68 require.Nil(t, store.Get(k2)) 69 70 cctx, write := ctx.CacheContext() 71 cstore := cctx.KVStore(key) 72 require.Equal(t, v1, cstore.Get(k1)) 73 require.Nil(t, cstore.Get(k2)) 74 75 cstore.Set(k2, v2) 76 require.Equal(t, v2, cstore.Get(k2)) 77 require.Nil(t, store.Get(k2)) 78 79 write() 80 81 require.Equal(t, v2, store.Get(k2)) 82 } 83 84 func TestLogContext(t *testing.T) { 85 key := types.NewKVStoreKey(t.Name()) 86 ctx := defaultContext(key) 87 logger := NewMockLogger() 88 ctx.SetLogger(logger) 89 ctx.Logger().Debug("debug") 90 ctx.Logger().Info("info") 91 ctx.Logger().Error("error") 92 require.Equal(t, *logger.logs, []string{"debug", "info", "error"}) 93 } 94 95 type dummy int64 //nolint:unused 96 97 func (d dummy) Clone() interface{} { 98 return d 99 } 100 101 // Testing saving/loading sdk type values to/from the context 102 func TestContextWithCustom(t *testing.T) { 103 var ctx types.Context 104 require.True(t, ctx.IsZero()) 105 106 header := abci.Header{} 107 height := int64(1) 108 chainid := "chainid" 109 ischeck := true 110 txbytes := []byte("txbytes") 111 logger := NewMockLogger() 112 voteinfos := []abci.VoteInfo{{}} 113 meter := types.NewGasMeter(10000) 114 minGasPrices := types.DecCoins{types.NewInt64DecCoin("feetoken", 1)} 115 116 ctx = types.NewContext(nil, header, ischeck, logger) 117 require.Equal(t, header, ctx.BlockHeader()) 118 119 ctx. 120 SetBlockHeight(height). 121 SetChainID(chainid). 122 SetTxBytes(txbytes). 123 SetVoteInfos(voteinfos). 124 SetGasMeter(meter). 125 SetMinGasPrices(minGasPrices) 126 127 require.Equal(t, height, ctx.BlockHeight()) 128 require.Equal(t, chainid, ctx.ChainID()) 129 require.Equal(t, ischeck, ctx.IsCheckTx()) 130 require.Equal(t, txbytes, ctx.TxBytes()) 131 require.Equal(t, logger, ctx.Logger()) 132 require.Equal(t, voteinfos, ctx.VoteInfos()) 133 require.Equal(t, meter, ctx.GasMeter()) 134 require.Equal(t, minGasPrices, ctx.MinGasPrices()) 135 } 136 137 // Testing saving/loading of header fields to/from the context 138 func TestContextHeader(t *testing.T) { 139 var ctx types.Context 140 141 height := int64(5) 142 time := time.Now() 143 addr := secp256k1.GenPrivKey().PubKey().Address() 144 proposer := types.ConsAddress(addr) 145 146 ctx = types.NewContext(nil, abci.Header{}, false, nil) 147 148 ctx. 149 SetBlockHeight(height). 150 SetBlockTime(time). 151 SetProposer(proposer) 152 153 require.Equal(t, height, ctx.BlockHeight()) 154 require.Equal(t, height, ctx.BlockHeader().Height) 155 require.Equal(t, time.UTC(), ctx.BlockHeader().Time) 156 require.Equal(t, proposer.Bytes(), ctx.BlockHeader().ProposerAddress) 157 } 158 159 func TestContextHeaderClone(t *testing.T) { 160 cases := map[string]struct { 161 h abci.Header 162 }{ 163 "empty": { 164 h: abci.Header{}, 165 }, 166 "height": { 167 h: abci.Header{ 168 Height: 77, 169 }, 170 }, 171 "time": { 172 h: abci.Header{ 173 Time: time.Unix(12345677, 12345), 174 }, 175 }, 176 "zero time": { 177 h: abci.Header{ 178 Time: time.Unix(0, 0), 179 }, 180 }, 181 "many items": { 182 h: abci.Header{ 183 Height: 823, 184 Time: time.Unix(9999999999, 0), 185 ChainID: "silly-demo", 186 }, 187 }, 188 "many items with hash": { 189 h: abci.Header{ 190 Height: 823, 191 Time: time.Unix(9999999999, 0), 192 ChainID: "silly-demo", 193 AppHash: []byte{5, 34, 11, 3, 23}, 194 ConsensusHash: []byte{11, 3, 23, 87, 3, 1}, 195 }, 196 }, 197 } 198 199 for name, tc := range cases { 200 tc := tc 201 t.Run(name, func(t *testing.T) { 202 ctx := types.NewContext(nil, tc.h, false, nil) 203 require.Equal(t, tc.h.Height, ctx.BlockHeight()) 204 require.Equal(t, tc.h.Time.UTC(), ctx.BlockTime()) 205 206 // update only changes one field 207 var newHeight int64 = 17 208 ctx.SetBlockHeight(newHeight) 209 require.Equal(t, newHeight, ctx.BlockHeight()) 210 require.Equal(t, tc.h.Time.UTC(), ctx.BlockTime()) 211 }) 212 } 213 } 214 215 //go:noinline 216 func testFoo(ctx types.Context) int { 217 return len(ctx.From()) 218 } 219 220 func BenchmarkContextDuffCopy(b *testing.B) { 221 ctx := types.NewContext(nil, abci.Header{}, false, nil) 222 b.Run("1", func(b *testing.B) { 223 b.Run("with", func(b *testing.B) { 224 for i := 0; i < b.N; i++ { 225 ctx = ctx.WithIsCheckTx(true) 226 testFoo(ctx) 227 } 228 }) 229 b.Run("set", func(b *testing.B) { 230 for i := 0; i < b.N; i++ { 231 ctx.SetIsCheckTx(true) 232 testFoo(ctx) 233 } 234 }) 235 }) 236 237 b.Run("2", func(b *testing.B) { 238 b.Run("with", func(b *testing.B) { 239 for i := 0; i < b.N; i++ { 240 newCtx := ctx.WithIsCheckTx(true) 241 testFoo(newCtx) 242 } 243 }) 244 b.Run("set", func(b *testing.B) { 245 for i := 0; i < b.N; i++ { 246 newCtx := ctx 247 newCtx.SetIsCheckTx(true) 248 testFoo(newCtx) 249 } 250 }) 251 }) 252 253 b.Run("3", func(b *testing.B) { 254 b.Run("with", func(b *testing.B) { 255 for i := 0; i < b.N; i++ { 256 testFoo(ctx.WithIsCheckTx(true)) 257 } 258 }) 259 b.Run("set", func(b *testing.B) { 260 for i := 0; i < b.N; i++ { 261 newCtx := ctx 262 newCtx.SetIsCheckTx(true) 263 testFoo(newCtx) 264 } 265 }) 266 }) 267 268 b.Run("4", func(b *testing.B) { 269 b.Run("with", func(b *testing.B) { 270 for i := 0; i < b.N; i++ { 271 testFoo(ctx.WithIsCheckTx(true).WithIsReCheckTx(false)) 272 } 273 }) 274 b.Run("set", func(b *testing.B) { 275 for i := 0; i < b.N; i++ { 276 newCtx := ctx 277 newCtx.SetIsCheckTx(true).SetIsReCheckTx(false) 278 testFoo(newCtx) 279 } 280 }) 281 }) 282 } 283 284 func BenchmarkContextWrapAndUnwrap(b *testing.B) { 285 key := types.NewKVStoreKey(b.Name()) 286 287 ctx := defaultContext(key) 288 logger := NewMockLogger() 289 ctx.SetLogger(logger) 290 291 height := int64(1) 292 chainid := "chainid" 293 txbytes := []byte("txbytes") 294 voteinfos := []abci.VoteInfo{{}} 295 meter := types.NewGasMeter(10000) 296 minGasPrices := types.DecCoins{types.NewInt64DecCoin("feetoken", 1)} 297 ctx. 298 SetBlockHeight(height). 299 SetChainID(chainid). 300 SetTxBytes(txbytes). 301 SetVoteInfos(voteinfos). 302 SetGasMeter(meter). 303 SetMinGasPrices(minGasPrices).SetContext(context.Background()) 304 ctxC := types.WrapSDKContext(ctx) 305 b.Run("UnwrapSDKContext", func(b *testing.B) { 306 b.ResetTimer() 307 b.ReportAllocs() 308 for i := 0; i < b.N; i++ { 309 types.UnwrapSDKContext(ctxC) 310 } 311 }) 312 313 b.Run("WrapSDKContext", func(b *testing.B) { 314 b.ResetTimer() 315 b.ReportAllocs() 316 for i := 0; i < b.N; i++ { 317 types.WrapSDKContext(ctx) 318 } 319 }) 320 }