github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/txs/add_delegator_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/crypto/secp256k1"
    15  	"github.com/MetalBlockchain/metalgo/utils/timer/mockable"
    16  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    17  	"github.com/MetalBlockchain/metalgo/vms/platformvm/stakeable"
    18  	"github.com/MetalBlockchain/metalgo/vms/secp256k1fx"
    19  )
    20  
    21  var preFundedKeys = secp256k1.TestKeys()
    22  
    23  func TestAddDelegatorTxSyntacticVerify(t *testing.T) {
    24  	require := require.New(t)
    25  	clk := mockable.Clock{}
    26  	ctx := snowtest.Context(t, snowtest.PChainID)
    27  	signers := [][]*secp256k1.PrivateKey{preFundedKeys}
    28  
    29  	var (
    30  		stx            *Tx
    31  		addDelegatorTx *AddDelegatorTx
    32  		err            error
    33  	)
    34  
    35  	// Case : signed tx is nil
    36  	err = stx.SyntacticVerify(ctx)
    37  	require.ErrorIs(err, ErrNilSignedTx)
    38  
    39  	// Case : unsigned tx is nil
    40  	err = addDelegatorTx.SyntacticVerify(ctx)
    41  	require.ErrorIs(err, ErrNilTx)
    42  
    43  	validatorWeight := uint64(2022)
    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: ctx.AVAXAssetID},
    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: ctx.AVAXAssetID},
    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  	stakes := []*avax.TransferableOutput{{
    66  		Asset: avax.Asset{ID: ctx.AVAXAssetID},
    67  		Out: &stakeable.LockOut{
    68  			Locktime: uint64(clk.Time().Add(time.Second).Unix()),
    69  			TransferableOut: &secp256k1fx.TransferOutput{
    70  				Amt: validatorWeight,
    71  				OutputOwners: secp256k1fx.OutputOwners{
    72  					Threshold: 1,
    73  					Addrs:     []ids.ShortID{preFundedKeys[0].PublicKey().Address()},
    74  				},
    75  			},
    76  		},
    77  	}}
    78  	addDelegatorTx = &AddDelegatorTx{
    79  		BaseTx: BaseTx{BaseTx: avax.BaseTx{
    80  			NetworkID:    ctx.NetworkID,
    81  			BlockchainID: ctx.ChainID,
    82  			Outs:         outputs,
    83  			Ins:          inputs,
    84  			Memo:         []byte{1, 2, 3, 4, 5, 6, 7, 8},
    85  		}},
    86  		Validator: Validator{
    87  			NodeID: ctx.NodeID,
    88  			Start:  uint64(clk.Time().Unix()),
    89  			End:    uint64(clk.Time().Add(time.Hour).Unix()),
    90  			Wght:   validatorWeight,
    91  		},
    92  		StakeOuts: stakes,
    93  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
    94  			Locktime:  0,
    95  			Threshold: 1,
    96  			Addrs:     []ids.ShortID{preFundedKeys[0].PublicKey().Address()},
    97  		},
    98  	}
    99  
   100  	// Case: signed tx not initialized
   101  	stx = &Tx{Unsigned: addDelegatorTx}
   102  	err = stx.SyntacticVerify(ctx)
   103  	require.ErrorIs(err, errSignedTxNotInitialized)
   104  
   105  	// Case: valid tx
   106  	stx, err = NewSigned(addDelegatorTx, Codec, signers)
   107  	require.NoError(err)
   108  	require.NoError(stx.SyntacticVerify(ctx))
   109  
   110  	// Case: Wrong network ID
   111  	addDelegatorTx.SyntacticallyVerified = false
   112  	addDelegatorTx.NetworkID++
   113  	stx, err = NewSigned(addDelegatorTx, Codec, signers)
   114  	require.NoError(err)
   115  	err = stx.SyntacticVerify(ctx)
   116  	require.ErrorIs(err, avax.ErrWrongNetworkID)
   117  	addDelegatorTx.NetworkID--
   118  
   119  	// Case: delegator weight is not equal to total stake weight
   120  	addDelegatorTx.SyntacticallyVerified = false
   121  	addDelegatorTx.Wght = 2 * validatorWeight
   122  	stx, err = NewSigned(addDelegatorTx, Codec, signers)
   123  	require.NoError(err)
   124  	err = stx.SyntacticVerify(ctx)
   125  	require.ErrorIs(err, errDelegatorWeightMismatch)
   126  	addDelegatorTx.Wght = validatorWeight
   127  }
   128  
   129  func TestAddDelegatorTxSyntacticVerifyNotAVAX(t *testing.T) {
   130  	require := require.New(t)
   131  	clk := mockable.Clock{}
   132  	ctx := snowtest.Context(t, snowtest.PChainID)
   133  	signers := [][]*secp256k1.PrivateKey{preFundedKeys}
   134  
   135  	var (
   136  		stx            *Tx
   137  		addDelegatorTx *AddDelegatorTx
   138  		err            error
   139  	)
   140  
   141  	assetID := ids.GenerateTestID()
   142  	validatorWeight := uint64(2022)
   143  	inputs := []*avax.TransferableInput{{
   144  		UTXOID: avax.UTXOID{
   145  			TxID:        ids.ID{'t', 'x', 'I', 'D'},
   146  			OutputIndex: 2,
   147  		},
   148  		Asset: avax.Asset{ID: assetID},
   149  		In: &secp256k1fx.TransferInput{
   150  			Amt:   uint64(5678),
   151  			Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   152  		},
   153  	}}
   154  	outputs := []*avax.TransferableOutput{{
   155  		Asset: avax.Asset{ID: assetID},
   156  		Out: &secp256k1fx.TransferOutput{
   157  			Amt: uint64(1234),
   158  			OutputOwners: secp256k1fx.OutputOwners{
   159  				Threshold: 1,
   160  				Addrs:     []ids.ShortID{preFundedKeys[0].PublicKey().Address()},
   161  			},
   162  		},
   163  	}}
   164  	stakes := []*avax.TransferableOutput{{
   165  		Asset: avax.Asset{ID: assetID},
   166  		Out: &stakeable.LockOut{
   167  			Locktime: uint64(clk.Time().Add(time.Second).Unix()),
   168  			TransferableOut: &secp256k1fx.TransferOutput{
   169  				Amt: validatorWeight,
   170  				OutputOwners: secp256k1fx.OutputOwners{
   171  					Threshold: 1,
   172  					Addrs:     []ids.ShortID{preFundedKeys[0].PublicKey().Address()},
   173  				},
   174  			},
   175  		},
   176  	}}
   177  	addDelegatorTx = &AddDelegatorTx{
   178  		BaseTx: BaseTx{BaseTx: avax.BaseTx{
   179  			NetworkID:    ctx.NetworkID,
   180  			BlockchainID: ctx.ChainID,
   181  			Outs:         outputs,
   182  			Ins:          inputs,
   183  			Memo:         []byte{1, 2, 3, 4, 5, 6, 7, 8},
   184  		}},
   185  		Validator: Validator{
   186  			NodeID: ctx.NodeID,
   187  			Start:  uint64(clk.Time().Unix()),
   188  			End:    uint64(clk.Time().Add(time.Hour).Unix()),
   189  			Wght:   validatorWeight,
   190  		},
   191  		StakeOuts: stakes,
   192  		DelegationRewardsOwner: &secp256k1fx.OutputOwners{
   193  			Locktime:  0,
   194  			Threshold: 1,
   195  			Addrs:     []ids.ShortID{preFundedKeys[0].PublicKey().Address()},
   196  		},
   197  	}
   198  
   199  	stx, err = NewSigned(addDelegatorTx, Codec, signers)
   200  	require.NoError(err)
   201  
   202  	err = stx.SyntacticVerify(ctx)
   203  	require.ErrorIs(err, errStakeMustBeAVAX)
   204  }
   205  
   206  func TestAddDelegatorTxNotValidatorTx(t *testing.T) {
   207  	txIntf := any((*AddDelegatorTx)(nil))
   208  	_, ok := txIntf.(ValidatorTx)
   209  	require.False(t, ok)
   210  }