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  }