github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/types/types_test.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "context" 6 "strings" 7 "testing" 8 "time" 9 10 wasmvmtypes "github.com/CosmWasm/wasmvm/types" 11 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestContractInfoValidateBasic(t *testing.T) { 17 specs := map[string]struct { 18 srcMutator func(*ContractInfo) 19 expError bool 20 }{ 21 "all good": {srcMutator: func(_ *ContractInfo) {}}, 22 "code id empty": { 23 srcMutator: func(c *ContractInfo) { c.CodeID = 0 }, 24 expError: true, 25 }, 26 "creator empty": { 27 srcMutator: func(c *ContractInfo) { c.Creator = "" }, 28 expError: true, 29 }, 30 "creator not an address": { 31 srcMutator: func(c *ContractInfo) { c.Creator = "invalid address" }, 32 expError: true, 33 }, 34 "admin empty": { 35 srcMutator: func(c *ContractInfo) { c.Admin = "" }, 36 expError: false, 37 }, 38 "admin not an address": { 39 srcMutator: func(c *ContractInfo) { c.Admin = "invalid address" }, 40 expError: true, 41 }, 42 "label empty": { 43 srcMutator: func(c *ContractInfo) { c.Label = "" }, 44 expError: true, 45 }, 46 "label exceeds limit": { 47 srcMutator: func(c *ContractInfo) { c.Label = strings.Repeat("a", MaxLabelSize+1) }, 48 expError: true, 49 }, 50 //"invalid extension": { 51 // srcMutator: func(c *ContractInfo) { 52 // // any protobuf type with ValidateBasic method 53 // any, err := codectypes.NewAnyWithValue(&govtypes.TextProposal{}) 54 // require.NoError(t, err) 55 // c.Extension = any 56 // }, 57 // expError: true, 58 //}, 59 //"not validatable extension": { 60 // srcMutator: func(c *ContractInfo) { 61 // // any protobuf type with ValidateBasic method 62 // any, err := codectypes.NewAnyWithValue(&govtypes.Proposal{}) 63 // require.NoError(t, err) 64 // c.Extension = any 65 // }, 66 //}, 67 } 68 for msg, spec := range specs { 69 t.Run(msg, func(t *testing.T) { 70 state := ContractInfoFixture(spec.srcMutator) 71 got := state.ValidateBasic() 72 if spec.expError { 73 require.Error(t, got) 74 return 75 } 76 require.NoError(t, got) 77 }) 78 } 79 } 80 81 func TestCodeInfoValidateBasic(t *testing.T) { 82 specs := map[string]struct { 83 srcMutator func(*CodeInfo) 84 expError bool 85 }{ 86 "all good": {srcMutator: func(_ *CodeInfo) {}}, 87 "code hash empty": { 88 srcMutator: func(c *CodeInfo) { c.CodeHash = []byte{} }, 89 expError: true, 90 }, 91 "code hash nil": { 92 srcMutator: func(c *CodeInfo) { c.CodeHash = nil }, 93 expError: true, 94 }, 95 "creator empty": { 96 srcMutator: func(c *CodeInfo) { c.Creator = "" }, 97 expError: true, 98 }, 99 "creator not an address": { 100 srcMutator: func(c *CodeInfo) { c.Creator = "invalid address" }, 101 expError: true, 102 }, 103 "Instantiate config invalid": { 104 srcMutator: func(c *CodeInfo) { c.InstantiateConfig = AccessConfig{} }, 105 expError: true, 106 }, 107 } 108 for msg, spec := range specs { 109 t.Run(msg, func(t *testing.T) { 110 state := CodeInfoFixture(spec.srcMutator) 111 got := state.ValidateBasic() 112 if spec.expError { 113 require.Error(t, got) 114 return 115 } 116 require.NoError(t, got) 117 }) 118 } 119 } 120 121 //func TestContractInfoSetExtension(t *testing.T) { 122 // anyTime := time.Now().UTC() 123 // aNestedProtobufExt := func() ContractInfoExtension { 124 // // using gov proposal here as a random protobuf types as it contains an Any type inside for nested unpacking 125 // myExtension, err := govtypes.NewProposal(&govtypes.TextProposal{Title: "bar"}, 1, anyTime, anyTime) 126 // require.NoError(t, err) 127 // myExtension.TotalDeposit = nil 128 // return &myExtension 129 // } 130 // 131 // specs := map[string]struct { 132 // src ContractInfoExtension 133 // expErr bool 134 // expNil bool 135 // }{ 136 // "all good with any proto extension": { 137 // src: aNestedProtobufExt(), 138 // }, 139 // "nil allowed": { 140 // src: nil, 141 // expNil: true, 142 // }, 143 // "validated and accepted": { 144 // src: &govtypes.TextProposal{Title: "bar", Description: "set"}, 145 // }, 146 // "validated and rejected": { 147 // src: &govtypes.TextProposal{Title: "bar"}, 148 // expErr: true, 149 // }, 150 // } 151 // for name, spec := range specs { 152 // t.Run(name, func(t *testing.T) { 153 // var c ContractInfo 154 // gotErr := c.SetExtension(spec.src) 155 // if spec.expErr { 156 // require.Error(t, gotErr) 157 // return 158 // } 159 // require.NoError(t, gotErr) 160 // if spec.expNil { 161 // return 162 // } 163 // require.NotNil(t, c.Extension) 164 // assert.NotNil(t, c.Extension.GetCachedValue()) 165 // }) 166 // } 167 //} 168 // 169 //func TestContractInfoMarshalUnmarshal(t *testing.T) { 170 // var myAddr sdk.AccAddress = rand.Bytes(ContractAddrLen) 171 // var myOtherAddr sdk.AccAddress = rand.Bytes(ContractAddrLen) 172 // anyPos := AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2} 173 // 174 // anyTime := time.Now().UTC() 175 // // using gov proposal here as a random protobuf types as it contains an Any type inside for nested unpacking 176 // myExtension, err := govtypes.NewProposal(&govtypes.TextProposal{Title: "bar"}, 1, anyTime, anyTime) 177 // require.NoError(t, err) 178 // myExtension.TotalDeposit = nil 179 // 180 // src := NewContractInfo(1, myAddr, myOtherAddr, "bar", &anyPos) 181 // err = src.SetExtension(&myExtension) 182 // require.NoError(t, err) 183 // 184 // interfaceRegistry := types.NewInterfaceRegistry() 185 // marshaler := codec.NewProtoCodec(interfaceRegistry) 186 // RegisterInterfaces(interfaceRegistry) 187 // // register proposal as extension type 188 // interfaceRegistry.RegisterImplementations( 189 // (*ContractInfoExtension)(nil), 190 // &govtypes.Proposal{}, 191 // ) 192 // // register gov types for nested Anys 193 // govtypes.RegisterInterfaces(interfaceRegistry) 194 // 195 // // when encode 196 // bz, err := marshaler.Marshal(&src) 197 // require.NoError(t, err) 198 // // and decode 199 // var dest ContractInfo 200 // err = marshaler.Unmarshal(bz, &dest) 201 // // then 202 // require.NoError(t, err) 203 // assert.Equal(t, src, dest) 204 // // and sanity check nested any 205 // var destExt govtypes.Proposal 206 // require.NoError(t, dest.ReadExtension(&destExt)) 207 // assert.Equal(t, destExt.GetTitle(), "bar") 208 //} 209 // 210 //func TestContractInfoReadExtension(t *testing.T) { 211 // anyTime := time.Now().UTC() 212 // myExtension, err := govtypes.NewProposal(&govtypes.TextProposal{Title: "foo"}, 1, anyTime, anyTime) 213 // require.NoError(t, err) 214 // type TestExtensionAsStruct struct { 215 // ContractInfoExtension 216 // } 217 // 218 // specs := map[string]struct { 219 // setup func(*ContractInfo) 220 // param func() ContractInfoExtension 221 // expVal ContractInfoExtension 222 // expErr bool 223 // }{ 224 // "all good": { 225 // setup: func(i *ContractInfo) { 226 // i.SetExtension(&myExtension) 227 // }, 228 // param: func() ContractInfoExtension { 229 // return &govtypes.Proposal{} 230 // }, 231 // expVal: &myExtension, 232 // }, 233 // "no extension set": { 234 // setup: func(i *ContractInfo) { 235 // }, 236 // param: func() ContractInfoExtension { 237 // return &govtypes.Proposal{} 238 // }, 239 // expVal: &govtypes.Proposal{}, 240 // }, 241 // "nil argument value": { 242 // setup: func(i *ContractInfo) { 243 // i.SetExtension(&myExtension) 244 // }, 245 // param: func() ContractInfoExtension { 246 // return nil 247 // }, 248 // expErr: true, 249 // }, 250 // "non matching types": { 251 // setup: func(i *ContractInfo) { 252 // i.SetExtension(&myExtension) 253 // }, 254 // param: func() ContractInfoExtension { 255 // return &govtypes.TextProposal{} 256 // }, 257 // expErr: true, 258 // }, 259 // "not a pointer argument": { 260 // setup: func(i *ContractInfo) { 261 // }, 262 // param: func() ContractInfoExtension { 263 // return TestExtensionAsStruct{} 264 // }, 265 // expErr: true, 266 // }, 267 // } 268 // for name, spec := range specs { 269 // t.Run(name, func(t *testing.T) { 270 // var c ContractInfo 271 // spec.setup(&c) 272 // // when 273 // 274 // gotValue := spec.param() 275 // gotErr := c.ReadExtension(gotValue) 276 // 277 // // then 278 // if spec.expErr { 279 // require.Error(t, gotErr) 280 // return 281 // } 282 // require.NoError(t, gotErr) 283 // assert.Equal(t, spec.expVal, gotValue) 284 // }) 285 // } 286 //} 287 288 func TestNewEnv(t *testing.T) { 289 myTime := time.Unix(0, 1619700924259075000) 290 ctx := (&sdk.Context{}).SetChainID("testing").SetContext(context.Background()) 291 t.Logf("++ unix: %d", myTime.UnixNano()) 292 var myContractAddr sdk.AccAddress = randBytes(ContractAddrLen) 293 specs := map[string]struct { 294 srcCtx sdk.Context 295 exp wasmvmtypes.Env 296 }{ 297 "all good with tx counter": { 298 srcCtx: WithTXCounter((*ctx).WithBlockHeight(1).WithBlockTime(myTime), 0), 299 exp: wasmvmtypes.Env{ 300 Block: wasmvmtypes.BlockInfo{ 301 Height: 1, 302 Time: 1619700924259075000, 303 ChainID: "testing", 304 }, 305 Contract: wasmvmtypes.ContractInfo{ 306 Address: myContractAddr.String(), 307 }, 308 Transaction: &wasmvmtypes.TransactionInfo{Index: 0}, 309 }, 310 }, 311 //"without tx counter": { 312 // srcCtx: (*ctx).WithBlockHeight(1).WithBlockTime(myTime), 313 // exp: wasmvmtypes.Env{ 314 // Block: wasmvmtypes.BlockInfo{ 315 // Height: 1, 316 // Time: 1619700924259075000, 317 // ChainID: "testing", 318 // }, 319 // Contract: wasmvmtypes.ContractInfo{ 320 // Address: myContractAddr.String(), 321 // }, 322 // }, 323 //}, 324 } 325 for name, spec := range specs { 326 t.Run(name, func(t *testing.T) { 327 assert.Equal(t, spec.exp, NewEnv(spec.srcCtx, myContractAddr)) 328 }) 329 } 330 } 331 332 func TestVerifyAddressLen(t *testing.T) { 333 specs := map[string]struct { 334 src []byte 335 expErr bool 336 }{ 337 "valid contract address": { 338 src: bytes.Repeat([]byte{1}, 32), 339 }, 340 "valid legacy address": { 341 src: bytes.Repeat([]byte{1}, 20), 342 }, 343 "address too short for legacy": { 344 src: bytes.Repeat([]byte{1}, 19), 345 expErr: true, 346 }, 347 "address too short for contract": { 348 src: bytes.Repeat([]byte{1}, 31), 349 expErr: true, 350 }, 351 "address too long for legacy": { 352 src: bytes.Repeat([]byte{1}, 21), 353 expErr: true, 354 }, 355 "address too long for contract": { 356 src: bytes.Repeat([]byte{1}, 33), 357 expErr: true, 358 }, 359 } 360 for name, spec := range specs { 361 t.Run(name, func(t *testing.T) { 362 gotErr := VerifyAddressLen()(spec.src) 363 if spec.expErr { 364 require.Error(t, gotErr) 365 return 366 } 367 require.NoError(t, gotErr) 368 }) 369 } 370 } 371 372 func TestAccesConfigSubset(t *testing.T) { 373 specs := map[string]struct { 374 check AccessConfig 375 superSet AccessConfig 376 isSubSet bool 377 }{ 378 "nobody <= nobody": { 379 superSet: AccessConfig{Permission: AccessTypeNobody}, 380 check: AccessConfig{Permission: AccessTypeNobody}, 381 isSubSet: true, 382 }, 383 "only > nobody": { 384 superSet: AccessConfig{Permission: AccessTypeNobody}, 385 check: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "foobar"}, 386 isSubSet: false, 387 }, 388 "everybody > nobody": { 389 superSet: AccessConfig{Permission: AccessTypeNobody}, 390 check: AccessConfig{Permission: AccessTypeEverybody}, 391 isSubSet: false, 392 }, 393 "unspecified > nobody": { 394 superSet: AccessConfig{Permission: AccessTypeNobody}, 395 check: AccessConfig{Permission: AccessTypeUnspecified}, 396 isSubSet: false, 397 }, 398 "nobody <= everybody": { 399 superSet: AccessConfig{Permission: AccessTypeEverybody}, 400 check: AccessConfig{Permission: AccessTypeNobody}, 401 isSubSet: true, 402 }, 403 "only <= everybody": { 404 superSet: AccessConfig{Permission: AccessTypeEverybody}, 405 check: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "foobar"}, 406 isSubSet: true, 407 }, 408 "everybody <= everybody": { 409 superSet: AccessConfig{Permission: AccessTypeEverybody}, 410 check: AccessConfig{Permission: AccessTypeEverybody}, 411 isSubSet: true, 412 }, 413 "unspecified > everybody": { 414 superSet: AccessConfig{Permission: AccessTypeEverybody}, 415 check: AccessConfig{Permission: AccessTypeUnspecified}, 416 isSubSet: false, 417 }, 418 "nobody <= only": { 419 superSet: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "owner"}, 420 check: AccessConfig{Permission: AccessTypeNobody}, 421 isSubSet: true, 422 }, 423 "only <= only(same)": { 424 superSet: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "owner"}, 425 check: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "owner"}, 426 isSubSet: true, 427 }, 428 "only > only(other)": { 429 superSet: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "owner"}, 430 check: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "other"}, 431 isSubSet: false, 432 }, 433 "everybody > only": { 434 superSet: AccessConfig{Permission: AccessTypeOnlyAddress, Address: "owner"}, 435 check: AccessConfig{Permission: AccessTypeEverybody}, 436 isSubSet: false, 437 }, 438 "nobody > unspecified": { 439 superSet: AccessConfig{Permission: AccessTypeUnspecified}, 440 check: AccessConfig{Permission: AccessTypeNobody}, 441 isSubSet: false, 442 }, 443 } 444 445 for name, spec := range specs { 446 t.Run(name, func(t *testing.T) { 447 subset := spec.check.IsSubset(spec.superSet) 448 require.Equal(t, spec.isSubSet, subset) 449 }) 450 } 451 }