github.com/MetalBlockchain/metalgo@v1.11.9/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/MetalBlockchain/metalgo/ids"
    13  	"github.com/MetalBlockchain/metalgo/snow/snowtest"
    14  	"github.com/MetalBlockchain/metalgo/utils/constants"
    15  	"github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1"
    16  	"github.com/MetalBlockchain/metalgo/utils/timer/mockable"
    17  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    18  	"github.com/MetalBlockchain/metalgo/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].PublicKey().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].PublicKey().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  }