github.com/ava-labs/avalanchego@v1.11.11/vms/components/avax/transferables_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 avax
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/ava-labs/avalanchego/codec"
    12  	"github.com/ava-labs/avalanchego/codec/linearcodec"
    13  	"github.com/ava-labs/avalanchego/ids"
    14  	"github.com/ava-labs/avalanchego/utils"
    15  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    16  )
    17  
    18  func TestTransferableOutputVerifyNil(t *testing.T) {
    19  	to := (*TransferableOutput)(nil)
    20  	err := to.Verify()
    21  	require.ErrorIs(t, err, ErrNilTransferableOutput)
    22  }
    23  
    24  func TestTransferableOutputVerifyNilFx(t *testing.T) {
    25  	to := &TransferableOutput{Asset: Asset{ID: ids.Empty}}
    26  	err := to.Verify()
    27  	require.ErrorIs(t, err, ErrNilTransferableFxOutput)
    28  }
    29  
    30  func TestTransferableOutputVerify(t *testing.T) {
    31  	require := require.New(t)
    32  
    33  	assetID := ids.GenerateTestID()
    34  	to := &TransferableOutput{
    35  		Asset: Asset{ID: assetID},
    36  		Out:   &TestTransferable{Val: 1},
    37  	}
    38  	require.NoError(to.Verify())
    39  	require.Equal(to.Out, to.Output())
    40  }
    41  
    42  func TestTransferableOutputSorting(t *testing.T) {
    43  	require := require.New(t)
    44  
    45  	c := linearcodec.NewDefault()
    46  	require.NoError(c.RegisterType(&TestTransferable{}))
    47  	manager := codec.NewDefaultManager()
    48  	require.NoError(manager.RegisterCodec(codecVersion, c))
    49  
    50  	assetID1 := ids.ID{1}
    51  	outs := []*TransferableOutput{
    52  		{
    53  			Asset: Asset{ID: assetID1},
    54  			Out:   &TestTransferable{Val: 1},
    55  		},
    56  		{
    57  			Asset: Asset{ID: ids.Empty},
    58  			Out:   &TestTransferable{Val: 1},
    59  		},
    60  		{
    61  			Asset: Asset{ID: assetID1},
    62  			Out:   &TestTransferable{Val: 0},
    63  		},
    64  		{
    65  			Asset: Asset{ID: ids.Empty},
    66  			Out:   &TestTransferable{Val: 0},
    67  		},
    68  		{
    69  			Asset: Asset{ID: ids.Empty},
    70  			Out:   &TestTransferable{Val: 0},
    71  		},
    72  	}
    73  
    74  	require.False(IsSortedTransferableOutputs(outs, manager))
    75  	SortTransferableOutputs(outs, manager)
    76  	require.True(IsSortedTransferableOutputs(outs, manager))
    77  	require.Zero(outs[0].Out.(*TestTransferable).Val)
    78  	require.Zero(outs[1].Out.(*TestTransferable).Val)
    79  	require.Equal(uint64(1), outs[2].Out.(*TestTransferable).Val)
    80  	require.Equal(assetID1, outs[3].AssetID())
    81  	require.Equal(assetID1, outs[4].AssetID())
    82  }
    83  
    84  func TestTransferableOutputSerialization(t *testing.T) {
    85  	require := require.New(t)
    86  
    87  	c := linearcodec.NewDefault()
    88  	require.NoError(c.RegisterType(&secp256k1fx.TransferOutput{}))
    89  	manager := codec.NewDefaultManager()
    90  	require.NoError(manager.RegisterCodec(codecVersion, c))
    91  
    92  	expected := []byte{
    93  		// Codec version
    94  		0x00, 0x00,
    95  		// assetID:
    96  		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    97  		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    98  		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    99  		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   100  		// output:
   101  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   102  		0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x00,
   103  		0x00, 0x00, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x01,
   104  		0x00, 0x00, 0x00, 0x02, 0x51, 0x02, 0x5c, 0x61,
   105  		0xfb, 0xcf, 0xc0, 0x78, 0xf6, 0x93, 0x34, 0xf8,
   106  		0x34, 0xbe, 0x6d, 0xd2, 0x6d, 0x55, 0xa9, 0x55,
   107  		0xc3, 0x34, 0x41, 0x28, 0xe0, 0x60, 0x12, 0x8e,
   108  		0xde, 0x35, 0x23, 0xa2, 0x4a, 0x46, 0x1c, 0x89,
   109  		0x43, 0xab, 0x08, 0x59,
   110  	}
   111  
   112  	out := &TransferableOutput{
   113  		Asset: Asset{
   114  			ID: ids.ID{
   115  				0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   116  				0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   117  				0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   118  				0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   119  			},
   120  		},
   121  		Out: &secp256k1fx.TransferOutput{
   122  			Amt: 12345,
   123  			OutputOwners: secp256k1fx.OutputOwners{
   124  				Locktime:  54321,
   125  				Threshold: 1,
   126  				Addrs: []ids.ShortID{
   127  					{
   128  						0x51, 0x02, 0x5c, 0x61, 0xfb, 0xcf, 0xc0, 0x78,
   129  						0xf6, 0x93, 0x34, 0xf8, 0x34, 0xbe, 0x6d, 0xd2,
   130  						0x6d, 0x55, 0xa9, 0x55,
   131  					},
   132  					{
   133  						0xc3, 0x34, 0x41, 0x28, 0xe0, 0x60, 0x12, 0x8e,
   134  						0xde, 0x35, 0x23, 0xa2, 0x4a, 0x46, 0x1c, 0x89,
   135  						0x43, 0xab, 0x08, 0x59,
   136  					},
   137  				},
   138  			},
   139  		},
   140  	}
   141  
   142  	outBytes, err := manager.Marshal(codecVersion, out)
   143  	require.NoError(err)
   144  	require.Equal(expected, outBytes)
   145  }
   146  
   147  func TestTransferableInputVerifyNil(t *testing.T) {
   148  	ti := (*TransferableInput)(nil)
   149  	err := ti.Verify()
   150  	require.ErrorIs(t, err, ErrNilTransferableInput)
   151  }
   152  
   153  func TestTransferableInputVerifyNilFx(t *testing.T) {
   154  	ti := &TransferableInput{
   155  		UTXOID: UTXOID{TxID: ids.Empty},
   156  		Asset:  Asset{ID: ids.Empty},
   157  	}
   158  	err := ti.Verify()
   159  	require.ErrorIs(t, err, ErrNilTransferableFxInput)
   160  }
   161  
   162  func TestTransferableInputVerify(t *testing.T) {
   163  	require := require.New(t)
   164  
   165  	assetID := ids.GenerateTestID()
   166  	ti := &TransferableInput{
   167  		UTXOID: UTXOID{TxID: assetID},
   168  		Asset:  Asset{ID: assetID},
   169  		In:     &TestTransferable{},
   170  	}
   171  	require.NoError(ti.Verify())
   172  	require.Equal(ti.In, ti.Input())
   173  }
   174  
   175  func TestTransferableInputSorting(t *testing.T) {
   176  	require := require.New(t)
   177  
   178  	c := linearcodec.NewDefault()
   179  	require.NoError(c.RegisterType(&TestTransferable{}))
   180  
   181  	ins := []*TransferableInput{
   182  		{
   183  			UTXOID: UTXOID{
   184  				TxID:        ids.ID{1},
   185  				OutputIndex: 1,
   186  			},
   187  			Asset: Asset{ID: ids.Empty},
   188  			In:    &TestTransferable{},
   189  		},
   190  		{
   191  			UTXOID: UTXOID{
   192  				TxID:        ids.ID{1},
   193  				OutputIndex: 0,
   194  			},
   195  			Asset: Asset{ID: ids.Empty},
   196  			In:    &TestTransferable{},
   197  		},
   198  		{
   199  			UTXOID: UTXOID{
   200  				TxID:        ids.Empty,
   201  				OutputIndex: 1,
   202  			},
   203  			Asset: Asset{ID: ids.Empty},
   204  			In:    &TestTransferable{},
   205  		},
   206  		{
   207  			UTXOID: UTXOID{
   208  				TxID:        ids.Empty,
   209  				OutputIndex: 0,
   210  			},
   211  			Asset: Asset{ID: ids.Empty},
   212  			In:    &TestTransferable{},
   213  		},
   214  	}
   215  
   216  	require.False(utils.IsSortedAndUnique(ins))
   217  	utils.Sort(ins)
   218  	require.True(utils.IsSortedAndUnique(ins))
   219  
   220  	ins = append(ins, &TransferableInput{
   221  		UTXOID: UTXOID{
   222  			TxID:        ids.Empty,
   223  			OutputIndex: 1,
   224  		},
   225  		Asset: Asset{ID: ids.Empty},
   226  		In:    &TestTransferable{},
   227  	})
   228  
   229  	require.False(utils.IsSortedAndUnique(ins))
   230  }
   231  
   232  func TestTransferableInputSerialization(t *testing.T) {
   233  	require := require.New(t)
   234  
   235  	c := linearcodec.NewDefault()
   236  	require.NoError(c.RegisterType(&secp256k1fx.TransferInput{}))
   237  	manager := codec.NewDefaultManager()
   238  	require.NoError(manager.RegisterCodec(codecVersion, c))
   239  
   240  	expected := []byte{
   241  		// Codec version
   242  		0x00, 0x00,
   243  		// txID:
   244  		0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81,
   245  		0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
   246  		0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
   247  		0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
   248  		// utxoIndex:
   249  		0x00, 0x00, 0x00, 0x05,
   250  		// assetID:
   251  		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   252  		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   253  		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   254  		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   255  		// input:
   256  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   257  		0x07, 0x5b, 0xcd, 0x15, 0x00, 0x00, 0x00, 0x02,
   258  		0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07,
   259  	}
   260  
   261  	in := &TransferableInput{
   262  		UTXOID: UTXOID{
   263  			TxID: ids.ID{
   264  				0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81,
   265  				0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
   266  				0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
   267  				0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
   268  			},
   269  			OutputIndex: 5,
   270  		},
   271  		Asset: Asset{
   272  			ID: ids.ID{
   273  				0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   274  				0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   275  				0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   276  				0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   277  			},
   278  		},
   279  		In: &secp256k1fx.TransferInput{
   280  			Amt: 123456789,
   281  			Input: secp256k1fx.Input{
   282  				SigIndices: []uint32{3, 7},
   283  			},
   284  		},
   285  	}
   286  
   287  	inBytes, err := manager.Marshal(codecVersion, in)
   288  	require.NoError(err)
   289  	require.Equal(expected, inBytes)
   290  }