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 }