github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/gas_register_test.go (about) 1 package keeper 2 3 import ( 4 "math" 5 "strings" 6 "testing" 7 8 wasmvmtypes "github.com/CosmWasm/wasmvm/types" 9 storetypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 10 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func TestCompileCosts(t *testing.T) { 15 specs := map[string]struct { 16 srcLen int 17 srcConfig WasmGasRegisterConfig 18 exp sdk.Gas 19 expPanic bool 20 }{ 21 "one byte": { 22 srcLen: 1, 23 srcConfig: DefaultGasRegisterConfig(), 24 exp: sdk.Gas(3), // DefaultCompileCost 25 }, 26 "zero byte": { 27 srcLen: 0, 28 srcConfig: DefaultGasRegisterConfig(), 29 exp: sdk.Gas(0), 30 }, 31 "negative len": { 32 srcLen: -1, 33 srcConfig: DefaultGasRegisterConfig(), 34 expPanic: true, 35 }, 36 } 37 for name, spec := range specs { 38 t.Run(name, func(t *testing.T) { 39 if spec.expPanic { 40 assert.Panics(t, func() { 41 NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) 42 }) 43 return 44 } 45 gotGas := NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) 46 assert.Equal(t, spec.exp, gotGas) 47 }) 48 } 49 } 50 51 func TestNewContractInstanceCosts(t *testing.T) { 52 specs := map[string]struct { 53 srcLen int 54 srcConfig WasmGasRegisterConfig 55 pinned bool 56 exp sdk.Gas 57 expPanic bool 58 }{ 59 "small msg - pinned": { 60 srcLen: 1, 61 srcConfig: DefaultGasRegisterConfig(), 62 pinned: true, 63 exp: DefaultContractMessageDataCost, 64 }, 65 "big msg - pinned": { 66 srcLen: math.MaxUint32, 67 srcConfig: DefaultGasRegisterConfig(), 68 pinned: true, 69 exp: DefaultContractMessageDataCost * sdk.Gas(math.MaxUint32), 70 }, 71 "empty msg - pinned": { 72 srcLen: 0, 73 pinned: true, 74 srcConfig: DefaultGasRegisterConfig(), 75 exp: sdk.Gas(0), 76 }, 77 "small msg - unpinned": { 78 srcLen: 1, 79 srcConfig: DefaultGasRegisterConfig(), 80 exp: DefaultContractMessageDataCost + DefaultInstanceCost, 81 }, 82 "big msg - unpinned": { 83 srcLen: math.MaxUint32, 84 srcConfig: DefaultGasRegisterConfig(), 85 exp: sdk.Gas(DefaultContractMessageDataCost*math.MaxUint32 + DefaultInstanceCost), 86 }, 87 "empty msg - unpinned": { 88 srcLen: 0, 89 srcConfig: DefaultGasRegisterConfig(), 90 exp: sdk.Gas(DefaultInstanceCost), 91 }, 92 93 "negative len": { 94 srcLen: -1, 95 srcConfig: DefaultGasRegisterConfig(), 96 expPanic: true, 97 }, 98 } 99 for name, spec := range specs { 100 t.Run(name, func(t *testing.T) { 101 if spec.expPanic { 102 assert.Panics(t, func() { 103 NewWasmGasRegister(spec.srcConfig).NewContractInstanceCosts(spec.pinned, spec.srcLen) 104 }) 105 return 106 } 107 gotGas := NewWasmGasRegister(spec.srcConfig).NewContractInstanceCosts(spec.pinned, spec.srcLen) 108 assert.Equal(t, spec.exp, gotGas) 109 }) 110 } 111 } 112 113 func TestContractInstanceCosts(t *testing.T) { 114 // same as TestNewContractInstanceCosts currently 115 specs := map[string]struct { 116 srcLen int 117 srcConfig WasmGasRegisterConfig 118 pinned bool 119 exp sdk.Gas 120 expPanic bool 121 }{ 122 "small msg - pinned": { 123 srcLen: 1, 124 srcConfig: DefaultGasRegisterConfig(), 125 pinned: true, 126 exp: DefaultContractMessageDataCost, 127 }, 128 "big msg - pinned": { 129 srcLen: math.MaxUint32, 130 srcConfig: DefaultGasRegisterConfig(), 131 pinned: true, 132 exp: sdk.Gas(DefaultContractMessageDataCost * math.MaxUint32), 133 }, 134 "empty msg - pinned": { 135 srcLen: 0, 136 pinned: true, 137 srcConfig: DefaultGasRegisterConfig(), 138 exp: sdk.Gas(0), 139 }, 140 "small msg - unpinned": { 141 srcLen: 1, 142 srcConfig: DefaultGasRegisterConfig(), 143 exp: DefaultContractMessageDataCost + DefaultInstanceCost, 144 }, 145 "big msg - unpinned": { 146 srcLen: math.MaxUint32, 147 srcConfig: DefaultGasRegisterConfig(), 148 exp: sdk.Gas(DefaultContractMessageDataCost*math.MaxUint32 + DefaultInstanceCost), 149 }, 150 "empty msg - unpinned": { 151 srcLen: 0, 152 srcConfig: DefaultGasRegisterConfig(), 153 exp: sdk.Gas(DefaultInstanceCost), 154 }, 155 156 "negative len": { 157 srcLen: -1, 158 srcConfig: DefaultGasRegisterConfig(), 159 expPanic: true, 160 }, 161 } 162 for name, spec := range specs { 163 t.Run(name, func(t *testing.T) { 164 if spec.expPanic { 165 assert.Panics(t, func() { 166 NewWasmGasRegister(spec.srcConfig).InstantiateContractCosts(spec.pinned, spec.srcLen) 167 }) 168 return 169 } 170 gotGas := NewWasmGasRegister(spec.srcConfig).InstantiateContractCosts(spec.pinned, spec.srcLen) 171 assert.Equal(t, spec.exp, gotGas) 172 }) 173 } 174 } 175 176 func TestReplyCost(t *testing.T) { 177 specs := map[string]struct { 178 src wasmvmtypes.Reply 179 srcConfig WasmGasRegisterConfig 180 pinned bool 181 exp sdk.Gas 182 expPanic bool 183 }{ 184 "subcall response with events and data - pinned": { 185 src: wasmvmtypes.Reply{ 186 Result: wasmvmtypes.SubMsgResult{ 187 Ok: &wasmvmtypes.SubMsgResponse{ 188 Events: []wasmvmtypes.Event{ 189 {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, 190 }, 191 Data: []byte{0x1}, 192 }, 193 }, 194 }, 195 srcConfig: DefaultGasRegisterConfig(), 196 pinned: true, 197 exp: sdk.Gas(3*DefaultEventAttributeDataCost + DefaultPerAttributeCost + DefaultContractMessageDataCost), // 3 == len("foo") 198 }, 199 "subcall response with events - pinned": { 200 src: wasmvmtypes.Reply{ 201 Result: wasmvmtypes.SubMsgResult{ 202 Ok: &wasmvmtypes.SubMsgResponse{ 203 Events: []wasmvmtypes.Event{ 204 {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, 205 }, 206 }, 207 }, 208 }, 209 srcConfig: DefaultGasRegisterConfig(), 210 pinned: true, 211 exp: sdk.Gas(3*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo") 212 }, 213 "subcall response with events exceeds free tier- pinned": { 214 src: wasmvmtypes.Reply{ 215 Result: wasmvmtypes.SubMsgResult{ 216 Ok: &wasmvmtypes.SubMsgResponse{ 217 Events: []wasmvmtypes.Event{ 218 {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: strings.Repeat("x", DefaultEventAttributeDataFreeTier), Value: "myData"}}}, 219 }, 220 }, 221 }, 222 }, 223 srcConfig: DefaultGasRegisterConfig(), 224 pinned: true, 225 exp: sdk.Gas((3+6)*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo"), 6 == len("myData") 226 }, 227 "subcall response error - pinned": { 228 src: wasmvmtypes.Reply{ 229 Result: wasmvmtypes.SubMsgResult{ 230 Err: "foo", 231 }, 232 }, 233 srcConfig: DefaultGasRegisterConfig(), 234 pinned: true, 235 exp: 3 * DefaultContractMessageDataCost, 236 }, 237 "subcall response with events and data - unpinned": { 238 src: wasmvmtypes.Reply{ 239 Result: wasmvmtypes.SubMsgResult{ 240 Ok: &wasmvmtypes.SubMsgResponse{ 241 Events: []wasmvmtypes.Event{ 242 {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, 243 }, 244 Data: []byte{0x1}, 245 }, 246 }, 247 }, 248 srcConfig: DefaultGasRegisterConfig(), 249 exp: sdk.Gas(DefaultInstanceCost + 3*DefaultEventAttributeDataCost + DefaultPerAttributeCost + DefaultContractMessageDataCost), 250 }, 251 "subcall response with events - unpinned": { 252 src: wasmvmtypes.Reply{ 253 Result: wasmvmtypes.SubMsgResult{ 254 Ok: &wasmvmtypes.SubMsgResponse{ 255 Events: []wasmvmtypes.Event{ 256 {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, 257 }, 258 }, 259 }, 260 }, 261 srcConfig: DefaultGasRegisterConfig(), 262 exp: sdk.Gas(DefaultInstanceCost + 3*DefaultEventAttributeDataCost + DefaultPerAttributeCost), 263 }, 264 "subcall response with events exceeds free tier- unpinned": { 265 src: wasmvmtypes.Reply{ 266 Result: wasmvmtypes.SubMsgResult{ 267 Ok: &wasmvmtypes.SubMsgResponse{ 268 Events: []wasmvmtypes.Event{ 269 {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: strings.Repeat("x", DefaultEventAttributeDataFreeTier), Value: "myData"}}}, 270 }, 271 }, 272 }, 273 }, 274 srcConfig: DefaultGasRegisterConfig(), 275 exp: sdk.Gas(DefaultInstanceCost + (3+6)*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo"), 6 == len("myData") 276 }, 277 "subcall response error - unpinned": { 278 src: wasmvmtypes.Reply{ 279 Result: wasmvmtypes.SubMsgResult{ 280 Err: "foo", 281 }, 282 }, 283 srcConfig: DefaultGasRegisterConfig(), 284 exp: sdk.Gas(DefaultInstanceCost + 3*DefaultContractMessageDataCost), 285 }, 286 "subcall response with empty events": { 287 src: wasmvmtypes.Reply{ 288 Result: wasmvmtypes.SubMsgResult{ 289 Ok: &wasmvmtypes.SubMsgResponse{ 290 Events: make([]wasmvmtypes.Event, 10), 291 }, 292 }, 293 }, 294 srcConfig: DefaultGasRegisterConfig(), 295 exp: DefaultInstanceCost, 296 }, 297 "subcall response with events unset": { 298 src: wasmvmtypes.Reply{ 299 Result: wasmvmtypes.SubMsgResult{ 300 Ok: &wasmvmtypes.SubMsgResponse{}, 301 }, 302 }, 303 srcConfig: DefaultGasRegisterConfig(), 304 exp: DefaultInstanceCost, 305 }, 306 } 307 for name, spec := range specs { 308 t.Run(name, func(t *testing.T) { 309 if spec.expPanic { 310 assert.Panics(t, func() { 311 NewWasmGasRegister(spec.srcConfig).ReplyCosts(spec.pinned, spec.src) 312 }) 313 return 314 } 315 gotGas := NewWasmGasRegister(spec.srcConfig).ReplyCosts(spec.pinned, spec.src) 316 assert.Equal(t, spec.exp, gotGas) 317 }) 318 } 319 } 320 321 func TestEventCosts(t *testing.T) { 322 // most cases are covered in TestReplyCost already. This ensures some edge cases 323 specs := map[string]struct { 324 srcAttrs []wasmvmtypes.EventAttribute 325 srcEvents wasmvmtypes.Events 326 expGas sdk.Gas 327 }{ 328 "empty events": { 329 srcEvents: make([]wasmvmtypes.Event, 1), 330 expGas: DefaultPerCustomEventCost, 331 }, 332 "empty attributes": { 333 srcAttrs: make([]wasmvmtypes.EventAttribute, 1), 334 expGas: DefaultPerAttributeCost, 335 }, 336 "both nil": { 337 expGas: 0, 338 }, 339 } 340 for name, spec := range specs { 341 t.Run(name, func(t *testing.T) { 342 gotGas := NewDefaultWasmGasRegister().EventCosts(spec.srcAttrs, spec.srcEvents) 343 assert.Equal(t, spec.expGas, gotGas) 344 }) 345 } 346 } 347 348 func TestToWasmVMGasConversion(t *testing.T) { 349 specs := map[string]struct { 350 src storetypes.Gas 351 srcConfig WasmGasRegisterConfig 352 exp uint64 353 expPanic bool 354 }{ 355 "0": { 356 src: 0, 357 exp: 0, 358 srcConfig: DefaultGasRegisterConfig(), 359 }, 360 "max": { 361 srcConfig: WasmGasRegisterConfig{ 362 GasMultiplier: 1, 363 }, 364 src: math.MaxUint64, 365 exp: math.MaxUint64, 366 }, 367 "overflow": { 368 srcConfig: WasmGasRegisterConfig{ 369 GasMultiplier: 2, 370 }, 371 src: math.MaxUint64, 372 expPanic: true, 373 }, 374 } 375 for name, spec := range specs { 376 t.Run(name, func(t *testing.T) { 377 if spec.expPanic { 378 assert.Panics(t, func() { 379 r := NewWasmGasRegister(spec.srcConfig) 380 _ = r.ToWasmVMGas(spec.src) 381 }) 382 return 383 } 384 r := NewWasmGasRegister(spec.srcConfig) 385 got := r.ToWasmVMGas(spec.src) 386 assert.Equal(t, spec.exp, got) 387 }) 388 } 389 } 390 391 func TestFromWasmVMGasConversion(t *testing.T) { 392 specs := map[string]struct { 393 src uint64 394 exp storetypes.Gas 395 srcConfig WasmGasRegisterConfig 396 expPanic bool 397 }{ 398 "0": { 399 src: 0, 400 exp: 0, 401 srcConfig: DefaultGasRegisterConfig(), 402 }, 403 "max": { 404 srcConfig: WasmGasRegisterConfig{ 405 GasMultiplier: 1, 406 }, 407 src: math.MaxUint64, 408 exp: math.MaxUint64, 409 }, 410 "missconfigured": { 411 srcConfig: WasmGasRegisterConfig{ 412 GasMultiplier: 0, 413 }, 414 src: 1, 415 expPanic: true, 416 }, 417 } 418 for name, spec := range specs { 419 t.Run(name, func(t *testing.T) { 420 if spec.expPanic { 421 assert.Panics(t, func() { 422 r := NewWasmGasRegister(spec.srcConfig) 423 _ = r.FromWasmVMGas(spec.src) 424 }) 425 return 426 } 427 r := NewWasmGasRegister(spec.srcConfig) 428 got := r.FromWasmVMGas(spec.src) 429 assert.Equal(t, spec.exp, got) 430 }) 431 } 432 }