code.vegaprotocol.io/vega@v0.79.0/core/processor/gastimator_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 processor_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  
    22  	"code.vegaprotocol.io/vega/core/processor"
    23  	"code.vegaprotocol.io/vega/core/txn"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    27  
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestUpdateMaxGas(t *testing.T) {
    32  	eet := &ExecEngineTest{marketCounters: map[string]*types.MarketCounters{}}
    33  	gastimator := processor.NewGastimator(eet)
    34  	gastimator.OnMaxGasUpdate(context.Background(), num.NewUint(1234))
    35  	require.Equal(t, uint64(1234), gastimator.GetMaxGas())
    36  }
    37  
    38  func TestSubmitOrder(t *testing.T) {
    39  	tx := &testTx{
    40  		command:      txn.SubmitOrderCommand,
    41  		unmarshaller: unmarshalSubmitOrder(&commandspb.OrderSubmission{MarketId: "1"}),
    42  	}
    43  	testSubmitOrAmendOrder(t, tx)
    44  }
    45  
    46  func TestAmendOrder(t *testing.T) {
    47  	tx := &testTx{
    48  		command:      txn.AmendOrderCommand,
    49  		unmarshaller: unmarshalAmendtOrder(&commandspb.OrderAmendment{MarketId: "1"}),
    50  	}
    51  	testSubmitOrAmendOrder(t, tx)
    52  }
    53  
    54  func testSubmitOrAmendOrder(t *testing.T, tx *testTx) {
    55  	t.Helper()
    56  	marketCounters := map[string]*types.MarketCounters{}
    57  	eet := &ExecEngineTest{marketCounters: marketCounters}
    58  	gastimator := processor.NewGastimator(eet)
    59  	gastimator.OnMaxGasUpdate(context.Background(), num.NewUint(1234))
    60  	gastimator.OnDefaultGasUpdate(context.Background(), num.NewUint(1))
    61  	gastimator.OnMinBlockCapacityUpdate(context.Background(), num.NewUint(1))
    62  
    63  	// there's nothing yet for the market so expect default counters
    64  	count, err := gastimator.CalcGasWantedForTx(tx)
    65  	require.NoError(t, err)
    66  	require.Equal(t, uint64(1), count)
    67  
    68  	// change the default gas to see we get the new default
    69  	gastimator.OnDefaultGasUpdate(context.Background(), num.NewUint(10))
    70  	count, err = gastimator.CalcGasWantedForTx(tx)
    71  	require.NoError(t, err)
    72  	require.Equal(t, uint64(10), count)
    73  
    74  	// set some counters
    75  	marketCounters["1"] = &types.MarketCounters{
    76  		PeggedOrderCounter:  1,
    77  		PositionCount:       2,
    78  		OrderbookLevelCount: 10,
    79  	}
    80  	gastimator.OnBlockEnd()
    81  
    82  	// gasOrder = network.transaction.defaultgas + peg cost factor x pegs
    83  	//                                         + position factor x positions
    84  	//                                         + level factor x levels
    85  	// gasOrder = min(maxGas-1,gasOrder)
    86  	// gasOrder = min(1233, 10 + 50 * 1 + 2 + 10 * 0.1) = 563
    87  	count, err = gastimator.CalcGasWantedForTx(tx)
    88  	require.NoError(t, err)
    89  	require.Equal(t, uint64(63), count)
    90  
    91  	// update counters such that now the max gas is lower than gas wanted for the order
    92  	marketCounters["1"] = &types.MarketCounters{
    93  		PeggedOrderCounter:  8,
    94  		PositionCount:       2,
    95  		OrderbookLevelCount: 100,
    96  	}
    97  
    98  	// gasOrder = min(1233, 10 + 50 * 8 + 2 + 100 * 0.1) = 422
    99  	count, err = gastimator.CalcGasWantedForTx(tx)
   100  	require.NoError(t, err)
   101  	require.Equal(t, uint64(422), count)
   102  }
   103  
   104  func TestCancelOrder(t *testing.T) {
   105  	tx := &testTx{
   106  		command:      txn.CancelOrderCommand,
   107  		unmarshaller: unmarshalCancelOrder(&commandspb.OrderCancellation{MarketId: "1", OrderId: "1"}),
   108  	}
   109  
   110  	marketCounters := map[string]*types.MarketCounters{}
   111  	eet := &ExecEngineTest{marketCounters: marketCounters}
   112  	gastimator := processor.NewGastimator(eet)
   113  	gastimator.OnMaxGasUpdate(context.Background(), num.NewUint(1234))
   114  	gastimator.OnDefaultGasUpdate(context.Background(), num.NewUint(1))
   115  	gastimator.OnMinBlockCapacityUpdate(context.Background(), num.NewUint(1))
   116  
   117  	// there's nothing yet for the market so expect default counters
   118  	count, err := gastimator.CalcGasWantedForTx(tx)
   119  	require.NoError(t, err)
   120  	require.Equal(t, uint64(1), count)
   121  
   122  	// change the default gas to see we get the new default
   123  	gastimator.OnDefaultGasUpdate(context.Background(), num.NewUint(10))
   124  	count, err = gastimator.CalcGasWantedForTx(tx)
   125  	require.NoError(t, err)
   126  	require.Equal(t, uint64(10), count)
   127  
   128  	// set some counters
   129  	marketCounters["1"] = &types.MarketCounters{
   130  		PeggedOrderCounter:  1,
   131  		PositionCount:       2,
   132  		OrderbookLevelCount: 10,
   133  	}
   134  	gastimator.OnBlockEnd()
   135  
   136  	// gasCancel = network.transaction.defaultgas + peg cost factor x pegs
   137  	// 	+ level factor x levels
   138  	// gasCancel = min(maxGas-1,gasCancel)
   139  	// gasOrder = min(1233, 10 + 50 * 1 + 10 * 0.1) = 561
   140  	count, err = gastimator.CalcGasWantedForTx(tx)
   141  	require.NoError(t, err)
   142  	require.Equal(t, uint64(61), count)
   143  
   144  	// update counters such that now the max gas is lower than gasCancel
   145  	marketCounters["1"] = &types.MarketCounters{
   146  		PeggedOrderCounter:  8,
   147  		PositionCount:       2,
   148  		OrderbookLevelCount: 100,
   149  	}
   150  
   151  	// gasOrder = min(1233, 10 + 50 * 8 + 100 * 0.1) = 420
   152  	count, err = gastimator.CalcGasWantedForTx(tx)
   153  	require.NoError(t, err)
   154  	require.Equal(t, uint64(420), count)
   155  }
   156  
   157  func TestBatch(t *testing.T) {
   158  	tx := &testTx{
   159  		command: txn.BatchMarketInstructions,
   160  		unmarshaller: unmarshalBatch(&commandspb.BatchMarketInstructions{
   161  			Submissions:   []*commandspb.OrderSubmission{{MarketId: "1"}, {MarketId: "1"}, {MarketId: "1"}},
   162  			Cancellations: []*commandspb.OrderCancellation{{MarketId: "1"}, {MarketId: "1"}, {MarketId: "1"}, {MarketId: "1"}, {MarketId: "1"}},
   163  			Amendments:    []*commandspb.OrderAmendment{{MarketId: "1"}, {MarketId: "1"}, {MarketId: "1"}, {MarketId: "1"}},
   164  		},
   165  		),
   166  	}
   167  
   168  	marketCounters := map[string]*types.MarketCounters{}
   169  	eet := &ExecEngineTest{marketCounters: marketCounters}
   170  	gastimator := processor.NewGastimator(eet)
   171  	gastimator.OnMaxGasUpdate(context.Background(), num.NewUint(10000))
   172  	gastimator.OnDefaultGasUpdate(context.Background(), num.NewUint(1))
   173  	gastimator.OnMinBlockCapacityUpdate(context.Background(), num.NewUint(1))
   174  
   175  	// there's nothing yet for any market so expect defaultgas * 3 + 4 * defaultgas = 7 * defaultgas
   176  	count, err := gastimator.CalcGasWantedForTx(tx)
   177  	require.NoError(t, err)
   178  	require.Equal(t, uint64(7), count)
   179  
   180  	// change the default gas to see we get the new default
   181  	// defaultGas + 0.5 * 2 * defaultGas +
   182  	// defaultGas + 2 * defaultGas +
   183  	// defaultGas + 1.5 * defaultGas = 75
   184  	gastimator.OnDefaultGasUpdate(context.Background(), num.NewUint(10))
   185  	count, err = gastimator.CalcGasWantedForTx(tx)
   186  	require.NoError(t, err)
   187  	require.Equal(t, uint64(75), count)
   188  
   189  	// set some counters
   190  	marketCounters["1"] = &types.MarketCounters{
   191  		PeggedOrderCounter:  1,
   192  		PositionCount:       2,
   193  		OrderbookLevelCount: 10,
   194  	}
   195  
   196  	gastimator.OnBlockEnd()
   197  
   198  	// we have 3 submissions, 5 cancellations and 4 amendments
   199  	count, err = gastimator.CalcGasWantedForTx(tx)
   200  	require.NoError(t, err)
   201  	require.Equal(t, uint64(466), count)
   202  
   203  	// update counters such that now the max gas is lower than gasCancel
   204  	marketCounters["1"] = &types.MarketCounters{
   205  		PeggedOrderCounter:  8,
   206  		PositionCount:       2,
   207  		OrderbookLevelCount: 100,
   208  	}
   209  
   210  	count, err = gastimator.CalcGasWantedForTx(tx)
   211  	require.NoError(t, err)
   212  	require.Equal(t, uint64(3159), count)
   213  }
   214  
   215  func TestGetPriority(t *testing.T) {
   216  	command := []txn.Command{
   217  		txn.SubmitOrderCommand,
   218  		txn.CancelOrderCommand,
   219  		txn.AmendOrderCommand,
   220  		txn.WithdrawCommand,
   221  		txn.ProposeCommand,
   222  		txn.BatchProposeCommand,
   223  		txn.VoteCommand,
   224  		txn.AnnounceNodeCommand,
   225  		txn.NodeVoteCommand,
   226  		txn.NodeSignatureCommand,
   227  		txn.LiquidityProvisionCommand,
   228  		txn.CancelLiquidityProvisionCommand,
   229  		txn.AmendLiquidityProvisionCommand,
   230  		txn.ChainEventCommand,
   231  		txn.SubmitOracleDataCommand,
   232  		txn.DelegateCommand,
   233  		txn.UndelegateCommand,
   234  		txn.RotateKeySubmissionCommand,
   235  		txn.StateVariableProposalCommand,
   236  		txn.TransferFundsCommand,
   237  		txn.CancelTransferFundsCommand,
   238  		txn.ValidatorHeartbeatCommand,
   239  		txn.RotateEthereumKeySubmissionCommand,
   240  		txn.ProtocolUpgradeCommand,
   241  		txn.IssueSignatures,
   242  		txn.BatchMarketInstructions,
   243  	}
   244  	marketCounters := map[string]*types.MarketCounters{}
   245  	eet := &ExecEngineTest{marketCounters: marketCounters}
   246  	gastimator := processor.NewGastimator(eet)
   247  	for _, c := range command {
   248  		expected := uint64(1)
   249  		if c.IsValidatorCommand() {
   250  			expected = uint64(10000)
   251  		} else if c == txn.ProposeCommand || c == txn.VoteCommand || c == txn.BatchProposeCommand {
   252  			expected = uint64(100)
   253  		}
   254  		require.Equal(t, expected, gastimator.GetPriority(&testTx{command: c}), c)
   255  	}
   256  }
   257  
   258  type ExecEngineTest struct {
   259  	marketCounters map[string]*types.MarketCounters
   260  }
   261  
   262  func (eet *ExecEngineTest) GetMarketCounters() map[string]*types.MarketCounters {
   263  	return eet.marketCounters
   264  }
   265  
   266  func unmarshalBatch(batch *commandspb.BatchMarketInstructions) func(interface{}) error {
   267  	return func(i interface{}) error {
   268  		underlyingCmd, _ := i.(*commandspb.BatchMarketInstructions)
   269  		*underlyingCmd = *batch
   270  		return nil
   271  	}
   272  }
   273  
   274  func unmarshalSubmitOrder(order *commandspb.OrderSubmission) func(interface{}) error {
   275  	return func(i interface{}) error {
   276  		underlyingCmd, _ := i.(*commandspb.OrderSubmission)
   277  		*underlyingCmd = *order
   278  		return nil
   279  	}
   280  }
   281  
   282  func unmarshalAmendtOrder(order *commandspb.OrderAmendment) func(interface{}) error {
   283  	return func(i interface{}) error {
   284  		underlyingCmd, _ := i.(*commandspb.OrderAmendment)
   285  		*underlyingCmd = *order
   286  		return nil
   287  	}
   288  }
   289  
   290  func unmarshalCancelOrder(order *commandspb.OrderCancellation) func(interface{}) error {
   291  	return func(i interface{}) error {
   292  		underlyingCmd, _ := i.(*commandspb.OrderCancellation)
   293  		*underlyingCmd = *order
   294  		return nil
   295  	}
   296  }
   297  
   298  type testTx struct {
   299  	command      txn.Command
   300  	unmarshaller func(interface{}) error
   301  }
   302  
   303  func (tx *testTx) GetLength() int                { return 0 }
   304  func (tx *testTx) Unmarshal(i interface{}) error { return tx.unmarshaller(i) }
   305  func (tx *testTx) GetPoWTID() string             { return "" }
   306  func (tx *testTx) GetVersion() uint32            { return 2 }
   307  func (tx *testTx) GetPoWNonce() uint64           { return 0 }
   308  func (tx *testTx) GetNonce() uint64              { return 0 }
   309  func (tx *testTx) Signature() []byte             { return []byte{} }
   310  func (tx *testTx) Payload() []byte               { return nil }
   311  func (tx *testTx) PubKey() []byte                { return []byte{} }
   312  func (tx *testTx) PubKeyHex() string             { return "" }
   313  func (tx *testTx) Party() string                 { return "" }
   314  func (tx *testTx) Hash() []byte                  { return []byte{} }
   315  func (tx *testTx) Command() txn.Command          { return tx.command }
   316  func (tx *testTx) BlockHeight() uint64           { return 0 }
   317  func (tx *testTx) GetCmd() interface{}           { return nil }