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