code.vegaprotocol.io/vega@v0.79.0/core/spam/simple_spam_policy_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package spam_test
    17  
    18  import (
    19  	"strconv"
    20  	"testing"
    21  
    22  	"code.vegaprotocol.io/vega/core/netparams"
    23  	"code.vegaprotocol.io/vega/core/spam"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  	"code.vegaprotocol.io/vega/logging"
    27  
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  var insufficientPropTokens, _ = num.UintFromString("50000000000000000000000", 10)
    32  
    33  var sufficientPropTokens, _ = num.UintFromString("100000000000000000000000", 10)
    34  
    35  func getCommandSpamPolicy(accounts map[string]*num.Uint) *spam.SimpleSpamPolicy {
    36  	testAccounts := testAccounts{balances: accounts}
    37  	logger := logging.NewTestLogger()
    38  	policy := spam.NewSimpleSpamPolicy("simple", netparams.SpamProtectionMinTokensForProposal, netparams.SpamProtectionMaxProposals, logger, testAccounts)
    39  	minTokensForProposal, _ := num.UintFromString("100000000000000000000000", 10)
    40  	policy.UpdateUintParam(netparams.SpamProtectionMinTokensForProposal, minTokensForProposal)
    41  	policy.UpdateIntParam(netparams.SpamProtectionMaxProposals, 3)
    42  	return policy
    43  }
    44  
    45  func TestInsufficientPropTokens(t *testing.T) {
    46  	policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": insufficientPropTokens})
    47  	// epoch 0 block 0
    48  	policy.Reset(types.Epoch{Seq: 0})
    49  	tx := &testTx{party: "party1", proposal: "proposal1"}
    50  	err := policy.PreBlockAccept(tx)
    51  	require.Equal(t, "party has insufficient associated governance tokens in their staking account to submit simple request", err.Error())
    52  }
    53  
    54  func TestCommandPreAccept(t *testing.T) {
    55  	policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens})
    56  	// epoch 0 block 0
    57  	policy.Reset(types.Epoch{Seq: 0})
    58  
    59  	// propose 5 times all pre accepted, 3 for each post accepted
    60  	for i := 0; i < 2; i++ {
    61  		tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)}
    62  		// pre accepted
    63  		for i := 0; i < 5; i++ {
    64  			err := policy.PreBlockAccept(tx)
    65  			require.NoError(t, err)
    66  		}
    67  	}
    68  }
    69  
    70  func TestEndPrepareBlock(t *testing.T) {
    71  	policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens})
    72  	policy.Reset(types.Epoch{Seq: 0})
    73  
    74  	tx1 := &testTx{party: "party1", proposal: "proposal1"}
    75  	tx2 := &testTx{party: "party1", proposal: "proposal2"}
    76  	tx3 := &testTx{party: "party1", proposal: "proposal3"}
    77  
    78  	// prepare a block
    79  	require.NoError(t, policy.CheckBlockTx(tx1))
    80  	require.NoError(t, policy.CheckBlockTx(tx2))
    81  	require.NoError(t, policy.CheckBlockTx(tx3))
    82  
    83  	// end the proposal preparation to rollback any block changes
    84  	policy.RollbackProposal()
    85  
    86  	s := policy.GetSpamStats(tx1.party)
    87  	require.Equal(t, uint64(0), s.CountForEpoch)
    88  
    89  	// assume block was proposed, now check from process proposal
    90  	policy.UpdateTx(tx1)
    91  	policy.UpdateTx(tx2)
    92  	policy.UpdateTx(tx3)
    93  
    94  	s = policy.GetSpamStats(tx1.party)
    95  	require.Equal(t, uint64(3), s.CountForEpoch)
    96  }
    97  
    98  func TestCheckBlockTx(t *testing.T) {
    99  	policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens})
   100  	policy.Reset(types.Epoch{Seq: 0})
   101  
   102  	tx1 := &testTx{party: "party1", proposal: "proposal1"}
   103  	tx2 := &testTx{party: "party1", proposal: "proposal2"}
   104  	tx3 := &testTx{party: "party1", proposal: "proposal3"}
   105  	tx4 := &testTx{party: "party1", proposal: "proposal4"}
   106  
   107  	require.NoError(t, policy.CheckBlockTx(tx1))
   108  	require.NoError(t, policy.CheckBlockTx(tx2))
   109  	require.NoError(t, policy.CheckBlockTx(tx3))
   110  	require.Error(t, policy.CheckBlockTx(tx4))
   111  
   112  	// rollback the proposal
   113  	policy.RollbackProposal()
   114  
   115  	// as the state has nothing expect pre block accept of all 4 txs
   116  	require.NoError(t, policy.PreBlockAccept(tx1))
   117  	require.NoError(t, policy.PreBlockAccept(tx2))
   118  	require.NoError(t, policy.PreBlockAccept(tx3))
   119  	require.NoError(t, policy.PreBlockAccept(tx4))
   120  
   121  	// now a block is made with the first 3 txs
   122  	policy.UpdateTx(tx1)
   123  	policy.UpdateTx(tx2)
   124  	policy.UpdateTx(tx3)
   125  
   126  	stats := policy.GetSpamStats(tx1.party)
   127  	require.Equal(t, uint64(3), stats.CountForEpoch)
   128  
   129  	// now that there's been 3 proposals already, the 4th should be pre-rejected
   130  	require.Error(t, policy.PreBlockAccept(tx4))
   131  
   132  	// start a new epoch to reset counters
   133  	policy.Reset(types.Epoch{Seq: 0})
   134  
   135  	// check that the new proposal is pre-block accepted
   136  	require.NoError(t, policy.PreBlockAccept(tx4))
   137  
   138  	stats = policy.GetSpamStats(tx1.party)
   139  	require.Equal(t, uint64(0), stats.CountForEpoch)
   140  }