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 }