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