github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/txs/add_subnet_validator_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 "testing" 8 "time" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/ava-labs/avalanchego/ids" 13 "github.com/ava-labs/avalanchego/snow/snowtest" 14 "github.com/ava-labs/avalanchego/utils/constants" 15 "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" 16 "github.com/ava-labs/avalanchego/utils/timer/mockable" 17 "github.com/ava-labs/avalanchego/vms/components/avax" 18 "github.com/ava-labs/avalanchego/vms/secp256k1fx" 19 ) 20 21 // TODO use table tests here 22 func TestAddSubnetValidatorTxSyntacticVerify(t *testing.T) { 23 require := require.New(t) 24 clk := mockable.Clock{} 25 ctx := snowtest.Context(t, snowtest.PChainID) 26 signers := [][]*secp256k1.PrivateKey{preFundedKeys} 27 28 var ( 29 stx *Tx 30 addSubnetValidatorTx *AddSubnetValidatorTx 31 err error 32 ) 33 34 // Case : signed tx is nil 35 err = stx.SyntacticVerify(ctx) 36 require.ErrorIs(err, ErrNilSignedTx) 37 38 // Case : unsigned tx is nil 39 err = addSubnetValidatorTx.SyntacticVerify(ctx) 40 require.ErrorIs(err, ErrNilTx) 41 42 validatorWeight := uint64(2022) 43 subnetID := ids.ID{'s', 'u', 'b', 'n', 'e', 't', 'I', 'D'} 44 inputs := []*avax.TransferableInput{{ 45 UTXOID: avax.UTXOID{ 46 TxID: ids.ID{'t', 'x', 'I', 'D'}, 47 OutputIndex: 2, 48 }, 49 Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}}, 50 In: &secp256k1fx.TransferInput{ 51 Amt: uint64(5678), 52 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 53 }, 54 }} 55 outputs := []*avax.TransferableOutput{{ 56 Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}}, 57 Out: &secp256k1fx.TransferOutput{ 58 Amt: uint64(1234), 59 OutputOwners: secp256k1fx.OutputOwners{ 60 Threshold: 1, 61 Addrs: []ids.ShortID{preFundedKeys[0].Address()}, 62 }, 63 }, 64 }} 65 subnetAuth := &secp256k1fx.Input{ 66 SigIndices: []uint32{0, 1}, 67 } 68 addSubnetValidatorTx = &AddSubnetValidatorTx{ 69 BaseTx: BaseTx{BaseTx: avax.BaseTx{ 70 NetworkID: ctx.NetworkID, 71 BlockchainID: ctx.ChainID, 72 Ins: inputs, 73 Outs: outputs, 74 Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 75 }}, 76 SubnetValidator: SubnetValidator{ 77 Validator: Validator{ 78 NodeID: ctx.NodeID, 79 Start: uint64(clk.Time().Unix()), 80 End: uint64(clk.Time().Add(time.Hour).Unix()), 81 Wght: validatorWeight, 82 }, 83 Subnet: subnetID, 84 }, 85 SubnetAuth: subnetAuth, 86 } 87 88 // Case: valid tx 89 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 90 require.NoError(err) 91 require.NoError(stx.SyntacticVerify(ctx)) 92 93 // Case: Wrong network ID 94 addSubnetValidatorTx.SyntacticallyVerified = false 95 addSubnetValidatorTx.NetworkID++ 96 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 97 require.NoError(err) 98 err = stx.SyntacticVerify(ctx) 99 require.ErrorIs(err, avax.ErrWrongNetworkID) 100 addSubnetValidatorTx.NetworkID-- 101 102 // Case: Specifies primary network SubnetID 103 addSubnetValidatorTx.SyntacticallyVerified = false 104 addSubnetValidatorTx.Subnet = ids.Empty 105 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 106 require.NoError(err) 107 err = stx.SyntacticVerify(ctx) 108 require.ErrorIs(err, errAddPrimaryNetworkValidator) 109 addSubnetValidatorTx.Subnet = subnetID 110 111 // Case: No weight 112 addSubnetValidatorTx.SyntacticallyVerified = false 113 addSubnetValidatorTx.Wght = 0 114 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 115 require.NoError(err) 116 err = stx.SyntacticVerify(ctx) 117 require.ErrorIs(err, ErrWeightTooSmall) 118 addSubnetValidatorTx.Wght = validatorWeight 119 120 // Case: Subnet auth indices not unique 121 addSubnetValidatorTx.SyntacticallyVerified = false 122 input := addSubnetValidatorTx.SubnetAuth.(*secp256k1fx.Input) 123 oldInput := *input 124 input.SigIndices[0] = input.SigIndices[1] 125 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 126 require.NoError(err) 127 err = stx.SyntacticVerify(ctx) 128 require.ErrorIs(err, secp256k1fx.ErrInputIndicesNotSortedUnique) 129 *input = oldInput 130 131 // Case: adding to Primary Network 132 addSubnetValidatorTx.SyntacticallyVerified = false 133 addSubnetValidatorTx.Subnet = constants.PrimaryNetworkID 134 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 135 require.NoError(err) 136 err = stx.SyntacticVerify(ctx) 137 require.ErrorIs(err, errAddPrimaryNetworkValidator) 138 } 139 140 func TestAddSubnetValidatorMarshal(t *testing.T) { 141 require := require.New(t) 142 clk := mockable.Clock{} 143 ctx := snowtest.Context(t, snowtest.PChainID) 144 signers := [][]*secp256k1.PrivateKey{preFundedKeys} 145 146 var ( 147 stx *Tx 148 addSubnetValidatorTx *AddSubnetValidatorTx 149 err error 150 ) 151 152 // create a valid tx 153 validatorWeight := uint64(2022) 154 subnetID := ids.ID{'s', 'u', 'b', 'n', 'e', 't', 'I', 'D'} 155 inputs := []*avax.TransferableInput{{ 156 UTXOID: avax.UTXOID{ 157 TxID: ids.ID{'t', 'x', 'I', 'D'}, 158 OutputIndex: 2, 159 }, 160 Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}}, 161 In: &secp256k1fx.TransferInput{ 162 Amt: uint64(5678), 163 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 164 }, 165 }} 166 outputs := []*avax.TransferableOutput{{ 167 Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}}, 168 Out: &secp256k1fx.TransferOutput{ 169 Amt: uint64(1234), 170 OutputOwners: secp256k1fx.OutputOwners{ 171 Threshold: 1, 172 Addrs: []ids.ShortID{preFundedKeys[0].Address()}, 173 }, 174 }, 175 }} 176 subnetAuth := &secp256k1fx.Input{ 177 SigIndices: []uint32{0, 1}, 178 } 179 addSubnetValidatorTx = &AddSubnetValidatorTx{ 180 BaseTx: BaseTx{BaseTx: avax.BaseTx{ 181 NetworkID: ctx.NetworkID, 182 BlockchainID: ctx.ChainID, 183 Ins: inputs, 184 Outs: outputs, 185 Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 186 }}, 187 SubnetValidator: SubnetValidator{ 188 Validator: Validator{ 189 NodeID: ctx.NodeID, 190 Start: uint64(clk.Time().Unix()), 191 End: uint64(clk.Time().Add(time.Hour).Unix()), 192 Wght: validatorWeight, 193 }, 194 Subnet: subnetID, 195 }, 196 SubnetAuth: subnetAuth, 197 } 198 199 // Case: valid tx 200 stx, err = NewSigned(addSubnetValidatorTx, Codec, signers) 201 require.NoError(err) 202 require.NoError(stx.SyntacticVerify(ctx)) 203 204 txBytes, err := Codec.Marshal(CodecVersion, stx) 205 require.NoError(err) 206 207 parsedTx, err := Parse(Codec, txBytes) 208 require.NoError(err) 209 210 require.NoError(parsedTx.SyntacticVerify(ctx)) 211 require.Equal(stx, parsedTx) 212 } 213 214 func TestAddSubnetValidatorTxNotValidatorTx(t *testing.T) { 215 txIntf := any((*AddSubnetValidatorTx)(nil)) 216 _, ok := txIntf.(ValidatorTx) 217 require.False(t, ok) 218 } 219 220 func TestAddSubnetValidatorTxNotDelegatorTx(t *testing.T) { 221 txIntf := any((*AddSubnetValidatorTx)(nil)) 222 _, ok := txIntf.(DelegatorTx) 223 require.False(t, ok) 224 } 225 226 func TestAddSubnetValidatorTxNotPermissionlessStaker(t *testing.T) { 227 txIntf := any((*AddSubnetValidatorTx)(nil)) 228 _, ok := txIntf.(PermissionlessStaker) 229 require.False(t, ok) 230 }