github.com/ava-labs/avalanchego@v1.11.11/vms/secp256k1fx/fx_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package secp256k1fx
     5  
     6  import (
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/ava-labs/avalanchego/codec/linearcodec"
    13  	"github.com/ava-labs/avalanchego/ids"
    14  	"github.com/ava-labs/avalanchego/utils/cb58"
    15  	"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
    16  	"github.com/ava-labs/avalanchego/utils/logging"
    17  )
    18  
    19  var (
    20  	txBytes  = []byte{0, 1, 2, 3, 4, 5}
    21  	sigBytes = [secp256k1.SignatureLen]byte{ // signature of addr on txBytes
    22  		0x0e, 0x33, 0x4e, 0xbc, 0x67, 0xa7, 0x3f, 0xe8,
    23  		0x24, 0x33, 0xac, 0xa3, 0x47, 0x88, 0xa6, 0x3d,
    24  		0x58, 0xe5, 0x8e, 0xf0, 0x3a, 0xd5, 0x84, 0xf1,
    25  		0xbc, 0xa3, 0xb2, 0xd2, 0x5d, 0x51, 0xd6, 0x9b,
    26  		0x0f, 0x28, 0x5d, 0xcd, 0x3f, 0x71, 0x17, 0x0a,
    27  		0xf9, 0xbf, 0x2d, 0xb1, 0x10, 0x26, 0x5c, 0xe9,
    28  		0xdc, 0xc3, 0x9d, 0x7a, 0x01, 0x50, 0x9d, 0xe8,
    29  		0x35, 0xbd, 0xcb, 0x29, 0x3a, 0xd1, 0x49, 0x32,
    30  		0x00,
    31  	}
    32  	addr = ids.ShortID{
    33  		0x01, 0x5c, 0xce, 0x6c, 0x55, 0xd6, 0xb5, 0x09,
    34  		0x84, 0x5c, 0x8c, 0x4e, 0x30, 0xbe, 0xd9, 0x8d,
    35  		0x39, 0x1a, 0xe7, 0xf0,
    36  	}
    37  	addr2     ids.ShortID
    38  	sig2Bytes [secp256k1.SignatureLen]byte // signature of addr2 on txBytes
    39  )
    40  
    41  func init() {
    42  	b, err := cb58.Decode("31SoC6ehdWUWFcuzkXci7ymFEQ8HGTJgw")
    43  	if err != nil {
    44  		panic(err)
    45  	}
    46  	copy(addr2[:], b)
    47  	b, err = cb58.Decode("c7doHa86hWYyfXTVnNsdP1CG1gxhXVpZ9Q5CiHi2oFRdnaxh2YR2Mvu2cUNMgyQy4BNQaXAxWWPt36BJ5pDWX1Xeos4h9L")
    48  	if err != nil {
    49  		panic(err)
    50  	}
    51  	copy(sig2Bytes[:], b)
    52  }
    53  
    54  func TestFxInitialize(t *testing.T) {
    55  	vm := TestVM{
    56  		Codec: linearcodec.NewDefault(),
    57  		Log:   logging.NoLog{},
    58  	}
    59  	fx := Fx{}
    60  	require.NoError(t, fx.Initialize(&vm))
    61  }
    62  
    63  func TestFxInitializeInvalid(t *testing.T) {
    64  	fx := Fx{}
    65  	err := fx.Initialize(nil)
    66  	require.ErrorIs(t, err, ErrWrongVMType)
    67  }
    68  
    69  func TestFxVerifyTransfer(t *testing.T) {
    70  	require := require.New(t)
    71  	vm := TestVM{
    72  		Codec: linearcodec.NewDefault(),
    73  		Log:   logging.NoLog{},
    74  	}
    75  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
    76  	vm.Clk.Set(date)
    77  	fx := Fx{}
    78  	require.NoError(fx.Initialize(&vm))
    79  	require.NoError(fx.Bootstrapping())
    80  	require.NoError(fx.Bootstrapped())
    81  	tx := &TestTx{UnsignedBytes: txBytes}
    82  	out := &TransferOutput{
    83  		Amt: 1,
    84  		OutputOwners: OutputOwners{
    85  			Locktime:  0,
    86  			Threshold: 1,
    87  			Addrs: []ids.ShortID{
    88  				addr,
    89  			},
    90  		},
    91  	}
    92  	in := &TransferInput{
    93  		Amt: 1,
    94  		Input: Input{
    95  			SigIndices: []uint32{0},
    96  		},
    97  	}
    98  	cred := &Credential{
    99  		Sigs: [][secp256k1.SignatureLen]byte{
   100  			sigBytes,
   101  		},
   102  	}
   103  
   104  	require.NoError(fx.VerifyTransfer(tx, in, cred, out))
   105  }
   106  
   107  func TestFxVerifyTransferNilTx(t *testing.T) {
   108  	require := require.New(t)
   109  	vm := TestVM{
   110  		Codec: linearcodec.NewDefault(),
   111  		Log:   logging.NoLog{},
   112  	}
   113  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   114  	vm.Clk.Set(date)
   115  	fx := Fx{}
   116  	require.NoError(fx.Initialize(&vm))
   117  	out := &TransferOutput{
   118  		Amt: 1,
   119  		OutputOwners: OutputOwners{
   120  			Locktime:  0,
   121  			Threshold: 1,
   122  			Addrs: []ids.ShortID{
   123  				addr,
   124  			},
   125  		},
   126  	}
   127  	in := &TransferInput{
   128  		Amt: 1,
   129  		Input: Input{
   130  			SigIndices: []uint32{0},
   131  		},
   132  	}
   133  	cred := &Credential{
   134  		Sigs: [][secp256k1.SignatureLen]byte{
   135  			sigBytes,
   136  		},
   137  	}
   138  
   139  	err := fx.VerifyTransfer(nil, in, cred, out)
   140  	require.ErrorIs(err, ErrWrongTxType)
   141  }
   142  
   143  func TestFxVerifyTransferNilOutput(t *testing.T) {
   144  	require := require.New(t)
   145  	vm := TestVM{
   146  		Codec: linearcodec.NewDefault(),
   147  		Log:   logging.NoLog{},
   148  	}
   149  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   150  	vm.Clk.Set(date)
   151  	fx := Fx{}
   152  	require.NoError(fx.Initialize(&vm))
   153  	tx := &TestTx{UnsignedBytes: txBytes}
   154  	in := &TransferInput{
   155  		Amt: 1,
   156  		Input: Input{
   157  			SigIndices: []uint32{0},
   158  		},
   159  	}
   160  	cred := &Credential{
   161  		Sigs: [][secp256k1.SignatureLen]byte{
   162  			sigBytes,
   163  		},
   164  	}
   165  
   166  	err := fx.VerifyTransfer(tx, in, cred, nil)
   167  	require.ErrorIs(err, ErrWrongUTXOType)
   168  }
   169  
   170  func TestFxVerifyTransferNilInput(t *testing.T) {
   171  	require := require.New(t)
   172  	vm := TestVM{
   173  		Codec: linearcodec.NewDefault(),
   174  		Log:   logging.NoLog{},
   175  	}
   176  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   177  	vm.Clk.Set(date)
   178  	fx := Fx{}
   179  	require.NoError(fx.Initialize(&vm))
   180  	tx := &TestTx{UnsignedBytes: txBytes}
   181  	out := &TransferOutput{
   182  		Amt: 1,
   183  		OutputOwners: OutputOwners{
   184  			Locktime:  0,
   185  			Threshold: 1,
   186  			Addrs: []ids.ShortID{
   187  				addr,
   188  			},
   189  		},
   190  	}
   191  	cred := &Credential{
   192  		Sigs: [][secp256k1.SignatureLen]byte{
   193  			sigBytes,
   194  		},
   195  	}
   196  
   197  	err := fx.VerifyTransfer(tx, nil, cred, out)
   198  	require.ErrorIs(err, ErrWrongInputType)
   199  }
   200  
   201  func TestFxVerifyTransferNilCredential(t *testing.T) {
   202  	require := require.New(t)
   203  	vm := TestVM{
   204  		Codec: linearcodec.NewDefault(),
   205  		Log:   logging.NoLog{},
   206  	}
   207  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   208  	vm.Clk.Set(date)
   209  	fx := Fx{}
   210  	require.NoError(fx.Initialize(&vm))
   211  	tx := &TestTx{UnsignedBytes: txBytes}
   212  	out := &TransferOutput{
   213  		Amt: 1,
   214  		OutputOwners: OutputOwners{
   215  			Locktime:  0,
   216  			Threshold: 1,
   217  			Addrs: []ids.ShortID{
   218  				addr,
   219  			},
   220  		},
   221  	}
   222  	in := &TransferInput{
   223  		Amt: 1,
   224  		Input: Input{
   225  			SigIndices: []uint32{0},
   226  		},
   227  	}
   228  
   229  	err := fx.VerifyTransfer(tx, in, nil, out)
   230  	require.ErrorIs(err, ErrWrongCredentialType)
   231  }
   232  
   233  func TestFxVerifyTransferInvalidOutput(t *testing.T) {
   234  	require := require.New(t)
   235  	vm := TestVM{
   236  		Codec: linearcodec.NewDefault(),
   237  		Log:   logging.NoLog{},
   238  	}
   239  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   240  	vm.Clk.Set(date)
   241  	fx := Fx{}
   242  	require.NoError(fx.Initialize(&vm))
   243  	tx := &TestTx{UnsignedBytes: txBytes}
   244  	out := &TransferOutput{
   245  		Amt: 1,
   246  		OutputOwners: OutputOwners{
   247  			Locktime:  0,
   248  			Threshold: 0,
   249  			Addrs: []ids.ShortID{
   250  				addr,
   251  			},
   252  		},
   253  	}
   254  	in := &TransferInput{
   255  		Amt: 1,
   256  		Input: Input{
   257  			SigIndices: []uint32{0},
   258  		},
   259  	}
   260  	cred := &Credential{
   261  		Sigs: [][secp256k1.SignatureLen]byte{
   262  			sigBytes,
   263  		},
   264  	}
   265  
   266  	err := fx.VerifyTransfer(tx, in, cred, out)
   267  	require.ErrorIs(err, ErrOutputUnoptimized)
   268  }
   269  
   270  func TestFxVerifyTransferWrongAmounts(t *testing.T) {
   271  	require := require.New(t)
   272  	vm := TestVM{
   273  		Codec: linearcodec.NewDefault(),
   274  		Log:   logging.NoLog{},
   275  	}
   276  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   277  	vm.Clk.Set(date)
   278  	fx := Fx{}
   279  	require.NoError(fx.Initialize(&vm))
   280  	tx := &TestTx{UnsignedBytes: txBytes}
   281  	out := &TransferOutput{
   282  		Amt: 1,
   283  		OutputOwners: OutputOwners{
   284  			Locktime:  0,
   285  			Threshold: 1,
   286  			Addrs: []ids.ShortID{
   287  				addr,
   288  			},
   289  		},
   290  	}
   291  	in := &TransferInput{
   292  		Amt: 2,
   293  		Input: Input{
   294  			SigIndices: []uint32{0},
   295  		},
   296  	}
   297  	cred := &Credential{
   298  		Sigs: [][secp256k1.SignatureLen]byte{
   299  			sigBytes,
   300  		},
   301  	}
   302  
   303  	err := fx.VerifyTransfer(tx, in, cred, out)
   304  	require.ErrorIs(err, ErrMismatchedAmounts)
   305  }
   306  
   307  func TestFxVerifyTransferTimelocked(t *testing.T) {
   308  	require := require.New(t)
   309  	vm := TestVM{
   310  		Codec: linearcodec.NewDefault(),
   311  		Log:   logging.NoLog{},
   312  	}
   313  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   314  	vm.Clk.Set(date)
   315  	fx := Fx{}
   316  	require.NoError(fx.Initialize(&vm))
   317  	tx := &TestTx{UnsignedBytes: txBytes}
   318  	out := &TransferOutput{
   319  		Amt: 1,
   320  		OutputOwners: OutputOwners{
   321  			Locktime:  uint64(date.Add(time.Second).Unix()),
   322  			Threshold: 1,
   323  			Addrs: []ids.ShortID{
   324  				addr,
   325  			},
   326  		},
   327  	}
   328  	in := &TransferInput{
   329  		Amt: 1,
   330  		Input: Input{
   331  			SigIndices: []uint32{0},
   332  		},
   333  	}
   334  	cred := &Credential{
   335  		Sigs: [][secp256k1.SignatureLen]byte{
   336  			sigBytes,
   337  		},
   338  	}
   339  
   340  	err := fx.VerifyTransfer(tx, in, cred, out)
   341  	require.ErrorIs(err, ErrTimelocked)
   342  }
   343  
   344  func TestFxVerifyTransferTooManySigners(t *testing.T) {
   345  	require := require.New(t)
   346  	vm := TestVM{
   347  		Codec: linearcodec.NewDefault(),
   348  		Log:   logging.NoLog{},
   349  	}
   350  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   351  	vm.Clk.Set(date)
   352  	fx := Fx{}
   353  	require.NoError(fx.Initialize(&vm))
   354  	tx := &TestTx{UnsignedBytes: txBytes}
   355  	out := &TransferOutput{
   356  		Amt: 1,
   357  		OutputOwners: OutputOwners{
   358  			Locktime:  0,
   359  			Threshold: 1,
   360  			Addrs: []ids.ShortID{
   361  				addr,
   362  			},
   363  		},
   364  	}
   365  	in := &TransferInput{
   366  		Amt: 1,
   367  		Input: Input{
   368  			SigIndices: []uint32{0, 1},
   369  		},
   370  	}
   371  	cred := &Credential{
   372  		Sigs: [][secp256k1.SignatureLen]byte{
   373  			sigBytes,
   374  			{},
   375  		},
   376  	}
   377  
   378  	err := fx.VerifyTransfer(tx, in, cred, out)
   379  	require.ErrorIs(err, ErrTooManySigners)
   380  }
   381  
   382  func TestFxVerifyTransferTooFewSigners(t *testing.T) {
   383  	require := require.New(t)
   384  	vm := TestVM{
   385  		Codec: linearcodec.NewDefault(),
   386  		Log:   logging.NoLog{},
   387  	}
   388  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   389  	vm.Clk.Set(date)
   390  	fx := Fx{}
   391  	require.NoError(fx.Initialize(&vm))
   392  	tx := &TestTx{UnsignedBytes: txBytes}
   393  	out := &TransferOutput{
   394  		Amt: 1,
   395  		OutputOwners: OutputOwners{
   396  			Locktime:  0,
   397  			Threshold: 1,
   398  			Addrs: []ids.ShortID{
   399  				addr,
   400  			},
   401  		},
   402  	}
   403  	in := &TransferInput{
   404  		Amt: 1,
   405  		Input: Input{
   406  			SigIndices: []uint32{},
   407  		},
   408  	}
   409  	cred := &Credential{
   410  		Sigs: [][secp256k1.SignatureLen]byte{},
   411  	}
   412  
   413  	err := fx.VerifyTransfer(tx, in, cred, out)
   414  	require.ErrorIs(err, ErrTooFewSigners)
   415  }
   416  
   417  func TestFxVerifyTransferMismatchedSigners(t *testing.T) {
   418  	require := require.New(t)
   419  	vm := TestVM{
   420  		Codec: linearcodec.NewDefault(),
   421  		Log:   logging.NoLog{},
   422  	}
   423  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   424  	vm.Clk.Set(date)
   425  	fx := Fx{}
   426  	require.NoError(fx.Initialize(&vm))
   427  	tx := &TestTx{UnsignedBytes: txBytes}
   428  	out := &TransferOutput{
   429  		Amt: 1,
   430  		OutputOwners: OutputOwners{
   431  			Locktime:  0,
   432  			Threshold: 1,
   433  			Addrs: []ids.ShortID{
   434  				addr,
   435  			},
   436  		},
   437  	}
   438  	in := &TransferInput{
   439  		Amt: 1,
   440  		Input: Input{
   441  			SigIndices: []uint32{0},
   442  		},
   443  	}
   444  	cred := &Credential{
   445  		Sigs: [][secp256k1.SignatureLen]byte{
   446  			sigBytes,
   447  			{},
   448  		},
   449  	}
   450  
   451  	err := fx.VerifyTransfer(tx, in, cred, out)
   452  	require.ErrorIs(err, ErrInputCredentialSignersMismatch)
   453  }
   454  
   455  func TestFxVerifyTransferInvalidSignature(t *testing.T) {
   456  	require := require.New(t)
   457  	vm := TestVM{
   458  		Codec: linearcodec.NewDefault(),
   459  		Log:   logging.NoLog{},
   460  	}
   461  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   462  	vm.Clk.Set(date)
   463  	fx := Fx{}
   464  	require.NoError(fx.Initialize(&vm))
   465  	require.NoError(fx.Bootstrapping())
   466  	tx := &TestTx{UnsignedBytes: txBytes}
   467  	out := &TransferOutput{
   468  		Amt: 1,
   469  		OutputOwners: OutputOwners{
   470  			Locktime:  0,
   471  			Threshold: 1,
   472  			Addrs: []ids.ShortID{
   473  				addr,
   474  			},
   475  		},
   476  	}
   477  	in := &TransferInput{
   478  		Amt: 1,
   479  		Input: Input{
   480  			SigIndices: []uint32{0},
   481  		},
   482  	}
   483  	cred := &Credential{
   484  		Sigs: [][secp256k1.SignatureLen]byte{
   485  			{},
   486  		},
   487  	}
   488  
   489  	require.NoError(fx.VerifyTransfer(tx, in, cred, out))
   490  	require.NoError(fx.Bootstrapped())
   491  	err := fx.VerifyTransfer(tx, in, cred, out)
   492  	require.ErrorIs(err, secp256k1.ErrInvalidSig)
   493  }
   494  
   495  func TestFxVerifyTransferWrongSigner(t *testing.T) {
   496  	require := require.New(t)
   497  	vm := TestVM{
   498  		Codec: linearcodec.NewDefault(),
   499  		Log:   logging.NoLog{},
   500  	}
   501  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   502  	vm.Clk.Set(date)
   503  	fx := Fx{}
   504  	require.NoError(fx.Initialize(&vm))
   505  	require.NoError(fx.Bootstrapping())
   506  	tx := &TestTx{UnsignedBytes: txBytes}
   507  	out := &TransferOutput{
   508  		Amt: 1,
   509  		OutputOwners: OutputOwners{
   510  			Locktime:  0,
   511  			Threshold: 1,
   512  			Addrs: []ids.ShortID{
   513  				ids.ShortEmpty,
   514  			},
   515  		},
   516  	}
   517  	in := &TransferInput{
   518  		Amt: 1,
   519  		Input: Input{
   520  			SigIndices: []uint32{0},
   521  		},
   522  	}
   523  	cred := &Credential{
   524  		Sigs: [][secp256k1.SignatureLen]byte{
   525  			sigBytes,
   526  		},
   527  	}
   528  
   529  	require.NoError(fx.VerifyTransfer(tx, in, cred, out))
   530  	require.NoError(fx.Bootstrapped())
   531  	err := fx.VerifyTransfer(tx, in, cred, out)
   532  	require.ErrorIs(err, ErrWrongSig)
   533  }
   534  
   535  func TestFxVerifyTransferSigIndexOOB(t *testing.T) {
   536  	require := require.New(t)
   537  	vm := TestVM{
   538  		Codec: linearcodec.NewDefault(),
   539  		Log:   logging.NoLog{},
   540  	}
   541  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   542  	vm.Clk.Set(date)
   543  	fx := Fx{}
   544  	require.NoError(fx.Initialize(&vm))
   545  	require.NoError(fx.Bootstrapping())
   546  	tx := &TestTx{UnsignedBytes: txBytes}
   547  	out := &TransferOutput{
   548  		Amt: 1,
   549  		OutputOwners: OutputOwners{
   550  			Locktime:  0,
   551  			Threshold: 1,
   552  			Addrs: []ids.ShortID{
   553  				addr,
   554  			},
   555  		},
   556  	}
   557  	in := &TransferInput{
   558  		Amt: 1,
   559  		Input: Input{
   560  			SigIndices: []uint32{1}, // There is no address at index 1
   561  		},
   562  	}
   563  	cred := &Credential{
   564  		Sigs: [][secp256k1.SignatureLen]byte{
   565  			sigBytes,
   566  		},
   567  	}
   568  
   569  	require.NoError(fx.VerifyTransfer(tx, in, cred, out))
   570  	require.NoError(fx.Bootstrapped())
   571  	err := fx.VerifyTransfer(tx, in, cred, out)
   572  	require.ErrorIs(err, ErrInputOutputIndexOutOfBounds)
   573  }
   574  
   575  func TestFxVerifyOperation(t *testing.T) {
   576  	require := require.New(t)
   577  	vm := TestVM{
   578  		Codec: linearcodec.NewDefault(),
   579  		Log:   logging.NoLog{},
   580  	}
   581  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   582  	vm.Clk.Set(date)
   583  	fx := Fx{}
   584  	require.NoError(fx.Initialize(&vm))
   585  	tx := &TestTx{UnsignedBytes: txBytes}
   586  	utxo := &MintOutput{
   587  		OutputOwners: OutputOwners{
   588  			Threshold: 1,
   589  			Addrs: []ids.ShortID{
   590  				addr,
   591  			},
   592  		},
   593  	}
   594  	op := &MintOperation{
   595  		MintInput: Input{
   596  			SigIndices: []uint32{0},
   597  		},
   598  		MintOutput: MintOutput{
   599  			OutputOwners: OutputOwners{
   600  				Threshold: 1,
   601  				Addrs: []ids.ShortID{
   602  					addr,
   603  				},
   604  			},
   605  		},
   606  		TransferOutput: TransferOutput{
   607  			Amt: 1,
   608  			OutputOwners: OutputOwners{
   609  				Locktime:  0,
   610  				Threshold: 1,
   611  				Addrs: []ids.ShortID{
   612  					addr,
   613  				},
   614  			},
   615  		},
   616  	}
   617  	cred := &Credential{
   618  		Sigs: [][secp256k1.SignatureLen]byte{
   619  			sigBytes,
   620  		},
   621  	}
   622  
   623  	utxos := []interface{}{utxo}
   624  	require.NoError(fx.VerifyOperation(tx, op, cred, utxos))
   625  }
   626  
   627  func TestFxVerifyOperationUnknownTx(t *testing.T) {
   628  	require := require.New(t)
   629  	vm := TestVM{
   630  		Codec: linearcodec.NewDefault(),
   631  		Log:   logging.NoLog{},
   632  	}
   633  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   634  	vm.Clk.Set(date)
   635  	fx := Fx{}
   636  	require.NoError(fx.Initialize(&vm))
   637  	utxo := &MintOutput{
   638  		OutputOwners: OutputOwners{
   639  			Threshold: 1,
   640  			Addrs: []ids.ShortID{
   641  				addr,
   642  			},
   643  		},
   644  	}
   645  	op := &MintOperation{
   646  		MintInput: Input{
   647  			SigIndices: []uint32{0},
   648  		},
   649  		MintOutput: MintOutput{
   650  			OutputOwners: OutputOwners{
   651  				Threshold: 1,
   652  				Addrs: []ids.ShortID{
   653  					addr,
   654  				},
   655  			},
   656  		},
   657  		TransferOutput: TransferOutput{
   658  			Amt: 1,
   659  			OutputOwners: OutputOwners{
   660  				Locktime:  0,
   661  				Threshold: 1,
   662  				Addrs: []ids.ShortID{
   663  					addr,
   664  				},
   665  			},
   666  		},
   667  	}
   668  	cred := &Credential{
   669  		Sigs: [][secp256k1.SignatureLen]byte{
   670  			sigBytes,
   671  		},
   672  	}
   673  
   674  	utxos := []interface{}{utxo}
   675  	err := fx.VerifyOperation(nil, op, cred, utxos)
   676  	require.ErrorIs(err, ErrWrongTxType)
   677  }
   678  
   679  func TestFxVerifyOperationUnknownOperation(t *testing.T) {
   680  	require := require.New(t)
   681  	vm := TestVM{
   682  		Codec: linearcodec.NewDefault(),
   683  		Log:   logging.NoLog{},
   684  	}
   685  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   686  	vm.Clk.Set(date)
   687  	fx := Fx{}
   688  	require.NoError(fx.Initialize(&vm))
   689  	tx := &TestTx{UnsignedBytes: txBytes}
   690  	utxo := &MintOutput{
   691  		OutputOwners: OutputOwners{
   692  			Threshold: 1,
   693  			Addrs: []ids.ShortID{
   694  				addr,
   695  			},
   696  		},
   697  	}
   698  	cred := &Credential{
   699  		Sigs: [][secp256k1.SignatureLen]byte{
   700  			sigBytes,
   701  		},
   702  	}
   703  
   704  	utxos := []interface{}{utxo}
   705  	err := fx.VerifyOperation(tx, nil, cred, utxos)
   706  	require.ErrorIs(err, ErrWrongOpType)
   707  }
   708  
   709  func TestFxVerifyOperationUnknownCredential(t *testing.T) {
   710  	require := require.New(t)
   711  	vm := TestVM{
   712  		Codec: linearcodec.NewDefault(),
   713  		Log:   logging.NoLog{},
   714  	}
   715  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   716  	vm.Clk.Set(date)
   717  	fx := Fx{}
   718  	require.NoError(fx.Initialize(&vm))
   719  	tx := &TestTx{UnsignedBytes: txBytes}
   720  	utxo := &MintOutput{
   721  		OutputOwners: OutputOwners{
   722  			Threshold: 1,
   723  			Addrs: []ids.ShortID{
   724  				addr,
   725  			},
   726  		},
   727  	}
   728  	op := &MintOperation{
   729  		MintInput: Input{
   730  			SigIndices: []uint32{0},
   731  		},
   732  		MintOutput: MintOutput{
   733  			OutputOwners: OutputOwners{
   734  				Threshold: 1,
   735  				Addrs: []ids.ShortID{
   736  					addr,
   737  				},
   738  			},
   739  		},
   740  		TransferOutput: TransferOutput{
   741  			Amt: 1,
   742  			OutputOwners: OutputOwners{
   743  				Locktime:  0,
   744  				Threshold: 1,
   745  				Addrs: []ids.ShortID{
   746  					addr,
   747  				},
   748  			},
   749  		},
   750  	}
   751  
   752  	utxos := []interface{}{utxo}
   753  	err := fx.VerifyOperation(tx, op, nil, utxos)
   754  	require.ErrorIs(err, ErrWrongCredentialType)
   755  }
   756  
   757  func TestFxVerifyOperationWrongNumberOfUTXOs(t *testing.T) {
   758  	require := require.New(t)
   759  	vm := TestVM{
   760  		Codec: linearcodec.NewDefault(),
   761  		Log:   logging.NoLog{},
   762  	}
   763  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   764  	vm.Clk.Set(date)
   765  	fx := Fx{}
   766  	require.NoError(fx.Initialize(&vm))
   767  	tx := &TestTx{UnsignedBytes: txBytes}
   768  	utxo := &MintOutput{
   769  		OutputOwners: OutputOwners{
   770  			Threshold: 1,
   771  			Addrs: []ids.ShortID{
   772  				addr,
   773  			},
   774  		},
   775  	}
   776  	op := &MintOperation{
   777  		MintInput: Input{
   778  			SigIndices: []uint32{0},
   779  		},
   780  		MintOutput: MintOutput{
   781  			OutputOwners: OutputOwners{
   782  				Threshold: 1,
   783  				Addrs: []ids.ShortID{
   784  					addr,
   785  				},
   786  			},
   787  		},
   788  		TransferOutput: TransferOutput{
   789  			Amt: 1,
   790  			OutputOwners: OutputOwners{
   791  				Locktime:  0,
   792  				Threshold: 1,
   793  				Addrs: []ids.ShortID{
   794  					addr,
   795  				},
   796  			},
   797  		},
   798  	}
   799  	cred := &Credential{
   800  		Sigs: [][secp256k1.SignatureLen]byte{
   801  			sigBytes,
   802  		},
   803  	}
   804  
   805  	utxos := []interface{}{utxo, utxo}
   806  	err := fx.VerifyOperation(tx, op, cred, utxos)
   807  	require.ErrorIs(err, ErrWrongNumberOfUTXOs)
   808  }
   809  
   810  func TestFxVerifyOperationUnknownUTXOType(t *testing.T) {
   811  	require := require.New(t)
   812  	vm := TestVM{
   813  		Codec: linearcodec.NewDefault(),
   814  		Log:   logging.NoLog{},
   815  	}
   816  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   817  	vm.Clk.Set(date)
   818  	fx := Fx{}
   819  	require.NoError(fx.Initialize(&vm))
   820  	tx := &TestTx{UnsignedBytes: txBytes}
   821  	op := &MintOperation{
   822  		MintInput: Input{
   823  			SigIndices: []uint32{0},
   824  		},
   825  		MintOutput: MintOutput{
   826  			OutputOwners: OutputOwners{
   827  				Threshold: 1,
   828  				Addrs: []ids.ShortID{
   829  					addr,
   830  				},
   831  			},
   832  		},
   833  		TransferOutput: TransferOutput{
   834  			Amt: 1,
   835  			OutputOwners: OutputOwners{
   836  				Locktime:  0,
   837  				Threshold: 1,
   838  				Addrs: []ids.ShortID{
   839  					addr,
   840  				},
   841  			},
   842  		},
   843  	}
   844  	cred := &Credential{
   845  		Sigs: [][secp256k1.SignatureLen]byte{
   846  			sigBytes,
   847  		},
   848  	}
   849  
   850  	utxos := []interface{}{nil}
   851  	err := fx.VerifyOperation(tx, op, cred, utxos)
   852  	require.ErrorIs(err, ErrWrongUTXOType)
   853  }
   854  
   855  func TestFxVerifyOperationInvalidOperationVerify(t *testing.T) {
   856  	require := require.New(t)
   857  	vm := TestVM{
   858  		Codec: linearcodec.NewDefault(),
   859  		Log:   logging.NoLog{},
   860  	}
   861  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   862  	vm.Clk.Set(date)
   863  	fx := Fx{}
   864  	require.NoError(fx.Initialize(&vm))
   865  	tx := &TestTx{UnsignedBytes: txBytes}
   866  	utxo := &MintOutput{
   867  		OutputOwners: OutputOwners{
   868  			Threshold: 1,
   869  			Addrs: []ids.ShortID{
   870  				addr,
   871  			},
   872  		},
   873  	}
   874  	op := &MintOperation{
   875  		MintInput: Input{
   876  			SigIndices: []uint32{0},
   877  		},
   878  		MintOutput: MintOutput{
   879  			OutputOwners: OutputOwners{
   880  				Threshold: 1,
   881  				Addrs: []ids.ShortID{
   882  					addr,
   883  				},
   884  			},
   885  		},
   886  		TransferOutput: TransferOutput{
   887  			Amt: 1,
   888  			OutputOwners: OutputOwners{
   889  				Locktime:  0,
   890  				Threshold: 1,
   891  			},
   892  		},
   893  	}
   894  	cred := &Credential{
   895  		Sigs: [][secp256k1.SignatureLen]byte{
   896  			sigBytes,
   897  		},
   898  	}
   899  
   900  	utxos := []interface{}{utxo}
   901  	err := fx.VerifyOperation(tx, op, cred, utxos)
   902  	require.ErrorIs(err, ErrOutputUnspendable)
   903  }
   904  
   905  func TestFxVerifyOperationMismatchedMintOutputs(t *testing.T) {
   906  	require := require.New(t)
   907  	vm := TestVM{
   908  		Codec: linearcodec.NewDefault(),
   909  		Log:   logging.NoLog{},
   910  	}
   911  	date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
   912  	vm.Clk.Set(date)
   913  	fx := Fx{}
   914  	require.NoError(fx.Initialize(&vm))
   915  	tx := &TestTx{UnsignedBytes: txBytes}
   916  	utxo := &MintOutput{
   917  		OutputOwners: OutputOwners{
   918  			Threshold: 1,
   919  			Addrs: []ids.ShortID{
   920  				addr,
   921  			},
   922  		},
   923  	}
   924  	op := &MintOperation{
   925  		MintInput: Input{
   926  			SigIndices: []uint32{0},
   927  		},
   928  		MintOutput: MintOutput{
   929  			OutputOwners: OutputOwners{},
   930  		},
   931  		TransferOutput: TransferOutput{
   932  			Amt: 1,
   933  			OutputOwners: OutputOwners{
   934  				Locktime:  0,
   935  				Threshold: 1,
   936  				Addrs: []ids.ShortID{
   937  					addr,
   938  				},
   939  			},
   940  		},
   941  	}
   942  	cred := &Credential{
   943  		Sigs: [][secp256k1.SignatureLen]byte{
   944  			sigBytes,
   945  		},
   946  	}
   947  
   948  	utxos := []interface{}{utxo}
   949  	err := fx.VerifyOperation(tx, op, cred, utxos)
   950  	require.ErrorIs(err, ErrWrongMintCreated)
   951  }
   952  
   953  func TestVerifyPermission(t *testing.T) {
   954  	vm := TestVM{
   955  		Codec: linearcodec.NewDefault(),
   956  		Log:   logging.NoLog{},
   957  	}
   958  	fx := Fx{}
   959  	require.NoError(t, fx.Initialize(&vm))
   960  	require.NoError(t, fx.Bootstrapping())
   961  	require.NoError(t, fx.Bootstrapped())
   962  
   963  	now := time.Now()
   964  	fx.VM.Clock().Set(now)
   965  
   966  	type test struct {
   967  		description string
   968  		tx          UnsignedTx
   969  		in          *Input
   970  		cred        *Credential
   971  		cg          *OutputOwners
   972  		expectedErr error
   973  	}
   974  	tests := []test{
   975  		{
   976  			"threshold 0, no sigs, has addrs",
   977  			&TestTx{UnsignedBytes: txBytes},
   978  			&Input{SigIndices: []uint32{}},
   979  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{}},
   980  			&OutputOwners{
   981  				Threshold: 0,
   982  				Addrs:     []ids.ShortID{addr},
   983  			},
   984  			ErrOutputUnoptimized,
   985  		},
   986  		{
   987  			"threshold 0, no sigs, no addrs",
   988  			&TestTx{UnsignedBytes: txBytes},
   989  			&Input{SigIndices: []uint32{}},
   990  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{}},
   991  			&OutputOwners{
   992  				Threshold: 0,
   993  				Addrs:     []ids.ShortID{},
   994  			},
   995  			nil,
   996  		},
   997  		{
   998  			"threshold 1, 1 sig",
   999  			&TestTx{UnsignedBytes: txBytes},
  1000  			&Input{SigIndices: []uint32{0}},
  1001  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes}},
  1002  			&OutputOwners{
  1003  				Threshold: 1,
  1004  				Addrs:     []ids.ShortID{addr},
  1005  			},
  1006  			nil,
  1007  		},
  1008  		{
  1009  			"threshold 0, 1 sig (too many sigs)",
  1010  			&TestTx{UnsignedBytes: txBytes},
  1011  			&Input{SigIndices: []uint32{0}},
  1012  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes}},
  1013  			&OutputOwners{
  1014  				Threshold: 0,
  1015  				Addrs:     []ids.ShortID{addr},
  1016  			},
  1017  			ErrOutputUnoptimized,
  1018  		},
  1019  		{
  1020  			"threshold 1, 0 sigs (too few sigs)",
  1021  			&TestTx{UnsignedBytes: txBytes},
  1022  			&Input{SigIndices: []uint32{}},
  1023  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{}},
  1024  			&OutputOwners{
  1025  				Threshold: 1,
  1026  				Addrs:     []ids.ShortID{addr},
  1027  			},
  1028  			ErrTooFewSigners,
  1029  		},
  1030  		{
  1031  			"threshold 1, 1 incorrect sig",
  1032  			&TestTx{UnsignedBytes: txBytes},
  1033  			&Input{SigIndices: []uint32{0}},
  1034  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes}},
  1035  			&OutputOwners{
  1036  				Threshold: 1,
  1037  				Addrs:     []ids.ShortID{ids.GenerateTestShortID()},
  1038  			},
  1039  			ErrWrongSig,
  1040  		},
  1041  		{
  1042  			"repeated sig",
  1043  			&TestTx{UnsignedBytes: txBytes},
  1044  			&Input{SigIndices: []uint32{0, 0}},
  1045  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes, sigBytes}},
  1046  			&OutputOwners{
  1047  				Threshold: 2,
  1048  				Addrs:     []ids.ShortID{addr, addr2},
  1049  			},
  1050  			ErrInputIndicesNotSortedUnique,
  1051  		},
  1052  		{
  1053  			"threshold 2, repeated address and repeated sig",
  1054  			&TestTx{UnsignedBytes: txBytes},
  1055  			&Input{SigIndices: []uint32{0, 1}},
  1056  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes, sigBytes}},
  1057  			&OutputOwners{
  1058  				Threshold: 2,
  1059  				Addrs:     []ids.ShortID{addr, addr},
  1060  			},
  1061  			ErrAddrsNotSortedUnique,
  1062  		},
  1063  		{
  1064  			"threshold 2, 2 sigs",
  1065  			&TestTx{UnsignedBytes: txBytes},
  1066  			&Input{SigIndices: []uint32{0, 1}},
  1067  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes, sig2Bytes}},
  1068  			&OutputOwners{
  1069  				Threshold: 2,
  1070  				Addrs:     []ids.ShortID{addr, addr2},
  1071  			},
  1072  			nil,
  1073  		},
  1074  		{
  1075  			"threshold 2, 2 sigs reversed (should be sorted)",
  1076  			&TestTx{UnsignedBytes: txBytes},
  1077  			&Input{SigIndices: []uint32{1, 0}},
  1078  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sig2Bytes, sigBytes}},
  1079  			&OutputOwners{
  1080  				Threshold: 2,
  1081  				Addrs:     []ids.ShortID{addr, addr2},
  1082  			},
  1083  			ErrInputIndicesNotSortedUnique,
  1084  		},
  1085  		{
  1086  			"threshold 1, 1 sig, index out of bounds",
  1087  			&TestTx{UnsignedBytes: txBytes},
  1088  			&Input{SigIndices: []uint32{1}},
  1089  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes}},
  1090  			&OutputOwners{
  1091  				Threshold: 1,
  1092  				Addrs:     []ids.ShortID{addr},
  1093  			},
  1094  			ErrInputOutputIndexOutOfBounds,
  1095  		},
  1096  		{
  1097  			"too many signers",
  1098  			&TestTx{UnsignedBytes: txBytes},
  1099  			&Input{SigIndices: []uint32{0, 1}},
  1100  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes, sig2Bytes}},
  1101  			&OutputOwners{
  1102  				Threshold: 1,
  1103  				Addrs:     []ids.ShortID{addr, addr2},
  1104  			},
  1105  			ErrTooManySigners,
  1106  		},
  1107  		{
  1108  			"number of signatures doesn't match",
  1109  			&TestTx{UnsignedBytes: txBytes},
  1110  			&Input{SigIndices: []uint32{0}},
  1111  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes, sig2Bytes}},
  1112  			&OutputOwners{
  1113  				Threshold: 1,
  1114  				Addrs:     []ids.ShortID{addr, addr2},
  1115  			},
  1116  			ErrInputCredentialSignersMismatch,
  1117  		},
  1118  		{
  1119  			"output is locked",
  1120  			&TestTx{UnsignedBytes: txBytes},
  1121  			&Input{SigIndices: []uint32{0}},
  1122  			&Credential{Sigs: [][secp256k1.SignatureLen]byte{sigBytes, sig2Bytes}},
  1123  			&OutputOwners{
  1124  				Threshold: 1,
  1125  				Locktime:  uint64(now.Add(time.Second).Unix()),
  1126  				Addrs:     []ids.ShortID{addr, addr2},
  1127  			},
  1128  			ErrTimelocked,
  1129  		},
  1130  	}
  1131  
  1132  	for _, test := range tests {
  1133  		t.Run(test.description, func(t *testing.T) {
  1134  			err := fx.VerifyPermission(test.tx, test.in, test.cred, test.cg)
  1135  			require.ErrorIs(t, err, test.expectedErr)
  1136  		})
  1137  	}
  1138  }