github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/txs/add_permissionless_delegator_tx_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 txs
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"math"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"go.uber.org/mock/gomock"
    14  
    15  	"github.com/ava-labs/avalanchego/ids"
    16  	"github.com/ava-labs/avalanchego/snow"
    17  	"github.com/ava-labs/avalanchego/utils"
    18  	"github.com/ava-labs/avalanchego/utils/constants"
    19  	"github.com/ava-labs/avalanchego/utils/units"
    20  	"github.com/ava-labs/avalanchego/vms/components/avax"
    21  	"github.com/ava-labs/avalanchego/vms/components/avax/avaxmock"
    22  	"github.com/ava-labs/avalanchego/vms/platformvm/fx/fxmock"
    23  	"github.com/ava-labs/avalanchego/vms/platformvm/stakeable"
    24  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    25  	"github.com/ava-labs/avalanchego/vms/types"
    26  
    27  	safemath "github.com/ava-labs/avalanchego/utils/math"
    28  )
    29  
    30  var errCustom = errors.New("custom error")
    31  
    32  func TestAddPermissionlessPrimaryDelegatorSerialization(t *testing.T) {
    33  	require := require.New(t)
    34  
    35  	addr := ids.ShortID{
    36  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
    37  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
    38  		0x44, 0x55, 0x66, 0x77,
    39  	}
    40  
    41  	avaxAssetID, err := ids.FromString("FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z")
    42  	require.NoError(err)
    43  
    44  	customAssetID := ids.ID{
    45  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
    46  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
    47  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
    48  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
    49  	}
    50  
    51  	txID := ids.ID{
    52  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
    53  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
    54  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
    55  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
    56  	}
    57  	nodeID := ids.BuildTestNodeID([]byte{
    58  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    59  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    60  		0x11, 0x22, 0x33, 0x44,
    61  	})
    62  
    63  	simpleAddPrimaryTx := &AddPermissionlessDelegatorTx{
    64  		BaseTx: BaseTx{
    65  			BaseTx: avax.BaseTx{
    66  				NetworkID:    constants.MainnetID,
    67  				BlockchainID: constants.PlatformChainID,
    68  				Outs:         []*avax.TransferableOutput{},
    69  				Ins: []*avax.TransferableInput{
    70  					{
    71  						UTXOID: avax.UTXOID{
    72  							TxID:        txID,
    73  							OutputIndex: 1,
    74  						},
    75  						Asset: avax.Asset{
    76  							ID: avaxAssetID,
    77  						},
    78  						In: &secp256k1fx.TransferInput{
    79  							Amt: 2 * units.KiloAvax,
    80  							Input: secp256k1fx.Input{
    81  								SigIndices: []uint32{1},
    82  							},
    83  						},
    84  					},
    85  				},
    86  				Memo: types.JSONByteSlice{},
    87  			},
    88  		},
    89  		Validator: Validator{
    90  			NodeID: nodeID,
    91  			Start:  12345,
    92  			End:    12345 + 200*24*60*60,
    93  			Wght:   2 * units.KiloAvax,
    94  		},
    95  		Subnet: constants.PrimaryNetworkID,
    96  		StakeOuts: []*avax.TransferableOutput{
    97  			{
    98  				Asset: avax.Asset{
    99  					ID: avaxAssetID,
   100  				},
   101  				Out: &secp256k1fx.TransferOutput{
   102  					Amt: 2 * units.KiloAvax,
   103  					OutputOwners: secp256k1fx.OutputOwners{
   104  						Locktime:  0,
   105  						Threshold: 1,
   106  						Addrs: []ids.ShortID{
   107  							addr,
   108  						},
   109  					},
   110  				},
   111  			},
   112  		},
   113  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
   114  			Locktime:  0,
   115  			Threshold: 1,
   116  			Addrs: []ids.ShortID{
   117  				addr,
   118  			},
   119  		},
   120  	}
   121  	avax.SortTransferableOutputs(simpleAddPrimaryTx.Outs, Codec)
   122  	avax.SortTransferableOutputs(simpleAddPrimaryTx.StakeOuts, Codec)
   123  	utils.Sort(simpleAddPrimaryTx.Ins)
   124  	require.NoError(simpleAddPrimaryTx.SyntacticVerify(&snow.Context{
   125  		NetworkID:   1,
   126  		ChainID:     constants.PlatformChainID,
   127  		AVAXAssetID: avaxAssetID,
   128  	}))
   129  
   130  	expectedUnsignedSimpleAddPrimaryTxBytes := []byte{
   131  		// Codec version
   132  		0x00, 0x00,
   133  		// AddPermissionlessDelegatorTx type ID
   134  		0x00, 0x00, 0x00, 0x1a,
   135  		// Mainnet network ID
   136  		0x00, 0x00, 0x00, 0x01,
   137  		// P-chain blockchain ID
   138  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   139  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   140  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   141  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   142  		// Number of immediate outputs
   143  		0x00, 0x00, 0x00, 0x00,
   144  		// Number of inputs
   145  		0x00, 0x00, 0x00, 0x01,
   146  		// inputs[0]
   147  		// TxID
   148  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   149  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   150  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   151  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   152  		// Tx output index
   153  		0x00, 0x00, 0x00, 0x01,
   154  		// Mainnet AVAX asset ID
   155  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   156  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   157  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   158  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   159  		// secp256k1fx transfer input type ID
   160  		0x00, 0x00, 0x00, 0x05,
   161  		// Amount = 2k AVAX
   162  		0x00, 0x00, 0x01, 0xd1, 0xa9, 0x4a, 0x20, 0x00,
   163  		// Number of input signature indices
   164  		0x00, 0x00, 0x00, 0x01,
   165  		// signature index
   166  		0x00, 0x00, 0x00, 0x01,
   167  		// memo length
   168  		0x00, 0x00, 0x00, 0x00,
   169  		// NodeID
   170  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   171  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   172  		0x11, 0x22, 0x33, 0x44,
   173  		// Start time
   174  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
   175  		// End time
   176  		0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0xdc, 0x39,
   177  		// Stake weight
   178  		0x00, 0x00, 0x01, 0xd1, 0xa9, 0x4a, 0x20, 0x00,
   179  		// Primary network subnetID
   180  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   181  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   182  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   183  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   184  		// Number of locked outputs
   185  		0x00, 0x00, 0x00, 0x01,
   186  		// Mainnet AVAX asset ID
   187  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   188  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   189  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   190  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   191  		// secp256k1fx transferable output type ID
   192  		0x00, 0x00, 0x00, 0x07,
   193  		// amount
   194  		0x00, 0x00, 0x01, 0xd1, 0xa9, 0x4a, 0x20, 0x00,
   195  		// locktime
   196  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   197  		// threshold
   198  		0x00, 0x00, 0x00, 0x01,
   199  		// number of addresses
   200  		0x00, 0x00, 0x00, 0x01,
   201  		// addresses[0]
   202  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   203  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   204  		0x44, 0x55, 0x66, 0x77,
   205  		// secp256k1fx owner type ID
   206  		0x00, 0x00, 0x00, 0x0b,
   207  		// locktime
   208  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   209  		// threshold
   210  		0x00, 0x00, 0x00, 0x01,
   211  		// number of addresses
   212  		0x00, 0x00, 0x00, 0x01,
   213  		// addresses[0]
   214  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   215  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   216  		0x44, 0x55, 0x66, 0x77,
   217  	}
   218  	var unsignedSimpleAddPrimaryTx UnsignedTx = simpleAddPrimaryTx
   219  	unsignedSimpleAddPrimaryTxBytes, err := Codec.Marshal(CodecVersion, &unsignedSimpleAddPrimaryTx)
   220  	require.NoError(err)
   221  	require.Equal(expectedUnsignedSimpleAddPrimaryTxBytes, unsignedSimpleAddPrimaryTxBytes)
   222  
   223  	complexAddPrimaryTx := &AddPermissionlessDelegatorTx{
   224  		BaseTx: BaseTx{
   225  			BaseTx: avax.BaseTx{
   226  				NetworkID:    constants.MainnetID,
   227  				BlockchainID: constants.PlatformChainID,
   228  				Outs: []*avax.TransferableOutput{
   229  					{
   230  						Asset: avax.Asset{
   231  							ID: avaxAssetID,
   232  						},
   233  						Out: &secp256k1fx.TransferOutput{
   234  							Amt: 1,
   235  							OutputOwners: secp256k1fx.OutputOwners{
   236  								Locktime:  0,
   237  								Threshold: 1,
   238  								Addrs: []ids.ShortID{
   239  									addr,
   240  								},
   241  							},
   242  						},
   243  					},
   244  					{
   245  						Asset: avax.Asset{
   246  							ID: avaxAssetID,
   247  						},
   248  						Out: &stakeable.LockOut{
   249  							Locktime: 87654321,
   250  							TransferableOut: &secp256k1fx.TransferOutput{
   251  								Amt: 1,
   252  								OutputOwners: secp256k1fx.OutputOwners{
   253  									Locktime:  12345678,
   254  									Threshold: 0,
   255  									Addrs:     []ids.ShortID{},
   256  								},
   257  							},
   258  						},
   259  					},
   260  					{
   261  						Asset: avax.Asset{
   262  							ID: customAssetID,
   263  						},
   264  						Out: &stakeable.LockOut{
   265  							Locktime: 876543210,
   266  							TransferableOut: &secp256k1fx.TransferOutput{
   267  								Amt: 0xffffffffffffffff,
   268  								OutputOwners: secp256k1fx.OutputOwners{
   269  									Locktime:  0,
   270  									Threshold: 1,
   271  									Addrs: []ids.ShortID{
   272  										addr,
   273  									},
   274  								},
   275  							},
   276  						},
   277  					},
   278  				},
   279  				Ins: []*avax.TransferableInput{
   280  					{
   281  						UTXOID: avax.UTXOID{
   282  							TxID:        txID,
   283  							OutputIndex: 1,
   284  						},
   285  						Asset: avax.Asset{
   286  							ID: avaxAssetID,
   287  						},
   288  						In: &secp256k1fx.TransferInput{
   289  							Amt: units.MegaAvax,
   290  							Input: secp256k1fx.Input{
   291  								SigIndices: []uint32{2, 5},
   292  							},
   293  						},
   294  					},
   295  					{
   296  						UTXOID: avax.UTXOID{
   297  							TxID:        txID,
   298  							OutputIndex: 2,
   299  						},
   300  						Asset: avax.Asset{
   301  							ID: customAssetID,
   302  						},
   303  						In: &stakeable.LockIn{
   304  							Locktime: 876543210,
   305  							TransferableIn: &secp256k1fx.TransferInput{
   306  								Amt: 0xefffffffffffffff,
   307  								Input: secp256k1fx.Input{
   308  									SigIndices: []uint32{0},
   309  								},
   310  							},
   311  						},
   312  					},
   313  					{
   314  						UTXOID: avax.UTXOID{
   315  							TxID:        txID,
   316  							OutputIndex: 3,
   317  						},
   318  						Asset: avax.Asset{
   319  							ID: customAssetID,
   320  						},
   321  						In: &secp256k1fx.TransferInput{
   322  							Amt: 0x1000000000000000,
   323  							Input: secp256k1fx.Input{
   324  								SigIndices: []uint32{},
   325  							},
   326  						},
   327  					},
   328  				},
   329  				Memo: types.JSONByteSlice("😅\nwell that's\x01\x23\x45!"),
   330  			},
   331  		},
   332  		Validator: Validator{
   333  			NodeID: nodeID,
   334  			Start:  12345,
   335  			End:    12345 + 200*24*60*60,
   336  			Wght:   5 * units.KiloAvax,
   337  		},
   338  		Subnet: constants.PrimaryNetworkID,
   339  		StakeOuts: []*avax.TransferableOutput{
   340  			{
   341  				Asset: avax.Asset{
   342  					ID: avaxAssetID,
   343  				},
   344  				Out: &secp256k1fx.TransferOutput{
   345  					Amt: 2 * units.KiloAvax,
   346  					OutputOwners: secp256k1fx.OutputOwners{
   347  						Locktime:  0,
   348  						Threshold: 1,
   349  						Addrs: []ids.ShortID{
   350  							addr,
   351  						},
   352  					},
   353  				},
   354  			},
   355  			{
   356  				Asset: avax.Asset{
   357  					ID: avaxAssetID,
   358  				},
   359  				Out: &stakeable.LockOut{
   360  					Locktime: 987654321,
   361  					TransferableOut: &secp256k1fx.TransferOutput{
   362  						Amt: 3 * units.KiloAvax,
   363  						OutputOwners: secp256k1fx.OutputOwners{
   364  							Locktime:  87654321,
   365  							Threshold: 0,
   366  							Addrs:     []ids.ShortID{},
   367  						},
   368  					},
   369  				},
   370  			},
   371  		},
   372  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
   373  			Locktime:  0,
   374  			Threshold: 0,
   375  			Addrs:     []ids.ShortID{},
   376  		},
   377  	}
   378  	require.NoError(complexAddPrimaryTx.SyntacticVerify(&snow.Context{
   379  		NetworkID:   1,
   380  		ChainID:     constants.PlatformChainID,
   381  		AVAXAssetID: avaxAssetID,
   382  	}))
   383  
   384  	expectedUnsignedComplexAddPrimaryTxBytes := []byte{
   385  		// Codec version
   386  		0x00, 0x00,
   387  		// AddPermissionlessDelegatorTx type ID
   388  		0x00, 0x00, 0x00, 0x1a,
   389  		// Mainnet network ID
   390  		0x00, 0x00, 0x00, 0x01,
   391  		// P-chain blockchain ID
   392  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   393  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   394  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   395  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   396  		// Number of immediate outputs
   397  		0x00, 0x00, 0x00, 0x03,
   398  		// outputs[0]
   399  		// Mainnet AVAX asset ID
   400  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   401  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   402  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   403  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   404  		// secp256k1fx transfer output type ID
   405  		0x00, 0x00, 0x00, 0x07,
   406  		// amount
   407  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   408  		// locktime
   409  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   410  		// threshold
   411  		0x00, 0x00, 0x00, 0x01,
   412  		// number of addresses
   413  		0x00, 0x00, 0x00, 0x01,
   414  		// addresses[0]
   415  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   416  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   417  		0x44, 0x55, 0x66, 0x77,
   418  		// outputs[1]
   419  		// Mainnet AVAX asset ID
   420  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   421  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   422  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   423  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   424  		// stakeable locked output type ID
   425  		0x00, 0x00, 0x00, 0x16,
   426  		// locktime
   427  		0x00, 0x00, 0x00, 0x00, 0x05, 0x39, 0x7f, 0xb1,
   428  		// secp256k1fx transfer output type ID
   429  		0x00, 0x00, 0x00, 0x07,
   430  		// amount
   431  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   432  		// locktime
   433  		0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x61, 0x4e,
   434  		// threshold
   435  		0x00, 0x00, 0x00, 0x00,
   436  		// number of addresses
   437  		0x00, 0x00, 0x00, 0x00,
   438  		// outputs[2]
   439  		// custom asset ID
   440  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   441  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   442  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   443  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   444  		// stakeable locked output type ID
   445  		0x00, 0x00, 0x00, 0x16,
   446  		// locktime
   447  		0x00, 0x00, 0x00, 0x00, 0x34, 0x3e, 0xfc, 0xea,
   448  		// secp256k1fx transfer output type ID
   449  		0x00, 0x00, 0x00, 0x07,
   450  		// amount
   451  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   452  		// locktime
   453  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   454  		// threshold
   455  		0x00, 0x00, 0x00, 0x01,
   456  		// number of addresses
   457  		0x00, 0x00, 0x00, 0x01,
   458  		// address[0]
   459  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   460  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   461  		0x44, 0x55, 0x66, 0x77,
   462  		// number of inputs
   463  		0x00, 0x00, 0x00, 0x03,
   464  		// inputs[0]
   465  		// TxID
   466  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   467  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   468  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   469  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   470  		// Tx output index
   471  		0x00, 0x00, 0x00, 0x01,
   472  		// Mainnet AVAX asset ID
   473  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   474  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   475  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   476  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   477  		// secp256k1fx transfer input type ID
   478  		0x00, 0x00, 0x00, 0x05,
   479  		// amount
   480  		0x00, 0x03, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00,
   481  		// number of signature indices
   482  		0x00, 0x00, 0x00, 0x02,
   483  		// first signature index
   484  		0x00, 0x00, 0x00, 0x02,
   485  		// second signature index
   486  		0x00, 0x00, 0x00, 0x05,
   487  		// inputs[1]
   488  		// TxID
   489  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   490  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   491  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   492  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   493  		// Tx output index
   494  		0x00, 0x00, 0x00, 0x02,
   495  		// custom asset ID
   496  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   497  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   498  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   499  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   500  		// stakeable locked input type ID
   501  		0x00, 0x00, 0x00, 0x15,
   502  		// locktime
   503  		0x00, 0x00, 0x00, 0x00, 0x34, 0x3e, 0xfc, 0xea,
   504  		// secp256k1fx transfer input type ID
   505  		0x00, 0x00, 0x00, 0x05,
   506  		// amount
   507  		0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   508  		// number of signature indices
   509  		0x00, 0x00, 0x00, 0x01,
   510  		// signature index
   511  		0x00, 0x00, 0x00, 0x00,
   512  		// inputs[2]
   513  		// TxID
   514  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   515  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   516  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   517  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   518  		// Tx output index
   519  		0x00, 0x00, 0x00, 0x03,
   520  		// custom asset ID
   521  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   522  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   523  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   524  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   525  		// secp256k1 transfer input type ID
   526  		0x00, 0x00, 0x00, 0x05,
   527  		// amount
   528  		0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   529  		// number of signature indices
   530  		0x00, 0x00, 0x00, 0x00,
   531  		// memo length
   532  		0x00, 0x00, 0x00, 0x14,
   533  		// memo
   534  		0xf0, 0x9f, 0x98, 0x85, 0x0a, 0x77, 0x65, 0x6c,
   535  		0x6c, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73,
   536  		0x01, 0x23, 0x45, 0x21,
   537  		// nodeID
   538  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   539  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   540  		0x11, 0x22, 0x33, 0x44,
   541  		// Start time
   542  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
   543  		// End time
   544  		0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0xdc, 0x39,
   545  		// Stake weight
   546  		0x00, 0x00, 0x04, 0x8c, 0x27, 0x39, 0x50, 0x00,
   547  		// Primary Network subnet ID
   548  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   549  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   550  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   551  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   552  		// number of locked outputs
   553  		0x00, 0x00, 0x00, 0x02,
   554  		// Mainnet AVAX asset ID
   555  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   556  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   557  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   558  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   559  		// secp256k1 transfer output type ID
   560  		0x00, 0x00, 0x00, 0x07,
   561  		// amount
   562  		0x00, 0x00, 0x01, 0xd1, 0xa9, 0x4a, 0x20, 0x00,
   563  		// locktime
   564  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   565  		// threshold
   566  		0x00, 0x00, 0x00, 0x01,
   567  		// number of addresses
   568  		0x00, 0x00, 0x00, 0x01,
   569  		// addresses[0]
   570  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   571  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   572  		0x44, 0x55, 0x66, 0x77,
   573  		// Mainnet AVAX asset ID
   574  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   575  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   576  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   577  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   578  		// stakeable locked output type ID
   579  		0x00, 0x00, 0x00, 0x16,
   580  		// locktime
   581  		0x00, 0x00, 0x00, 0x00, 0x3a, 0xde, 0x68, 0xb1,
   582  		// secp256k1 transfer output type ID
   583  		0x00, 0x00, 0x00, 0x07,
   584  		// amount
   585  		0x00, 0x00, 0x02, 0xba, 0x7d, 0xef, 0x30, 0x00,
   586  		// locktime
   587  		0x00, 0x00, 0x00, 0x00, 0x05, 0x39, 0x7f, 0xb1,
   588  		// threshold
   589  		0x00, 0x00, 0x00, 0x00,
   590  		// number of addresses
   591  		0x00, 0x00, 0x00, 0x00,
   592  		// secp256k1 owner type ID
   593  		0x00, 0x00, 0x00, 0x0b,
   594  		// locktime
   595  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   596  		// threshold
   597  		0x00, 0x00, 0x00, 0x00,
   598  		// number of addresses
   599  		0x00, 0x00, 0x00, 0x00,
   600  	}
   601  	var unsignedComplexAddPrimaryTx UnsignedTx = complexAddPrimaryTx
   602  	unsignedComplexAddPrimaryTxBytes, err := Codec.Marshal(CodecVersion, &unsignedComplexAddPrimaryTx)
   603  	require.NoError(err)
   604  	require.Equal(expectedUnsignedComplexAddPrimaryTxBytes, unsignedComplexAddPrimaryTxBytes)
   605  
   606  	aliaser := ids.NewAliaser()
   607  	require.NoError(aliaser.Alias(constants.PlatformChainID, "P"))
   608  
   609  	unsignedComplexAddPrimaryTx.InitCtx(&snow.Context{
   610  		NetworkID:   1,
   611  		ChainID:     constants.PlatformChainID,
   612  		AVAXAssetID: avaxAssetID,
   613  		BCLookup:    aliaser,
   614  	})
   615  
   616  	unsignedComplexAddPrimaryTxJSONBytes, err := json.MarshalIndent(unsignedComplexAddPrimaryTx, "", "\t")
   617  	require.NoError(err)
   618  	require.Equal(`{
   619  	"networkID": 1,
   620  	"blockchainID": "11111111111111111111111111111111LpoYY",
   621  	"outputs": [
   622  		{
   623  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
   624  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   625  			"output": {
   626  				"addresses": [
   627  					"P-avax1g32kvaugnx4tk3z4vemc3xd2hdz92enh972wxr"
   628  				],
   629  				"amount": 1,
   630  				"locktime": 0,
   631  				"threshold": 1
   632  			}
   633  		},
   634  		{
   635  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
   636  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   637  			"output": {
   638  				"locktime": 87654321,
   639  				"output": {
   640  					"addresses": [],
   641  					"amount": 1,
   642  					"locktime": 12345678,
   643  					"threshold": 0
   644  				}
   645  			}
   646  		},
   647  		{
   648  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
   649  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   650  			"output": {
   651  				"locktime": 876543210,
   652  				"output": {
   653  					"addresses": [
   654  						"P-avax1g32kvaugnx4tk3z4vemc3xd2hdz92enh972wxr"
   655  					],
   656  					"amount": 18446744073709551615,
   657  					"locktime": 0,
   658  					"threshold": 1
   659  				}
   660  			}
   661  		}
   662  	],
   663  	"inputs": [
   664  		{
   665  			"txID": "2wiU5PnFTjTmoAXGZutHAsPF36qGGyLHYHj9G1Aucfmb3JFFGN",
   666  			"outputIndex": 1,
   667  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
   668  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   669  			"input": {
   670  				"amount": 1000000000000000,
   671  				"signatureIndices": [
   672  					2,
   673  					5
   674  				]
   675  			}
   676  		},
   677  		{
   678  			"txID": "2wiU5PnFTjTmoAXGZutHAsPF36qGGyLHYHj9G1Aucfmb3JFFGN",
   679  			"outputIndex": 2,
   680  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
   681  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   682  			"input": {
   683  				"locktime": 876543210,
   684  				"input": {
   685  					"amount": 17293822569102704639,
   686  					"signatureIndices": [
   687  						0
   688  					]
   689  				}
   690  			}
   691  		},
   692  		{
   693  			"txID": "2wiU5PnFTjTmoAXGZutHAsPF36qGGyLHYHj9G1Aucfmb3JFFGN",
   694  			"outputIndex": 3,
   695  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
   696  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   697  			"input": {
   698  				"amount": 1152921504606846976,
   699  				"signatureIndices": []
   700  			}
   701  		}
   702  	],
   703  	"memo": "0xf09f98850a77656c6c2074686174277301234521",
   704  	"validator": {
   705  		"nodeID": "NodeID-2ZbTY9GatRTrfinAoYiYLcf6CvrPAUYgo",
   706  		"start": 12345,
   707  		"end": 17292345,
   708  		"weight": 5000000000000
   709  	},
   710  	"subnetID": "11111111111111111111111111111111LpoYY",
   711  	"stake": [
   712  		{
   713  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
   714  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   715  			"output": {
   716  				"addresses": [
   717  					"P-avax1g32kvaugnx4tk3z4vemc3xd2hdz92enh972wxr"
   718  				],
   719  				"amount": 2000000000000,
   720  				"locktime": 0,
   721  				"threshold": 1
   722  			}
   723  		},
   724  		{
   725  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
   726  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
   727  			"output": {
   728  				"locktime": 987654321,
   729  				"output": {
   730  					"addresses": [],
   731  					"amount": 3000000000000,
   732  					"locktime": 87654321,
   733  					"threshold": 0
   734  				}
   735  			}
   736  		}
   737  	],
   738  	"rewardsOwner": {
   739  		"addresses": [],
   740  		"locktime": 0,
   741  		"threshold": 0
   742  	}
   743  }`, string(unsignedComplexAddPrimaryTxJSONBytes))
   744  }
   745  
   746  func TestAddPermissionlessSubnetDelegatorSerialization(t *testing.T) {
   747  	require := require.New(t)
   748  
   749  	addr := ids.ShortID{
   750  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   751  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   752  		0x44, 0x55, 0x66, 0x77,
   753  	}
   754  
   755  	avaxAssetID, err := ids.FromString("FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z")
   756  	require.NoError(err)
   757  
   758  	customAssetID := ids.ID{
   759  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   760  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   761  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   762  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   763  	}
   764  
   765  	txID := ids.ID{
   766  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   767  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   768  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   769  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   770  	}
   771  	nodeID := ids.BuildTestNodeID([]byte{
   772  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   773  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   774  		0x11, 0x22, 0x33, 0x44,
   775  	})
   776  	subnetID := ids.ID{
   777  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
   778  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
   779  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
   780  		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
   781  	}
   782  
   783  	simpleAddSubnetTx := &AddPermissionlessDelegatorTx{
   784  		BaseTx: BaseTx{
   785  			BaseTx: avax.BaseTx{
   786  				NetworkID:    constants.MainnetID,
   787  				BlockchainID: constants.PlatformChainID,
   788  				Outs:         []*avax.TransferableOutput{},
   789  				Ins: []*avax.TransferableInput{
   790  					{
   791  						UTXOID: avax.UTXOID{
   792  							TxID:        txID,
   793  							OutputIndex: 1,
   794  						},
   795  						Asset: avax.Asset{
   796  							ID: avaxAssetID,
   797  						},
   798  						In: &secp256k1fx.TransferInput{
   799  							Amt: units.MilliAvax,
   800  							Input: secp256k1fx.Input{
   801  								SigIndices: []uint32{1},
   802  							},
   803  						},
   804  					},
   805  					{
   806  						UTXOID: avax.UTXOID{
   807  							TxID:        txID,
   808  							OutputIndex: 2,
   809  						},
   810  						Asset: avax.Asset{
   811  							ID: customAssetID,
   812  						},
   813  						In: &secp256k1fx.TransferInput{
   814  							Amt: 1,
   815  							Input: secp256k1fx.Input{
   816  								SigIndices: []uint32{1},
   817  							},
   818  						},
   819  					},
   820  				},
   821  				Memo: types.JSONByteSlice{},
   822  			},
   823  		},
   824  		Validator: Validator{
   825  			NodeID: nodeID,
   826  			Start:  12345,
   827  			End:    12346,
   828  			Wght:   1,
   829  		},
   830  		Subnet: subnetID,
   831  		StakeOuts: []*avax.TransferableOutput{
   832  			{
   833  				Asset: avax.Asset{
   834  					ID: customAssetID,
   835  				},
   836  				Out: &secp256k1fx.TransferOutput{
   837  					Amt: 1,
   838  					OutputOwners: secp256k1fx.OutputOwners{
   839  						Locktime:  0,
   840  						Threshold: 1,
   841  						Addrs: []ids.ShortID{
   842  							addr,
   843  						},
   844  					},
   845  				},
   846  			},
   847  		},
   848  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
   849  			Locktime:  0,
   850  			Threshold: 1,
   851  			Addrs: []ids.ShortID{
   852  				addr,
   853  			},
   854  		},
   855  	}
   856  	avax.SortTransferableOutputs(simpleAddSubnetTx.Outs, Codec)
   857  	avax.SortTransferableOutputs(simpleAddSubnetTx.StakeOuts, Codec)
   858  	utils.Sort(simpleAddSubnetTx.Ins)
   859  	require.NoError(simpleAddSubnetTx.SyntacticVerify(&snow.Context{
   860  		NetworkID:   1,
   861  		ChainID:     constants.PlatformChainID,
   862  		AVAXAssetID: avaxAssetID,
   863  	}))
   864  
   865  	expectedUnsignedSimpleAddSubnetTxBytes := []byte{
   866  		// Codec version
   867  		0x00, 0x00,
   868  		// AddPermissionlessDelegationTx type ID
   869  		0x00, 0x00, 0x00, 0x1a,
   870  		// Mainnet network ID
   871  		0x00, 0x00, 0x00, 0x01,
   872  		// P-chain blockchain ID
   873  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   874  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   875  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   876  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   877  		// Number of immediate outputs
   878  		0x00, 0x00, 0x00, 0x00,
   879  		// Number of inputs
   880  		0x00, 0x00, 0x00, 0x02,
   881  		// inputs[0]
   882  		// TxID
   883  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   884  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   885  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   886  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   887  		// Tx output index
   888  		0x00, 0x00, 0x00, 0x01,
   889  		// Mainnet AVAX asset ID
   890  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
   891  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
   892  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
   893  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
   894  		// secp256k1fx transfer input type ID
   895  		0x00, 0x00, 0x00, 0x05,
   896  		// Amount = 1 MilliAVAX
   897  		0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x42, 0x40,
   898  		// Number of input signature indices
   899  		0x00, 0x00, 0x00, 0x01,
   900  		// signature index
   901  		0x00, 0x00, 0x00, 0x01,
   902  		// inputs[1]
   903  		// TxID
   904  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   905  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   906  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   907  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
   908  		// Tx output index
   909  		0x00, 0x00, 0x00, 0x02,
   910  		// custom asset ID
   911  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   912  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   913  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   914  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   915  		// secp256k1fx transfer input type ID
   916  		0x00, 0x00, 0x00, 0x05,
   917  		// Amount
   918  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   919  		// Number of input signature indices
   920  		0x00, 0x00, 0x00, 0x01,
   921  		// signature index
   922  		0x00, 0x00, 0x00, 0x01,
   923  		// memo length
   924  		0x00, 0x00, 0x00, 0x00,
   925  		// NodeID
   926  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   927  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
   928  		0x11, 0x22, 0x33, 0x44,
   929  		// Start time
   930  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
   931  		// End time
   932  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a,
   933  		// Stake weight
   934  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   935  		// SubnetID
   936  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
   937  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
   938  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
   939  		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
   940  		// Number of locked outputs
   941  		0x00, 0x00, 0x00, 0x01,
   942  		// custom asset ID
   943  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   944  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   945  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   946  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
   947  		// secp256k1fx transferable output type ID
   948  		0x00, 0x00, 0x00, 0x07,
   949  		// amount
   950  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   951  		// locktime
   952  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   953  		// threshold
   954  		0x00, 0x00, 0x00, 0x01,
   955  		// number of addresses
   956  		0x00, 0x00, 0x00, 0x01,
   957  		// addresses[0]
   958  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   959  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   960  		0x44, 0x55, 0x66, 0x77,
   961  		// secp256k1fx owner type ID
   962  		0x00, 0x00, 0x00, 0x0b,
   963  		// locktime
   964  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   965  		// threshold
   966  		0x00, 0x00, 0x00, 0x01,
   967  		// number of addresses
   968  		0x00, 0x00, 0x00, 0x01,
   969  		// addresses[0]
   970  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   971  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
   972  		0x44, 0x55, 0x66, 0x77,
   973  	}
   974  	var unsignedSimpleAddSubnetTx UnsignedTx = simpleAddSubnetTx
   975  	unsignedSimpleAddSubnetTxBytes, err := Codec.Marshal(CodecVersion, &unsignedSimpleAddSubnetTx)
   976  	require.NoError(err)
   977  	require.Equal(expectedUnsignedSimpleAddSubnetTxBytes, unsignedSimpleAddSubnetTxBytes)
   978  
   979  	complexAddSubnetTx := &AddPermissionlessDelegatorTx{
   980  		BaseTx: BaseTx{
   981  			BaseTx: avax.BaseTx{
   982  				NetworkID:    constants.MainnetID,
   983  				BlockchainID: constants.PlatformChainID,
   984  				Outs: []*avax.TransferableOutput{
   985  					{
   986  						Asset: avax.Asset{
   987  							ID: avaxAssetID,
   988  						},
   989  						Out: &secp256k1fx.TransferOutput{
   990  							Amt: 1,
   991  							OutputOwners: secp256k1fx.OutputOwners{
   992  								Locktime:  0,
   993  								Threshold: 1,
   994  								Addrs: []ids.ShortID{
   995  									addr,
   996  								},
   997  							},
   998  						},
   999  					},
  1000  					{
  1001  						Asset: avax.Asset{
  1002  							ID: avaxAssetID,
  1003  						},
  1004  						Out: &stakeable.LockOut{
  1005  							Locktime: 87654321,
  1006  							TransferableOut: &secp256k1fx.TransferOutput{
  1007  								Amt: 1,
  1008  								OutputOwners: secp256k1fx.OutputOwners{
  1009  									Locktime:  12345678,
  1010  									Threshold: 0,
  1011  									Addrs:     []ids.ShortID{},
  1012  								},
  1013  							},
  1014  						},
  1015  					},
  1016  					{
  1017  						Asset: avax.Asset{
  1018  							ID: customAssetID,
  1019  						},
  1020  						Out: &stakeable.LockOut{
  1021  							Locktime: 876543210,
  1022  							TransferableOut: &secp256k1fx.TransferOutput{
  1023  								Amt: 0xfffffffffffffff0,
  1024  								OutputOwners: secp256k1fx.OutputOwners{
  1025  									Locktime:  0,
  1026  									Threshold: 1,
  1027  									Addrs: []ids.ShortID{
  1028  										addr,
  1029  									},
  1030  								},
  1031  							},
  1032  						},
  1033  					},
  1034  				},
  1035  				Ins: []*avax.TransferableInput{
  1036  					{
  1037  						UTXOID: avax.UTXOID{
  1038  							TxID:        txID,
  1039  							OutputIndex: 1,
  1040  						},
  1041  						Asset: avax.Asset{
  1042  							ID: avaxAssetID,
  1043  						},
  1044  						In: &secp256k1fx.TransferInput{
  1045  							Amt: units.MegaAvax,
  1046  							Input: secp256k1fx.Input{
  1047  								SigIndices: []uint32{2, 5},
  1048  							},
  1049  						},
  1050  					},
  1051  					{
  1052  						UTXOID: avax.UTXOID{
  1053  							TxID:        txID,
  1054  							OutputIndex: 2,
  1055  						},
  1056  						Asset: avax.Asset{
  1057  							ID: customAssetID,
  1058  						},
  1059  						In: &stakeable.LockIn{
  1060  							Locktime: 876543210,
  1061  							TransferableIn: &secp256k1fx.TransferInput{
  1062  								Amt: 0xefffffffffffffff,
  1063  								Input: secp256k1fx.Input{
  1064  									SigIndices: []uint32{0},
  1065  								},
  1066  							},
  1067  						},
  1068  					},
  1069  					{
  1070  						UTXOID: avax.UTXOID{
  1071  							TxID:        txID,
  1072  							OutputIndex: 3,
  1073  						},
  1074  						Asset: avax.Asset{
  1075  							ID: customAssetID,
  1076  						},
  1077  						In: &secp256k1fx.TransferInput{
  1078  							Amt: 0x1000000000000000,
  1079  							Input: secp256k1fx.Input{
  1080  								SigIndices: []uint32{},
  1081  							},
  1082  						},
  1083  					},
  1084  				},
  1085  				Memo: types.JSONByteSlice("😅\nwell that's\x01\x23\x45!"),
  1086  			},
  1087  		},
  1088  		Validator: Validator{
  1089  			NodeID: nodeID,
  1090  			Start:  12345,
  1091  			End:    12345 + 1,
  1092  			Wght:   9,
  1093  		},
  1094  		Subnet: subnetID,
  1095  		StakeOuts: []*avax.TransferableOutput{
  1096  			{
  1097  				Asset: avax.Asset{
  1098  					ID: customAssetID,
  1099  				},
  1100  				Out: &secp256k1fx.TransferOutput{
  1101  					Amt: 2,
  1102  					OutputOwners: secp256k1fx.OutputOwners{
  1103  						Locktime:  0,
  1104  						Threshold: 1,
  1105  						Addrs: []ids.ShortID{
  1106  							addr,
  1107  						},
  1108  					},
  1109  				},
  1110  			},
  1111  			{
  1112  				Asset: avax.Asset{
  1113  					ID: customAssetID,
  1114  				},
  1115  				Out: &stakeable.LockOut{
  1116  					Locktime: 987654321,
  1117  					TransferableOut: &secp256k1fx.TransferOutput{
  1118  						Amt: 7,
  1119  						OutputOwners: secp256k1fx.OutputOwners{
  1120  							Locktime:  87654321,
  1121  							Threshold: 0,
  1122  							Addrs:     []ids.ShortID{},
  1123  						},
  1124  					},
  1125  				},
  1126  			},
  1127  		},
  1128  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
  1129  			Locktime:  0,
  1130  			Threshold: 0,
  1131  			Addrs:     []ids.ShortID{},
  1132  		},
  1133  	}
  1134  	require.NoError(complexAddSubnetTx.SyntacticVerify(&snow.Context{
  1135  		NetworkID:   1,
  1136  		ChainID:     constants.PlatformChainID,
  1137  		AVAXAssetID: avaxAssetID,
  1138  	}))
  1139  
  1140  	expectedUnsignedComplexAddSubnetTxBytes := []byte{
  1141  		// Codec version
  1142  		0x00, 0x00,
  1143  		// AddPermissionlessDelegatorTx type ID
  1144  		0x00, 0x00, 0x00, 0x1a,
  1145  		// Mainnet network ID
  1146  		0x00, 0x00, 0x00, 0x01,
  1147  		// P-chain blockchain ID
  1148  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1149  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1150  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1151  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1152  		// Number of immediate outputs
  1153  		0x00, 0x00, 0x00, 0x03,
  1154  		// outputs[0]
  1155  		// Mainnet AVAX asset ID
  1156  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
  1157  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
  1158  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
  1159  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
  1160  		// secp256k1fx transfer output type ID
  1161  		0x00, 0x00, 0x00, 0x07,
  1162  		// amount
  1163  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1164  		// locktime
  1165  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1166  		// threshold
  1167  		0x00, 0x00, 0x00, 0x01,
  1168  		// number of addresses
  1169  		0x00, 0x00, 0x00, 0x01,
  1170  		// addresses[0]
  1171  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
  1172  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
  1173  		0x44, 0x55, 0x66, 0x77,
  1174  		// outputs[1]
  1175  		// Mainnet AVAX asset ID
  1176  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
  1177  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
  1178  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
  1179  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
  1180  		// stakeable locked output type ID
  1181  		0x00, 0x00, 0x00, 0x16,
  1182  		// locktime
  1183  		0x00, 0x00, 0x00, 0x00, 0x05, 0x39, 0x7f, 0xb1,
  1184  		// secp256k1fx transfer output type ID
  1185  		0x00, 0x00, 0x00, 0x07,
  1186  		// amount
  1187  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1188  		// locktime
  1189  		0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x61, 0x4e,
  1190  		// threshold
  1191  		0x00, 0x00, 0x00, 0x00,
  1192  		// number of addresses
  1193  		0x00, 0x00, 0x00, 0x00,
  1194  		// outputs[2]
  1195  		// custom asset ID
  1196  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1197  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1198  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1199  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1200  		// stakeable locked output type ID
  1201  		0x00, 0x00, 0x00, 0x16,
  1202  		// locktime
  1203  		0x00, 0x00, 0x00, 0x00, 0x34, 0x3e, 0xfc, 0xea,
  1204  		// secp256k1fx transfer output type ID
  1205  		0x00, 0x00, 0x00, 0x07,
  1206  		// amount
  1207  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
  1208  		// locktime
  1209  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1210  		// threshold
  1211  		0x00, 0x00, 0x00, 0x01,
  1212  		// number of addresses
  1213  		0x00, 0x00, 0x00, 0x01,
  1214  		// address[0]
  1215  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
  1216  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
  1217  		0x44, 0x55, 0x66, 0x77,
  1218  		// number of inputs
  1219  		0x00, 0x00, 0x00, 0x03,
  1220  		// inputs[0]
  1221  		// TxID
  1222  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1223  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1224  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1225  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1226  		// Tx output index
  1227  		0x00, 0x00, 0x00, 0x01,
  1228  		// Mainnet AVAX asset ID
  1229  		0x21, 0xe6, 0x73, 0x17, 0xcb, 0xc4, 0xbe, 0x2a,
  1230  		0xeb, 0x00, 0x67, 0x7a, 0xd6, 0x46, 0x27, 0x78,
  1231  		0xa8, 0xf5, 0x22, 0x74, 0xb9, 0xd6, 0x05, 0xdf,
  1232  		0x25, 0x91, 0xb2, 0x30, 0x27, 0xa8, 0x7d, 0xff,
  1233  		// secp256k1fx transfer input type ID
  1234  		0x00, 0x00, 0x00, 0x05,
  1235  		// amount
  1236  		0x00, 0x03, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00,
  1237  		// number of signature indices
  1238  		0x00, 0x00, 0x00, 0x02,
  1239  		// first signature index
  1240  		0x00, 0x00, 0x00, 0x02,
  1241  		// second signature index
  1242  		0x00, 0x00, 0x00, 0x05,
  1243  		// inputs[1]
  1244  		// TxID
  1245  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1246  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1247  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1248  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1249  		// Tx output index
  1250  		0x00, 0x00, 0x00, 0x02,
  1251  		// custom asset ID
  1252  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1253  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1254  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1255  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1256  		// stakeable locked input type ID
  1257  		0x00, 0x00, 0x00, 0x15,
  1258  		// locktime
  1259  		0x00, 0x00, 0x00, 0x00, 0x34, 0x3e, 0xfc, 0xea,
  1260  		// secp256k1fx transfer input type ID
  1261  		0x00, 0x00, 0x00, 0x05,
  1262  		// amount
  1263  		0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1264  		// number of signature indices
  1265  		0x00, 0x00, 0x00, 0x01,
  1266  		// signature index
  1267  		0x00, 0x00, 0x00, 0x00,
  1268  		// inputs[2]
  1269  		// TxID
  1270  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1271  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1272  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1273  		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
  1274  		// Tx output index
  1275  		0x00, 0x00, 0x00, 0x03,
  1276  		// custom asset ID
  1277  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1278  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1279  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1280  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1281  		// secp256k1 transfer input type ID
  1282  		0x00, 0x00, 0x00, 0x05,
  1283  		// amount
  1284  		0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1285  		// number of signature indices
  1286  		0x00, 0x00, 0x00, 0x00,
  1287  		// memo length
  1288  		0x00, 0x00, 0x00, 0x14,
  1289  		// memo
  1290  		0xf0, 0x9f, 0x98, 0x85, 0x0a, 0x77, 0x65, 0x6c,
  1291  		0x6c, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73,
  1292  		0x01, 0x23, 0x45, 0x21,
  1293  		// nodeID
  1294  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
  1295  		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
  1296  		0x11, 0x22, 0x33, 0x44,
  1297  		// Start time
  1298  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
  1299  		// End time
  1300  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a,
  1301  		// Stake weight
  1302  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
  1303  		// subnetID
  1304  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
  1305  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
  1306  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
  1307  		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
  1308  		// number of locked outputs
  1309  		0x00, 0x00, 0x00, 0x02,
  1310  		// custom asset ID
  1311  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1312  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1313  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1314  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1315  		// secp256k1 transfer output type ID
  1316  		0x00, 0x00, 0x00, 0x07,
  1317  		// amount
  1318  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
  1319  		// locktime
  1320  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1321  		// threshold
  1322  		0x00, 0x00, 0x00, 0x01,
  1323  		// number of addresses
  1324  		0x00, 0x00, 0x00, 0x01,
  1325  		// addresses[0]
  1326  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
  1327  		0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
  1328  		0x44, 0x55, 0x66, 0x77,
  1329  		// custom asset ID
  1330  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1331  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1332  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1333  		0x99, 0x77, 0x55, 0x77, 0x11, 0x33, 0x55, 0x31,
  1334  		// stakeable locked output type ID
  1335  		0x00, 0x00, 0x00, 0x16,
  1336  		// locktime
  1337  		0x00, 0x00, 0x00, 0x00, 0x3a, 0xde, 0x68, 0xb1,
  1338  		// secp256k1 transfer output type ID
  1339  		0x00, 0x00, 0x00, 0x07,
  1340  		// amount
  1341  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
  1342  		// locktime
  1343  		0x00, 0x00, 0x00, 0x00, 0x05, 0x39, 0x7f, 0xb1,
  1344  		// threshold
  1345  		0x00, 0x00, 0x00, 0x00,
  1346  		// number of addresses
  1347  		0x00, 0x00, 0x00, 0x00,
  1348  		// secp256k1 owner type ID
  1349  		0x00, 0x00, 0x00, 0x0b,
  1350  		// locktime
  1351  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1352  		// threshold
  1353  		0x00, 0x00, 0x00, 0x00,
  1354  		// number of addresses
  1355  		0x00, 0x00, 0x00, 0x00,
  1356  	}
  1357  	var unsignedComplexAddSubnetTx UnsignedTx = complexAddSubnetTx
  1358  	unsignedComplexAddSubnetTxBytes, err := Codec.Marshal(CodecVersion, &unsignedComplexAddSubnetTx)
  1359  	require.NoError(err)
  1360  	require.Equal(expectedUnsignedComplexAddSubnetTxBytes, unsignedComplexAddSubnetTxBytes)
  1361  
  1362  	aliaser := ids.NewAliaser()
  1363  	require.NoError(aliaser.Alias(constants.PlatformChainID, "P"))
  1364  
  1365  	unsignedComplexAddSubnetTx.InitCtx(&snow.Context{
  1366  		NetworkID:   1,
  1367  		ChainID:     constants.PlatformChainID,
  1368  		AVAXAssetID: avaxAssetID,
  1369  		BCLookup:    aliaser,
  1370  	})
  1371  
  1372  	unsignedComplexAddSubnetTxJSONBytes, err := json.MarshalIndent(unsignedComplexAddSubnetTx, "", "\t")
  1373  	require.NoError(err)
  1374  	require.Equal(`{
  1375  	"networkID": 1,
  1376  	"blockchainID": "11111111111111111111111111111111LpoYY",
  1377  	"outputs": [
  1378  		{
  1379  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
  1380  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1381  			"output": {
  1382  				"addresses": [
  1383  					"P-avax1g32kvaugnx4tk3z4vemc3xd2hdz92enh972wxr"
  1384  				],
  1385  				"amount": 1,
  1386  				"locktime": 0,
  1387  				"threshold": 1
  1388  			}
  1389  		},
  1390  		{
  1391  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
  1392  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1393  			"output": {
  1394  				"locktime": 87654321,
  1395  				"output": {
  1396  					"addresses": [],
  1397  					"amount": 1,
  1398  					"locktime": 12345678,
  1399  					"threshold": 0
  1400  				}
  1401  			}
  1402  		},
  1403  		{
  1404  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
  1405  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1406  			"output": {
  1407  				"locktime": 876543210,
  1408  				"output": {
  1409  					"addresses": [
  1410  						"P-avax1g32kvaugnx4tk3z4vemc3xd2hdz92enh972wxr"
  1411  					],
  1412  					"amount": 18446744073709551600,
  1413  					"locktime": 0,
  1414  					"threshold": 1
  1415  				}
  1416  			}
  1417  		}
  1418  	],
  1419  	"inputs": [
  1420  		{
  1421  			"txID": "2wiU5PnFTjTmoAXGZutHAsPF36qGGyLHYHj9G1Aucfmb3JFFGN",
  1422  			"outputIndex": 1,
  1423  			"assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
  1424  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1425  			"input": {
  1426  				"amount": 1000000000000000,
  1427  				"signatureIndices": [
  1428  					2,
  1429  					5
  1430  				]
  1431  			}
  1432  		},
  1433  		{
  1434  			"txID": "2wiU5PnFTjTmoAXGZutHAsPF36qGGyLHYHj9G1Aucfmb3JFFGN",
  1435  			"outputIndex": 2,
  1436  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
  1437  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1438  			"input": {
  1439  				"locktime": 876543210,
  1440  				"input": {
  1441  					"amount": 17293822569102704639,
  1442  					"signatureIndices": [
  1443  						0
  1444  					]
  1445  				}
  1446  			}
  1447  		},
  1448  		{
  1449  			"txID": "2wiU5PnFTjTmoAXGZutHAsPF36qGGyLHYHj9G1Aucfmb3JFFGN",
  1450  			"outputIndex": 3,
  1451  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
  1452  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1453  			"input": {
  1454  				"amount": 1152921504606846976,
  1455  				"signatureIndices": []
  1456  			}
  1457  		}
  1458  	],
  1459  	"memo": "0xf09f98850a77656c6c2074686174277301234521",
  1460  	"validator": {
  1461  		"nodeID": "NodeID-2ZbTY9GatRTrfinAoYiYLcf6CvrPAUYgo",
  1462  		"start": 12345,
  1463  		"end": 12346,
  1464  		"weight": 9
  1465  	},
  1466  	"subnetID": "SkB92YpWm4UpburLz9tEKZw2i67H3FF6YkjaU4BkFUDTG9Xm",
  1467  	"stake": [
  1468  		{
  1469  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
  1470  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1471  			"output": {
  1472  				"addresses": [
  1473  					"P-avax1g32kvaugnx4tk3z4vemc3xd2hdz92enh972wxr"
  1474  				],
  1475  				"amount": 2,
  1476  				"locktime": 0,
  1477  				"threshold": 1
  1478  			}
  1479  		},
  1480  		{
  1481  			"assetID": "2Ab62uWwJw1T6VvmKD36ufsiuGZuX1pGykXAvPX1LtjTRHxwcc",
  1482  			"fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
  1483  			"output": {
  1484  				"locktime": 987654321,
  1485  				"output": {
  1486  					"addresses": [],
  1487  					"amount": 7,
  1488  					"locktime": 87654321,
  1489  					"threshold": 0
  1490  				}
  1491  			}
  1492  		}
  1493  	],
  1494  	"rewardsOwner": {
  1495  		"addresses": [],
  1496  		"locktime": 0,
  1497  		"threshold": 0
  1498  	}
  1499  }`, string(unsignedComplexAddSubnetTxJSONBytes))
  1500  }
  1501  
  1502  func TestAddPermissionlessDelegatorTxSyntacticVerify(t *testing.T) {
  1503  	type test struct {
  1504  		name   string
  1505  		txFunc func(*gomock.Controller) *AddPermissionlessDelegatorTx
  1506  		err    error
  1507  	}
  1508  
  1509  	var (
  1510  		networkID = uint32(1337)
  1511  		chainID   = ids.GenerateTestID()
  1512  	)
  1513  
  1514  	ctx := &snow.Context{
  1515  		ChainID:   chainID,
  1516  		NetworkID: networkID,
  1517  	}
  1518  
  1519  	// A BaseTx that already passed syntactic verification.
  1520  	verifiedBaseTx := BaseTx{
  1521  		SyntacticallyVerified: true,
  1522  	}
  1523  
  1524  	// A BaseTx that passes syntactic verification.
  1525  	validBaseTx := BaseTx{
  1526  		BaseTx: avax.BaseTx{
  1527  			NetworkID:    networkID,
  1528  			BlockchainID: chainID,
  1529  		},
  1530  	}
  1531  
  1532  	// A BaseTx that fails syntactic verification.
  1533  	invalidBaseTx := BaseTx{}
  1534  
  1535  	tests := []test{
  1536  		{
  1537  			name: "nil tx",
  1538  			txFunc: func(*gomock.Controller) *AddPermissionlessDelegatorTx {
  1539  				return nil
  1540  			},
  1541  			err: ErrNilTx,
  1542  		},
  1543  		{
  1544  			name: "already verified",
  1545  			txFunc: func(*gomock.Controller) *AddPermissionlessDelegatorTx {
  1546  				return &AddPermissionlessDelegatorTx{
  1547  					BaseTx: verifiedBaseTx,
  1548  				}
  1549  			},
  1550  			err: nil,
  1551  		},
  1552  		{
  1553  			name: "no provided stake",
  1554  			txFunc: func(*gomock.Controller) *AddPermissionlessDelegatorTx {
  1555  				return &AddPermissionlessDelegatorTx{
  1556  					BaseTx:    validBaseTx,
  1557  					StakeOuts: nil,
  1558  				}
  1559  			},
  1560  			err: errNoStake,
  1561  		},
  1562  		{
  1563  			name: "invalid BaseTx",
  1564  			txFunc: func(*gomock.Controller) *AddPermissionlessDelegatorTx {
  1565  				return &AddPermissionlessDelegatorTx{
  1566  					BaseTx: invalidBaseTx,
  1567  					Validator: Validator{
  1568  						NodeID: ids.GenerateTestNodeID(),
  1569  					},
  1570  					StakeOuts: []*avax.TransferableOutput{
  1571  						{
  1572  							Asset: avax.Asset{
  1573  								ID: ids.GenerateTestID(),
  1574  							},
  1575  							Out: &secp256k1fx.TransferOutput{
  1576  								Amt: 1,
  1577  							},
  1578  						},
  1579  					},
  1580  				}
  1581  			},
  1582  			err: avax.ErrWrongNetworkID,
  1583  		},
  1584  		{
  1585  			name: "invalid rewards owner",
  1586  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1587  				rewardsOwner := fxmock.NewOwner(ctrl)
  1588  				rewardsOwner.EXPECT().Verify().Return(errCustom)
  1589  				return &AddPermissionlessDelegatorTx{
  1590  					BaseTx: validBaseTx,
  1591  					Validator: Validator{
  1592  						Wght: 1,
  1593  					},
  1594  					Subnet: ids.GenerateTestID(),
  1595  					StakeOuts: []*avax.TransferableOutput{
  1596  						{
  1597  							Asset: avax.Asset{
  1598  								ID: ids.GenerateTestID(),
  1599  							},
  1600  							Out: &secp256k1fx.TransferOutput{
  1601  								Amt: 1,
  1602  							},
  1603  						},
  1604  					},
  1605  					DelegationRewardsOwner: rewardsOwner,
  1606  				}
  1607  			},
  1608  			err: errCustom,
  1609  		},
  1610  		{
  1611  			name: "invalid stake output",
  1612  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1613  				rewardsOwner := fxmock.NewOwner(ctrl)
  1614  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1615  
  1616  				stakeOut := avaxmock.NewTransferableOut(ctrl)
  1617  				stakeOut.EXPECT().Verify().Return(errCustom)
  1618  				return &AddPermissionlessDelegatorTx{
  1619  					BaseTx: validBaseTx,
  1620  					Validator: Validator{
  1621  						Wght: 1,
  1622  					},
  1623  					Subnet: ids.GenerateTestID(),
  1624  					StakeOuts: []*avax.TransferableOutput{
  1625  						{
  1626  							Asset: avax.Asset{
  1627  								ID: ids.GenerateTestID(),
  1628  							},
  1629  							Out: stakeOut,
  1630  						},
  1631  					},
  1632  					DelegationRewardsOwner: rewardsOwner,
  1633  				}
  1634  			},
  1635  			err: errCustom,
  1636  		},
  1637  		{
  1638  			name: "multiple staked assets",
  1639  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1640  				rewardsOwner := fxmock.NewOwner(ctrl)
  1641  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1642  				return &AddPermissionlessDelegatorTx{
  1643  					BaseTx: validBaseTx,
  1644  					Validator: Validator{
  1645  						Wght: 1,
  1646  					},
  1647  					Subnet: ids.GenerateTestID(),
  1648  					StakeOuts: []*avax.TransferableOutput{
  1649  						{
  1650  							Asset: avax.Asset{
  1651  								ID: ids.GenerateTestID(),
  1652  							},
  1653  							Out: &secp256k1fx.TransferOutput{
  1654  								Amt: 1,
  1655  							},
  1656  						},
  1657  						{
  1658  							Asset: avax.Asset{
  1659  								ID: ids.GenerateTestID(),
  1660  							},
  1661  							Out: &secp256k1fx.TransferOutput{
  1662  								Amt: 1,
  1663  							},
  1664  						},
  1665  					},
  1666  					DelegationRewardsOwner: rewardsOwner,
  1667  				}
  1668  			},
  1669  			err: errMultipleStakedAssets,
  1670  		},
  1671  		{
  1672  			name: "stake not sorted",
  1673  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1674  				rewardsOwner := fxmock.NewOwner(ctrl)
  1675  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1676  				assetID := ids.GenerateTestID()
  1677  				return &AddPermissionlessDelegatorTx{
  1678  					BaseTx: validBaseTx,
  1679  					Validator: Validator{
  1680  						Wght: 1,
  1681  					},
  1682  					Subnet: ids.GenerateTestID(),
  1683  					StakeOuts: []*avax.TransferableOutput{
  1684  						{
  1685  							Asset: avax.Asset{
  1686  								ID: assetID,
  1687  							},
  1688  							Out: &secp256k1fx.TransferOutput{
  1689  								Amt: 2,
  1690  							},
  1691  						},
  1692  						{
  1693  							Asset: avax.Asset{
  1694  								ID: assetID,
  1695  							},
  1696  							Out: &secp256k1fx.TransferOutput{
  1697  								Amt: 1,
  1698  							},
  1699  						},
  1700  					},
  1701  					DelegationRewardsOwner: rewardsOwner,
  1702  				}
  1703  			},
  1704  			err: errOutputsNotSorted,
  1705  		},
  1706  		{
  1707  			name: "stake overflow",
  1708  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1709  				rewardsOwner := fxmock.NewOwner(ctrl)
  1710  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1711  				assetID := ids.GenerateTestID()
  1712  				return &AddPermissionlessDelegatorTx{
  1713  					BaseTx: validBaseTx,
  1714  					Validator: Validator{
  1715  						NodeID: ids.GenerateTestNodeID(),
  1716  						Wght:   1,
  1717  					},
  1718  					Subnet: ids.GenerateTestID(),
  1719  					StakeOuts: []*avax.TransferableOutput{
  1720  						{
  1721  							Asset: avax.Asset{
  1722  								ID: assetID,
  1723  							},
  1724  							Out: &secp256k1fx.TransferOutput{
  1725  								Amt: math.MaxUint64,
  1726  							},
  1727  						},
  1728  						{
  1729  							Asset: avax.Asset{
  1730  								ID: assetID,
  1731  							},
  1732  							Out: &secp256k1fx.TransferOutput{
  1733  								Amt: 2,
  1734  							},
  1735  						},
  1736  					},
  1737  					DelegationRewardsOwner: rewardsOwner,
  1738  				}
  1739  			},
  1740  			err: safemath.ErrOverflow,
  1741  		},
  1742  		{
  1743  			name: "weight mismatch",
  1744  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1745  				rewardsOwner := fxmock.NewOwner(ctrl)
  1746  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1747  				assetID := ids.GenerateTestID()
  1748  				return &AddPermissionlessDelegatorTx{
  1749  					BaseTx: validBaseTx,
  1750  					Validator: Validator{
  1751  						Wght: 1,
  1752  					},
  1753  					Subnet: ids.GenerateTestID(),
  1754  					StakeOuts: []*avax.TransferableOutput{
  1755  						{
  1756  							Asset: avax.Asset{
  1757  								ID: assetID,
  1758  							},
  1759  							Out: &secp256k1fx.TransferOutput{
  1760  								Amt: 1,
  1761  							},
  1762  						},
  1763  						{
  1764  							Asset: avax.Asset{
  1765  								ID: assetID,
  1766  							},
  1767  							Out: &secp256k1fx.TransferOutput{
  1768  								Amt: 1,
  1769  							},
  1770  						},
  1771  					},
  1772  					DelegationRewardsOwner: rewardsOwner,
  1773  				}
  1774  			},
  1775  			err: errDelegatorWeightMismatch,
  1776  		},
  1777  		{
  1778  			name: "valid subnet validator",
  1779  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1780  				rewardsOwner := fxmock.NewOwner(ctrl)
  1781  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1782  				assetID := ids.GenerateTestID()
  1783  				return &AddPermissionlessDelegatorTx{
  1784  					BaseTx: validBaseTx,
  1785  					Validator: Validator{
  1786  						Wght: 2,
  1787  					},
  1788  					Subnet: ids.GenerateTestID(),
  1789  					StakeOuts: []*avax.TransferableOutput{
  1790  						{
  1791  							Asset: avax.Asset{
  1792  								ID: assetID,
  1793  							},
  1794  							Out: &secp256k1fx.TransferOutput{
  1795  								Amt: 1,
  1796  							},
  1797  						},
  1798  						{
  1799  							Asset: avax.Asset{
  1800  								ID: assetID,
  1801  							},
  1802  							Out: &secp256k1fx.TransferOutput{
  1803  								Amt: 1,
  1804  							},
  1805  						},
  1806  					},
  1807  					DelegationRewardsOwner: rewardsOwner,
  1808  				}
  1809  			},
  1810  			err: nil,
  1811  		},
  1812  		{
  1813  			name: "valid primary network validator",
  1814  			txFunc: func(ctrl *gomock.Controller) *AddPermissionlessDelegatorTx {
  1815  				rewardsOwner := fxmock.NewOwner(ctrl)
  1816  				rewardsOwner.EXPECT().Verify().Return(nil).AnyTimes()
  1817  				assetID := ids.GenerateTestID()
  1818  				return &AddPermissionlessDelegatorTx{
  1819  					BaseTx: validBaseTx,
  1820  					Validator: Validator{
  1821  						Wght: 2,
  1822  					},
  1823  					Subnet: constants.PrimaryNetworkID,
  1824  					StakeOuts: []*avax.TransferableOutput{
  1825  						{
  1826  							Asset: avax.Asset{
  1827  								ID: assetID,
  1828  							},
  1829  							Out: &secp256k1fx.TransferOutput{
  1830  								Amt: 1,
  1831  							},
  1832  						},
  1833  						{
  1834  							Asset: avax.Asset{
  1835  								ID: assetID,
  1836  							},
  1837  							Out: &secp256k1fx.TransferOutput{
  1838  								Amt: 1,
  1839  							},
  1840  						},
  1841  					},
  1842  					DelegationRewardsOwner: rewardsOwner,
  1843  				}
  1844  			},
  1845  			err: nil,
  1846  		},
  1847  	}
  1848  
  1849  	for _, tt := range tests {
  1850  		t.Run(tt.name, func(t *testing.T) {
  1851  			ctrl := gomock.NewController(t)
  1852  
  1853  			tx := tt.txFunc(ctrl)
  1854  			err := tx.SyntacticVerify(ctx)
  1855  			require.ErrorIs(t, err, tt.err)
  1856  		})
  1857  	}
  1858  }
  1859  
  1860  func TestAddPermissionlessDelegatorTxNotValidatorTx(t *testing.T) {
  1861  	txIntf := any((*AddPermissionlessDelegatorTx)(nil))
  1862  	_, ok := txIntf.(ValidatorTx)
  1863  	require.False(t, ok)
  1864  }